2016-06-08 17:22:36 +00:00
|
|
|
/*
|
2016-11-18 23:13:20 +00:00
|
|
|
This file is part of solidity.
|
2016-06-08 17:22:36 +00:00
|
|
|
|
2016-11-18 23:13:20 +00:00
|
|
|
solidity is free software: you can redistribute it and/or modify
|
2016-06-08 17:22:36 +00:00
|
|
|
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.
|
|
|
|
|
2016-11-18 23:13:20 +00:00
|
|
|
solidity is distributed in the hope that it will be useful,
|
2016-06-08 17:22:36 +00:00
|
|
|
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
|
2016-11-18 23:13:20 +00:00
|
|
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
2016-08-02 16:32:03 +00:00
|
|
|
|
|
|
|
The Implementation originally from https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx
|
2016-06-08 17:22:36 +00:00
|
|
|
*/
|
2017-02-24 23:11:26 +00:00
|
|
|
/// @file RPCSession.cpp
|
|
|
|
/// Low-level IPC communication between the test framework and the Ethereum node.
|
|
|
|
|
2018-02-23 15:41:23 +00:00
|
|
|
#include <test/RPCSession.h>
|
|
|
|
|
2018-03-14 11:04:04 +00:00
|
|
|
#include <test/Options.h>
|
2018-02-23 15:41:23 +00:00
|
|
|
|
2018-11-14 13:59:30 +00:00
|
|
|
#include <liblangutil/EVMVersion.h>
|
2016-06-08 17:22:36 +00:00
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
#include <libdevcore/CommonData.h>
|
2017-02-24 23:11:26 +00:00
|
|
|
|
2018-02-07 01:05:20 +00:00
|
|
|
#include <libdevcore/JSON.h>
|
2017-02-24 23:11:26 +00:00
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <thread>
|
|
|
|
#include <chrono>
|
2016-06-09 16:54:29 +00:00
|
|
|
|
2016-06-08 17:22:36 +00:00
|
|
|
using namespace std;
|
2016-06-09 16:54:29 +00:00
|
|
|
using namespace dev;
|
2016-06-08 17:22:36 +00:00
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
IPCSocket::IPCSocket(string const& _path): m_path(_path)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2016-08-03 06:13:48 +00:00
|
|
|
#if defined(_WIN32)
|
2016-08-02 16:32:03 +00:00
|
|
|
m_socket = CreateFile(
|
|
|
|
m_path.c_str(), // pipe name
|
|
|
|
GENERIC_READ | // read and write access
|
|
|
|
GENERIC_WRITE,
|
|
|
|
0, // no sharing
|
|
|
|
NULL, // default security attribute
|
|
|
|
OPEN_EXISTING, // opens existing pipe
|
|
|
|
0, // default attributes
|
|
|
|
NULL); // no template file
|
|
|
|
|
|
|
|
if (m_socket == INVALID_HANDLE_VALUE)
|
2016-08-31 14:29:10 +00:00
|
|
|
BOOST_FAIL("Error creating IPC socket object!");
|
2016-08-02 16:32:03 +00:00
|
|
|
|
2016-08-02 08:11:04 +00:00
|
|
|
#else
|
2016-06-09 16:54:29 +00:00
|
|
|
if (_path.length() >= sizeof(sockaddr_un::sun_path))
|
2016-06-08 17:22:36 +00:00
|
|
|
BOOST_FAIL("Error opening IPC: socket path is too long!");
|
|
|
|
|
|
|
|
struct sockaddr_un saun;
|
2016-08-01 05:25:37 +00:00
|
|
|
memset(&saun, 0, sizeof(sockaddr_un));
|
2016-06-08 17:22:36 +00:00
|
|
|
saun.sun_family = AF_UNIX;
|
|
|
|
strcpy(saun.sun_path, _path.c_str());
|
|
|
|
|
2016-08-01 05:25:37 +00:00
|
|
|
// http://idletechnology.blogspot.ca/2011/12/unix-domain-sockets-on-osx.html
|
|
|
|
//
|
|
|
|
// SUN_LEN() might be optimal, but it seemingly affects the portability,
|
|
|
|
// with at least Android missing this macro. Just using the sizeof() for
|
|
|
|
// structure seemingly works, and would only have the side-effect of
|
|
|
|
// sending larger-than-required packets over the socket. Given that this
|
|
|
|
// code is only used for unit-tests, that approach seems simpler.
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
saun.sun_len = sizeof(struct sockaddr_un);
|
|
|
|
#endif // defined(__APPLE__)
|
|
|
|
|
2016-06-08 17:22:36 +00:00
|
|
|
if ((m_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
|
|
|
BOOST_FAIL("Error creating IPC socket object");
|
|
|
|
|
2016-08-01 05:25:37 +00:00
|
|
|
if (connect(m_socket, reinterpret_cast<struct sockaddr const*>(&saun), sizeof(struct sockaddr_un)) < 0)
|
2017-10-19 10:00:24 +00:00
|
|
|
{
|
|
|
|
close(m_socket);
|
2016-06-08 17:22:36 +00:00
|
|
|
BOOST_FAIL("Error connecting to IPC socket: " << _path);
|
2017-10-19 10:00:24 +00:00
|
|
|
}
|
2016-08-02 08:11:04 +00:00
|
|
|
#endif
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string IPCSocket::sendRequest(string const& _req)
|
|
|
|
{
|
2016-08-02 08:11:04 +00:00
|
|
|
#if defined(_WIN32)
|
2017-02-09 13:06:48 +00:00
|
|
|
// Write to the pipe.
|
2016-08-02 16:32:03 +00:00
|
|
|
DWORD cbWritten;
|
|
|
|
BOOL fSuccess = WriteFile(
|
|
|
|
m_socket, // pipe handle
|
|
|
|
_req.c_str(), // message
|
|
|
|
_req.size(), // message length
|
|
|
|
&cbWritten, // bytes written
|
|
|
|
NULL); // not overlapped
|
|
|
|
|
2017-02-09 13:08:52 +00:00
|
|
|
if (!fSuccess || (_req.size() != cbWritten))
|
2016-08-02 16:32:03 +00:00
|
|
|
BOOST_FAIL("WriteFile to pipe failed");
|
|
|
|
|
|
|
|
// Read from the pipe.
|
2017-02-09 13:06:48 +00:00
|
|
|
DWORD cbRead;
|
2016-08-02 16:32:03 +00:00
|
|
|
fSuccess = ReadFile(
|
2017-02-07 14:10:43 +00:00
|
|
|
m_socket, // pipe handle
|
|
|
|
m_readBuf, // buffer to receive reply
|
|
|
|
sizeof(m_readBuf), // size of buffer
|
|
|
|
&cbRead, // number of bytes read
|
|
|
|
NULL); // not overlapped
|
2016-08-02 16:32:03 +00:00
|
|
|
|
|
|
|
if (!fSuccess)
|
|
|
|
BOOST_FAIL("ReadFile from pipe failed");
|
|
|
|
|
2017-02-09 13:06:48 +00:00
|
|
|
return string(m_readBuf, m_readBuf + cbRead);
|
2016-08-02 08:11:04 +00:00
|
|
|
#else
|
2017-02-07 13:34:00 +00:00
|
|
|
if (send(m_socket, _req.c_str(), _req.length(), 0) != (ssize_t)_req.length())
|
2017-02-24 23:11:26 +00:00
|
|
|
BOOST_FAIL("Writing on IPC failed.");
|
|
|
|
|
|
|
|
auto start = chrono::steady_clock::now();
|
|
|
|
ssize_t ret;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
ret = recv(m_socket, m_readBuf, sizeof(m_readBuf), 0);
|
|
|
|
// Also consider closed socket an error.
|
|
|
|
if (ret < 0)
|
|
|
|
BOOST_FAIL("Reading on IPC failed.");
|
2017-03-02 11:07:50 +00:00
|
|
|
}
|
|
|
|
while (
|
2017-02-24 23:11:26 +00:00
|
|
|
ret == 0 &&
|
|
|
|
chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count() < m_readTimeOutMS
|
|
|
|
);
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
BOOST_FAIL("Timeout reading on IPC.");
|
2017-02-07 14:10:43 +00:00
|
|
|
|
|
|
|
return string(m_readBuf, m_readBuf + ret);
|
2016-08-02 08:11:04 +00:00
|
|
|
#endif
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2019-02-13 15:22:42 +00:00
|
|
|
RPCSession& RPCSession::instance(string const& _path)
|
2016-06-09 16:54:29 +00:00
|
|
|
{
|
2019-02-06 11:10:48 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
static RPCSession session(_path);
|
|
|
|
BOOST_REQUIRE_EQUAL(session.m_ipcSocket.path(), _path);
|
|
|
|
return session;
|
|
|
|
}
|
|
|
|
catch (std::exception const&)
|
|
|
|
{
|
|
|
|
BOOST_THROW_EXCEPTION(std::runtime_error("Error creating RPC session for socket: " + _path));
|
|
|
|
}
|
2016-06-09 16:54:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string RPCSession::eth_getCode(string const& _address, string const& _blockNumber)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2016-06-09 16:54:29 +00:00
|
|
|
return rpcCall("eth_getCode", { quote(_address), quote(_blockNumber) }).asString();
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2017-02-09 18:41:51 +00:00
|
|
|
Json::Value RPCSession::eth_getBlockByNumber(string const& _blockNumber, bool _fullObjects)
|
|
|
|
{
|
|
|
|
// NOTE: to_string() converts bool to 0 or 1
|
|
|
|
return rpcCall("eth_getBlockByNumber", { quote(_blockNumber), _fullObjects ? "true" : "false" });
|
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
RPCSession::TransactionReceipt RPCSession::eth_getTransactionReceipt(string const& _transactionHash)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2016-06-09 16:54:29 +00:00
|
|
|
TransactionReceipt receipt;
|
|
|
|
Json::Value const result = rpcCall("eth_getTransactionReceipt", { quote(_transactionHash) });
|
|
|
|
receipt.gasUsed = result["gasUsed"].asString();
|
|
|
|
receipt.contractAddress = result["contractAddress"].asString();
|
2017-02-07 16:20:05 +00:00
|
|
|
receipt.blockNumber = result["blockNumber"].asString();
|
2018-06-15 10:18:00 +00:00
|
|
|
if (m_receiptHasStatusField)
|
|
|
|
{
|
|
|
|
BOOST_REQUIRE(!result["status"].isNull());
|
|
|
|
receipt.status = result["status"].asString();
|
|
|
|
}
|
2016-06-13 15:10:58 +00:00
|
|
|
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);
|
|
|
|
}
|
2016-06-08 17:22:36 +00:00
|
|
|
return receipt;
|
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
string RPCSession::eth_sendTransaction(TransactionData const& _td)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2016-06-09 16:54:29 +00:00
|
|
|
return rpcCall("eth_sendTransaction", { _td.toJson() }).asString();
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
string RPCSession::eth_call(TransactionData const& _td, string const& _blockNumber)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2016-06-09 16:54:29 +00:00
|
|
|
return rpcCall("eth_call", { _td.toJson(), quote(_blockNumber) }).asString();
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
string RPCSession::eth_sendTransaction(string const& _transaction)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2016-06-09 16:54:29 +00:00
|
|
|
return rpcCall("eth_sendTransaction", { _transaction }).asString();
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
string RPCSession::eth_getBalance(string const& _address, string const& _blockNumber)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
|
|
|
string address = (_address.length() == 20) ? "0x" + _address : _address;
|
2016-06-09 16:54:29 +00:00
|
|
|
return rpcCall("eth_getBalance", { quote(address), quote(_blockNumber) }).asString();
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-13 22:12:13 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2018-08-10 17:19:21 +00:00
|
|
|
string RPCSession::eth_gasPrice()
|
|
|
|
{
|
|
|
|
return rpcCall("eth_gasPrice").asString();
|
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
void RPCSession::personal_unlockAccount(string const& _address, string const& _password, int _duration)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2017-03-01 10:32:29 +00:00
|
|
|
BOOST_REQUIRE_MESSAGE(
|
|
|
|
rpcCall("personal_unlockAccount", { quote(_address), quote(_password), to_string(_duration) }),
|
|
|
|
"Error unlocking account " + _address
|
|
|
|
);
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
string RPCSession::personal_newAccount(string const& _password)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2017-03-01 10:32:29 +00:00
|
|
|
string addr = rpcCall("personal_newAccount", { quote(_password) }).asString();
|
2017-03-03 14:47:05 +00:00
|
|
|
BOOST_TEST_MESSAGE("Created account " + addr);
|
2017-03-01 10:32:29 +00:00
|
|
|
return addr;
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-18 00:08:20 +00:00
|
|
|
void RPCSession::test_setChainParams(vector<string> const& _accounts)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2018-02-26 18:53:38 +00:00
|
|
|
string forks;
|
2019-02-25 14:29:57 +00:00
|
|
|
if (test::Options::get().evmVersion() >= langutil::EVMVersion::tangerineWhistle())
|
2018-02-26 18:53:38 +00:00
|
|
|
forks += "\"EIP150ForkBlock\": \"0x00\",\n";
|
2019-02-25 14:29:57 +00:00
|
|
|
if (test::Options::get().evmVersion() >= langutil::EVMVersion::spuriousDragon())
|
2018-02-26 18:53:38 +00:00
|
|
|
forks += "\"EIP158ForkBlock\": \"0x00\",\n";
|
2019-02-25 14:29:57 +00:00
|
|
|
if (test::Options::get().evmVersion() >= langutil::EVMVersion::byzantium())
|
2018-06-15 10:18:00 +00:00
|
|
|
{
|
2018-02-26 18:53:38 +00:00
|
|
|
forks += "\"byzantiumForkBlock\": \"0x00\",\n";
|
2018-06-15 10:18:00 +00:00
|
|
|
m_receiptHasStatusField = true;
|
|
|
|
}
|
2019-02-25 14:29:57 +00:00
|
|
|
if (test::Options::get().evmVersion() >= langutil::EVMVersion::constantinople())
|
2018-04-05 09:55:46 +00:00
|
|
|
forks += "\"constantinopleForkBlock\": \"0x00\",\n";
|
2019-02-25 14:51:26 +00:00
|
|
|
if (test::Options::get().evmVersion() >= langutil::EVMVersion::petersburg())
|
|
|
|
forks += "\"constantinopleFixForkBlock\": \"0x00\",\n";
|
2018-02-07 01:05:20 +00:00
|
|
|
static string const c_configString = R"(
|
2016-06-18 00:08:20 +00:00
|
|
|
{
|
|
|
|
"sealEngine": "NoProof",
|
|
|
|
"params": {
|
2017-09-13 10:34:40 +00:00
|
|
|
"accountStartNonce": "0x00",
|
2016-06-18 00:08:20 +00:00
|
|
|
"maximumExtraDataSize": "0x1000000",
|
|
|
|
"blockReward": "0x",
|
2017-09-13 10:34:40 +00:00
|
|
|
"allowFutureBlocks": true,
|
2018-02-26 18:53:38 +00:00
|
|
|
)" + forks + R"(
|
|
|
|
"homesteadForkBlock": "0x00"
|
2016-06-18 00:08:20 +00:00
|
|
|
},
|
|
|
|
"genesis": {
|
|
|
|
"author": "0000000000000010000000000000000000000000",
|
|
|
|
"timestamp": "0x00",
|
|
|
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
|
|
"extraData": "0x",
|
2018-06-14 14:41:02 +00:00
|
|
|
"gasLimit": "0x1000000000000",
|
2018-06-25 11:55:23 +00:00
|
|
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
|
|
"nonce": "0x0000000000000042",
|
2018-06-30 10:07:30 +00:00
|
|
|
"difficulty": "131072"
|
|
|
|
},
|
2016-06-18 00:08:20 +00:00
|
|
|
"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 } } },
|
2017-10-09 09:09:20 +00:00
|
|
|
"0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
|
2017-10-24 09:42:48 +00:00
|
|
|
"0000000000000000000000000000000000000005": { "wei": "1", "precompiled": { "name": "modexp" } },
|
|
|
|
"0000000000000000000000000000000000000006": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_add", "linear": { "base": 500, "word": 0 } } },
|
|
|
|
"0000000000000000000000000000000000000007": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_mul", "linear": { "base": 40000, "word": 0 } } },
|
|
|
|
"0000000000000000000000000000000000000008": { "wei": "1", "precompiled": { "name": "alt_bn128_pairing_product" } }
|
2016-06-18 00:08:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
|
|
|
Json::Value config;
|
2018-02-07 01:05:20 +00:00
|
|
|
BOOST_REQUIRE(jsonParseStrict(c_configString, config));
|
2016-06-18 00:08:20 +00:00
|
|
|
for (auto const& account: _accounts)
|
|
|
|
config["accounts"][account]["wei"] = "0x100000000000000000000000000000000000000000";
|
2018-02-07 01:05:20 +00:00
|
|
|
test_setChainParams(jsonCompactPrint(config));
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
void RPCSession::test_setChainParams(string const& _config)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2017-02-08 12:31:26 +00:00
|
|
|
BOOST_REQUIRE(rpcCall("test_setChainParams", { _config }) == true);
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
void RPCSession::test_rewindToBlock(size_t _blockNr)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2017-02-08 12:31:26 +00:00
|
|
|
BOOST_REQUIRE(rpcCall("test_rewindToBlock", { to_string(_blockNr) }) == true);
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
void RPCSession::test_mineBlocks(int _number)
|
|
|
|
{
|
|
|
|
u256 startBlock = fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString()));
|
2017-02-08 12:31:26 +00:00
|
|
|
BOOST_REQUIRE(rpcCall("test_mineBlocks", { to_string(_number) }, true) == true);
|
2018-09-12 12:35:41 +00:00
|
|
|
BOOST_REQUIRE(fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString())) == startBlock + _number);
|
2016-06-09 16:54:29 +00:00
|
|
|
}
|
|
|
|
|
2016-06-18 00:08:20 +00:00
|
|
|
void RPCSession::test_modifyTimestamp(size_t _timestamp)
|
|
|
|
{
|
2017-02-08 12:31:26 +00:00
|
|
|
BOOST_REQUIRE(rpcCall("test_modifyTimestamp", { to_string(_timestamp) }) == true);
|
2016-06-18 00:08:20 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const& _args, bool _canFail)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2017-05-17 19:57:55 +00:00
|
|
|
BOOST_TEST_MESSAGE("Request: " + request);
|
2016-06-08 17:22:36 +00:00
|
|
|
string reply = m_ipcSocket.sendRequest(request);
|
2017-05-17 19:57:55 +00:00
|
|
|
BOOST_TEST_MESSAGE("Reply: " + reply);
|
2016-06-09 16:54:29 +00:00
|
|
|
|
|
|
|
Json::Value result;
|
2018-04-05 09:59:31 +00:00
|
|
|
string errorMsg;
|
|
|
|
if (!jsonParseStrict(reply, result, &errorMsg))
|
2019-01-30 13:34:40 +00:00
|
|
|
BOOST_FAIL("Failed to parse JSON-RPC response: " + errorMsg);
|
2016-06-09 16:54:29 +00:00
|
|
|
|
2019-01-30 12:57:25 +00:00
|
|
|
if (!result.isMember("id") || !result["id"].isUInt())
|
|
|
|
BOOST_FAIL("Badly formatted JSON-RPC response (missing or non-integer \"id\")");
|
|
|
|
if (result["id"].asUInt() != (m_rpcSequence - 1))
|
|
|
|
BOOST_FAIL(
|
|
|
|
"Response identifier mismatch. "
|
|
|
|
"Expected " + to_string(m_rpcSequence - 1) + " but got " + to_string(result["id"].asUInt()) + "."
|
|
|
|
);
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
if (result.isMember("error"))
|
|
|
|
{
|
|
|
|
if (_canFail)
|
|
|
|
return Json::Value();
|
2016-06-13 13:17:56 +00:00
|
|
|
|
2016-06-13 14:02:58 +00:00
|
|
|
BOOST_FAIL("Error on JSON-RPC call: " + result["error"]["message"].asString());
|
2016-06-09 16:54:29 +00:00
|
|
|
}
|
2019-03-25 14:09:15 +00:00
|
|
|
|
|
|
|
if (!result.isMember("result") || result["result"].isNull())
|
2019-04-04 10:25:12 +00:00
|
|
|
BOOST_FAIL(
|
|
|
|
"Missing result for JSON-RPC call: " +
|
|
|
|
result.toStyledString() +
|
|
|
|
"\nRequest was " +
|
|
|
|
request
|
|
|
|
);
|
2019-03-25 14:09:15 +00:00
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
return result["result"];
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2017-10-20 11:41:50 +00:00
|
|
|
string const& RPCSession::accountCreate()
|
|
|
|
{
|
|
|
|
m_accounts.push_back(personal_newAccount(""));
|
|
|
|
personal_unlockAccount(m_accounts.back(), "", 100000);
|
|
|
|
return m_accounts.back();
|
|
|
|
}
|
|
|
|
|
2016-06-18 00:08:20 +00:00
|
|
|
string const& RPCSession::accountCreateIfNotExists(size_t _id)
|
2016-06-09 16:54:29 +00:00
|
|
|
{
|
2017-10-20 11:44:52 +00:00
|
|
|
while ((_id + 1) > m_accounts.size())
|
2017-10-20 11:41:50 +00:00
|
|
|
accountCreate();
|
2016-06-18 00:08:20 +00:00
|
|
|
return m_accounts[_id];
|
2016-06-09 16:54:29 +00:00
|
|
|
}
|
|
|
|
|
2019-02-13 15:22:42 +00:00
|
|
|
RPCSession::RPCSession(string const& _path):
|
2016-06-18 00:08:20 +00:00
|
|
|
m_ipcSocket(_path)
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2017-10-20 11:41:50 +00:00
|
|
|
accountCreate();
|
|
|
|
// This will pre-fund the accounts create prior.
|
2016-06-18 00:08:20 +00:00
|
|
|
test_setChainParams(m_accounts);
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 16:54:29 +00:00
|
|
|
string RPCSession::TransactionData::toJson() const
|
2016-06-08 17:22:36 +00:00
|
|
|
{
|
2016-06-09 16:54:29 +00:00
|
|
|
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;
|
2018-02-07 01:05:20 +00:00
|
|
|
return jsonCompactPrint(json);
|
2016-06-08 17:22:36 +00:00
|
|
|
}
|