aboutsummaryrefslogtreecommitdiffstats
path: root/test/RPCSession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/RPCSession.cpp')
-rw-r--r--test/RPCSession.cpp120
1 files changed, 68 insertions, 52 deletions
diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp
index 44d21d69..f8b364d1 100644
--- a/test/RPCSession.cpp
+++ b/test/RPCSession.cpp
@@ -16,18 +16,20 @@
The Implementation originally from https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx
*/
-/** @file RPCSession.cpp
- * @author Dimtiry Khokhlov <dimitry@ethdev.com>
- * @date 2016
- */
+/// @file RPCSession.cpp
+/// Low-level IPC communication between the test framework and the Ethereum node.
+
+#include "RPCSession.h"
-#include <string>
-#include <stdio.h>
-#include <thread>
#include <libdevcore/CommonData.h>
+
#include <json/reader.h>
#include <json/writer.h>
-#include "RPCSession.h"
+
+#include <string>
+#include <stdio.h>
+#include <thread>
+#include <chrono>
using namespace std;
using namespace dev;
@@ -73,15 +75,13 @@ IPCSocket::IPCSocket(string const& _path): m_path(_path)
if (connect(m_socket, reinterpret_cast<struct sockaddr const*>(&saun), sizeof(struct sockaddr_un)) < 0)
BOOST_FAIL("Error connecting to IPC socket: " << _path);
-
- m_fp = fdopen(m_socket, "r");
#endif
}
string IPCSocket::sendRequest(string const& _req)
{
#if defined(_WIN32)
- string returnStr;
+ // Write to the pipe.
DWORD cbWritten;
BOOL fSuccess = WriteFile(
m_socket, // pipe handle
@@ -90,40 +90,44 @@ string IPCSocket::sendRequest(string const& _req)
&cbWritten, // bytes written
NULL); // not overlapped
- if (!fSuccess)
+ if (!fSuccess || (_req.size() != cbWritten))
BOOST_FAIL("WriteFile to pipe failed");
- DWORD cbRead;
- TCHAR chBuf[c_buffsize];
-
// Read from the pipe.
+ DWORD cbRead;
fSuccess = ReadFile(
- m_socket, // pipe handle
- chBuf, // buffer to receive reply
- c_buffsize,// size of buffer
- &cbRead, // number of bytes read
- NULL); // not overlapped
-
- returnStr += chBuf;
+ m_socket, // pipe handle
+ m_readBuf, // buffer to receive reply
+ sizeof(m_readBuf), // size of buffer
+ &cbRead, // number of bytes read
+ NULL); // not overlapped
if (!fSuccess)
BOOST_FAIL("ReadFile from pipe failed");
- cerr << "."; //Output for log activity
- return returnStr;
+ return string(m_readBuf, m_readBuf + cbRead);
#else
- send(m_socket, _req.c_str(), _req.length(), 0);
+ if (send(m_socket, _req.c_str(), _req.length(), 0) != (ssize_t)_req.length())
+ BOOST_FAIL("Writing on IPC failed.");
- char c;
- string response;
- while ((c = fgetc(m_fp)) != EOF)
+ auto start = chrono::steady_clock::now();
+ ssize_t ret;
+ do
{
- if (c != '\n')
- response += c;
- else
- break;
+ 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.");
}
- return response;
+ while (
+ ret == 0 &&
+ chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count() < m_readTimeOutMS
+ );
+
+ if (ret == 0)
+ BOOST_FAIL("Timeout reading on IPC.");
+
+ return string(m_readBuf, m_readBuf + ret);
#endif
}
@@ -139,6 +143,12 @@ string RPCSession::eth_getCode(string const& _address, string const& _blockNumbe
return rpcCall("eth_getCode", { quote(_address), quote(_blockNumber) }).asString();
}
+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" });
+}
+
RPCSession::TransactionReceipt RPCSession::eth_getTransactionReceipt(string const& _transactionHash)
{
TransactionReceipt receipt;
@@ -146,6 +156,7 @@ RPCSession::TransactionReceipt RPCSession::eth_getTransactionReceipt(string cons
BOOST_REQUIRE(!result.isNull());
receipt.gasUsed = result["gasUsed"].asString();
receipt.contractAddress = result["contractAddress"].asString();
+ receipt.blockNumber = result["blockNumber"].asString();
for (auto const& log: result["logs"])
{
LogEntry entry;
@@ -187,12 +198,17 @@ string RPCSession::eth_getStorageRoot(string const& _address, string const& _blo
void RPCSession::personal_unlockAccount(string const& _address, string const& _password, int _duration)
{
- rpcCall("personal_unlockAccount", { quote(_address), quote(_password), to_string(_duration) });
+ BOOST_REQUIRE_MESSAGE(
+ rpcCall("personal_unlockAccount", { quote(_address), quote(_password), to_string(_duration) }),
+ "Error unlocking account " + _address
+ );
}
string RPCSession::personal_newAccount(string const& _password)
{
- return rpcCall("personal_newAccount", { quote(_password) }).asString();
+ string addr = rpcCall("personal_newAccount", { quote(_password) }).asString();
+ BOOST_TEST_MESSAGE("Created account " + addr);
+ return addr;
}
void RPCSession::test_setChainParams(vector<string> const& _accounts)
@@ -231,40 +247,43 @@ void RPCSession::test_setChainParams(vector<string> const& _accounts)
void RPCSession::test_setChainParams(string const& _config)
{
- rpcCall("test_setChainParams", { _config });
+ BOOST_REQUIRE(rpcCall("test_setChainParams", { _config }) == true);
}
void RPCSession::test_rewindToBlock(size_t _blockNr)
{
- rpcCall("test_rewindToBlock", { to_string(_blockNr) });
+ BOOST_REQUIRE(rpcCall("test_rewindToBlock", { to_string(_blockNr) }) == true);
}
void RPCSession::test_mineBlocks(int _number)
{
u256 startBlock = fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString()));
- rpcCall("test_mineBlocks", { to_string(_number) }, true);
-
- bool mined = false;
+ BOOST_REQUIRE(rpcCall("test_mineBlocks", { to_string(_number) }, true) == true);
// We auto-calibrate the time it takes to mine the transaction.
// It would be better to go without polling, but that would probably need a change to the test client
+ auto startTime = std::chrono::steady_clock::now();
unsigned sleepTime = m_sleepTime;
- size_t polls = 0;
- for (; polls < 14 && !mined; ++polls)
+ size_t tries = 0;
+ for (; ; ++tries)
{
std::this_thread::sleep_for(chrono::milliseconds(sleepTime));
+ auto endTime = std::chrono::steady_clock::now();
+ unsigned timeSpent = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
+ if (timeSpent > m_maxMiningTime)
+ BOOST_FAIL("Error in test_mineBlocks: block mining timeout!");
if (fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString())) >= startBlock + _number)
- mined = true;
+ break;
else
sleepTime *= 2;
}
- if (polls > 1)
+ if (tries > 1)
{
m_successfulMineRuns = 0;
m_sleepTime += 2;
}
- else if (polls == 1)
+ else if (tries == 1)
{
m_successfulMineRuns++;
if (m_successfulMineRuns > 5)
@@ -274,14 +293,11 @@ void RPCSession::test_mineBlocks(int _number)
m_sleepTime--;
}
}
-
- if (!mined)
- BOOST_FAIL("Error in test_mineBlocks: block mining timeout!");
}
void RPCSession::test_modifyTimestamp(size_t _timestamp)
{
- rpcCall("test_modifyTimestamp", { to_string(_timestamp) });
+ BOOST_REQUIRE(rpcCall("test_modifyTimestamp", { to_string(_timestamp) }) == true);
}
Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const& _args, bool _canFail)
@@ -297,12 +313,12 @@ Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const&
request += "],\"id\":" + to_string(m_rpcSequence) + "}";
++m_rpcSequence;
- //cout << "Request: " << request << endl;
+ // cout << "Request: " << request << endl;
string reply = m_ipcSocket.sendRequest(request);
- //cout << "Reply: " << reply << endl;
+ // cout << "Reply: " << reply << endl;
Json::Value result;
- Json::Reader().parse(reply, result, false);
+ BOOST_REQUIRE(Json::Reader().parse(reply, result, false));
if (result.isMember("error"))
{