From 67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Jun 2016 23:47:35 +0200 Subject: Rename IPCSocket and removed unused code in TestHelper. --- test/RPCSession.cpp | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 test/RPCSession.cpp (limited to 'test/RPCSession.cpp') diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp new file mode 100644 index 00000000..01118cca --- /dev/null +++ b/test/RPCSession.cpp @@ -0,0 +1,262 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file RPCSession.cpp + * @author Dimtiry Khokhlov + * @date 2016 + */ + +#include +#include +#include +#include +#include +#include +#include "RPCSession.h" + +using namespace std; +using namespace dev; + +IPCSocket::IPCSocket(string const& _path): m_path(_path) +{ + if (_path.length() >= sizeof(sockaddr_un::sun_path)) + BOOST_FAIL("Error opening IPC: socket path is too long!"); + + struct sockaddr_un saun; + saun.sun_family = AF_UNIX; + strcpy(saun.sun_path, _path.c_str()); + + if ((m_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + BOOST_FAIL("Error creating IPC socket object"); + + int len = sizeof(saun.sun_family) + strlen(saun.sun_path); + + if (connect(m_socket, reinterpret_cast(&saun), len) < 0) + BOOST_FAIL("Error connecting to IPC socket: " << _path); + + m_fp = fdopen(m_socket, "r"); +} + +string IPCSocket::sendRequest(string const& _req) +{ + send(m_socket, _req.c_str(), _req.length(), 0); + + char c; + string response; + while ((c = fgetc(m_fp)) != EOF) + { + if (c != '\n') + response += c; + else + break; + } + return response; +} + +RPCSession& RPCSession::instance(const string& _path) +{ + static RPCSession session(_path); + BOOST_REQUIRE_EQUAL(session.m_ipcSocket.path(), _path); + return session; +} + +string RPCSession::eth_getCode(string const& _address, string const& _blockNumber) +{ + return rpcCall("eth_getCode", { quote(_address), quote(_blockNumber) }).asString(); +} + +RPCSession::TransactionReceipt RPCSession::eth_getTransactionReceipt(string const& _transactionHash) +{ + TransactionReceipt receipt; + Json::Value const result = rpcCall("eth_getTransactionReceipt", { quote(_transactionHash) }); + BOOST_REQUIRE(!result.isNull()); + receipt.gasUsed = result["gasUsed"].asString(); + receipt.contractAddress = result["contractAddress"].asString(); + for (auto const& log: result["logs"]) + { + LogEntry entry; + entry.address = log["address"].asString(); + entry.data = log["data"].asString(); + for (auto const& topic: log["topics"]) + entry.topics.push_back(topic.asString()); + receipt.logEntries.push_back(entry); + } + return receipt; +} + +string RPCSession::eth_sendTransaction(TransactionData const& _td) +{ + return rpcCall("eth_sendTransaction", { _td.toJson() }).asString(); +} + +string RPCSession::eth_call(TransactionData const& _td, string const& _blockNumber) +{ + return rpcCall("eth_call", { _td.toJson(), quote(_blockNumber) }).asString(); +} + +string RPCSession::eth_sendTransaction(string const& _transaction) +{ + return rpcCall("eth_sendTransaction", { _transaction }).asString(); +} + +string RPCSession::eth_getBalance(string const& _address, string const& _blockNumber) +{ + string address = (_address.length() == 20) ? "0x" + _address : _address; + return rpcCall("eth_getBalance", { quote(address), quote(_blockNumber) }).asString(); +} + +string RPCSession::eth_getStorageRoot(string const& _address, string const& _blockNumber) +{ + string address = (_address.length() == 20) ? "0x" + _address : _address; + return rpcCall("eth_getStorageRoot", { quote(address), quote(_blockNumber) }).asString(); +} + +void RPCSession::personal_unlockAccount(string const& _address, string const& _password, int _duration) +{ + rpcCall("personal_unlockAccount", { quote(_address), quote(_password), to_string(_duration) }); +} + +string RPCSession::personal_newAccount(string const& _password) +{ + return rpcCall("personal_newAccount", { quote(_password) }).asString(); +} + +void RPCSession::test_setChainParams(vector const& _accounts) +{ + static std::string const c_configString = R"( + { + "sealEngine": "NoProof", + "params": { + "accountStartNonce": "0x", + "maximumExtraDataSize": "0x1000000", + "blockReward": "0x", + "allowFutureBlocks": "1" + }, + "genesis": { + "author": "0000000000000010000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x1000000000000" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "wei": "1", "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "wei": "1", "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "wei": "1", "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } } + } + } + )"; + + Json::Value config; + BOOST_REQUIRE(Json::Reader().parse(c_configString, config)); + for (auto const& account: _accounts) + config["accounts"][account]["wei"] = "0x100000000000000000000000000000000000000000"; + test_setChainParams(Json::FastWriter().write(config)); +} + +void RPCSession::test_setChainParams(string const& _config) +{ + rpcCall("test_setChainParams", { _config }); +} + +void RPCSession::test_rewindToBlock(size_t _blockNr) +{ + rpcCall("test_rewindToBlock", { to_string(_blockNr) }); +} + +void RPCSession::test_mineBlocks(int _number) +{ + u256 startBlock = fromBigEndian(fromHex(rpcCall("eth_blockNumber").asString())); + rpcCall("test_mineBlocks", { to_string(_number) }, true); + + //@TODO do not use polling - but that would probably need a change to the test client + for (size_t polls = 0; polls < 100; ++polls) + { + if (fromBigEndian(fromHex(rpcCall("eth_blockNumber").asString())) >= startBlock + _number) + return; + std::this_thread::sleep_for(chrono::milliseconds(10)); //it does not work faster then 10 ms + } + + BOOST_FAIL("Error in test_mineBlocks: block mining timeout!"); +} + +void RPCSession::test_modifyTimestamp(size_t _timestamp) +{ + rpcCall("test_modifyTimestamp", { to_string(_timestamp) }); +} + +Json::Value RPCSession::rpcCall(string const& _methodName, vector const& _args, bool _canFail) +{ + string request = "{\"jsonrpc\":\"2.0\",\"method\":\"" + _methodName + "\",\"params\":["; + for (size_t i = 0; i < _args.size(); ++i) + { + request += _args[i]; + if (i + 1 != _args.size()) + request += ", "; + } + + request += "],\"id\":" + to_string(m_rpcSequence) + "}"; + ++m_rpcSequence; + + //cout << "Request: " << request << endl; + string reply = m_ipcSocket.sendRequest(request); + //cout << "Reply: " << reply << endl; + + Json::Value result; + Json::Reader().parse(reply, result, false); + + if (result.isMember("error")) + { + if (_canFail) + return Json::Value(); + + BOOST_FAIL("Error on JSON-RPC call: " + result["error"]["message"].asString()); + } + return result["result"]; +} + +string const& RPCSession::accountCreateIfNotExists(size_t _id) +{ + if (_id >= m_accounts.size()) + { + m_accounts.push_back(personal_newAccount("")); + personal_unlockAccount(m_accounts.back(), "", 100000); + } + return m_accounts[_id]; +} + +RPCSession::RPCSession(const string& _path): + m_ipcSocket(_path) +{ + string account = personal_newAccount(""); + personal_unlockAccount(account, "", 100000); + m_accounts.push_back(account); + test_setChainParams(m_accounts); +} + +string RPCSession::TransactionData::toJson() const +{ + Json::Value json; + json["from"] = (from.length() == 20) ? "0x" + from : from; + json["to"] = (to.length() == 20 || to == "") ? "0x" + to : to; + json["gas"] = gas; + json["gasprice"] = gasPrice; + json["value"] = value; + json["data"] = data; + return Json::FastWriter().write(json); + +} -- cgit