aboutsummaryrefslogtreecommitdiffstats
path: root/test/RPCSession.cpp
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-06-29 05:47:35 +0800
committerchriseth <c@ethdev.com>2016-06-29 06:14:50 +0800
commit67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8 (patch)
tree2ca0c0c7e40948ca0a687a6784a1245ca07e8b3b /test/RPCSession.cpp
parent05e5bdf780cba4d198066d6f26353fd25d8ff553 (diff)
downloaddexon-solidity-67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8.tar
dexon-solidity-67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8.tar.gz
dexon-solidity-67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8.tar.bz2
dexon-solidity-67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8.tar.lz
dexon-solidity-67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8.tar.xz
dexon-solidity-67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8.tar.zst
dexon-solidity-67d1e4783a760bf3c8f6f97e0fc53f0e1c24d2d8.zip
Rename IPCSocket and removed unused code in TestHelper.
Diffstat (limited to 'test/RPCSession.cpp')
-rw-r--r--test/RPCSession.cpp262
1 files changed, 262 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+*/
+/** @file RPCSession.cpp
+ * @author Dimtiry Khokhlov <dimitry@ethdev.com>
+ * @date 2016
+ */
+
+#include <string>
+#include <stdio.h>
+#include <thread>
+#include <libdevcore/CommonData.h>
+#include <jsoncpp/json/reader.h>
+#include <jsoncpp/json/writer.h>
+#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<struct sockaddr const*>(&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<string> 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<u256>(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<u256>(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<string> 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);
+
+}