From 8d5705420963d03b6060af02375feb0bed9ced68 Mon Sep 17 00:00:00 2001 From: Dimitry Kh Date: Wed, 22 Apr 2020 23:41:13 +0300 Subject: [PATCH 1/5] refactor rpc interface logic --- retesteth/ExitHandler.h | 2 +- retesteth/RPCSession.cpp | 516 ------------------ retesteth/RPCSession.h | 98 ---- retesteth/Socket.cpp | 278 ---------- retesteth/TestSuite.cpp | 46 +- retesteth/configs/ClientConfig.h | 10 +- retesteth/main.cpp | 2 +- retesteth/session/RPCImplementation.cpp | 288 ++++++++++ retesteth/session/RPCImplementation.h | 73 +++ retesteth/session/RPCSession.cpp | 248 +++++++++ retesteth/session/RPCSession.h | 40 ++ retesteth/session/SessionInterface.h | 78 +++ retesteth/session/Socket.cpp | 273 +++++++++ retesteth/{ => session}/Socket.h | 14 +- retesteth/testSuites/Common.cpp | 10 +- retesteth/testSuites/Common.h | 18 +- retesteth/testSuites/CompareStates.cpp | 8 +- retesteth/testSuites/RPCTests.cpp | 4 +- retesteth/testSuites/StateTests.cpp | 8 +- retesteth/testSuites/VMTestsConverter.cpp | 2 +- .../blockchain/BlockchainTestLogic.cpp | 4 +- .../fillers/BlockchainTestFillerLogic.cpp | 2 +- .../blockchain/fillers/TestBlockchain.cpp | 2 +- .../blockchain/fillers/TestBlockchain.h | 8 +- .../fillers/TestBlockchainManager.h | 8 +- 25 files changed, 1078 insertions(+), 962 deletions(-) delete mode 100644 retesteth/RPCSession.cpp delete mode 100644 retesteth/RPCSession.h delete mode 100644 retesteth/Socket.cpp create mode 100644 retesteth/session/RPCImplementation.cpp create mode 100644 retesteth/session/RPCImplementation.h create mode 100644 retesteth/session/RPCSession.cpp create mode 100644 retesteth/session/RPCSession.h create mode 100644 retesteth/session/SessionInterface.h create mode 100644 retesteth/session/Socket.cpp rename retesteth/{ => session}/Socket.h (95%) diff --git a/retesteth/ExitHandler.h b/retesteth/ExitHandler.h index 28090b913..192db1082 100644 --- a/retesteth/ExitHandler.h +++ b/retesteth/ExitHandler.h @@ -1,5 +1,5 @@ #pragma once -#include +#include class ExitHandler { diff --git a/retesteth/RPCSession.cpp b/retesteth/RPCSession.cpp deleted file mode 100644 index 4af963fd0..000000000 --- a/retesteth/RPCSession.cpp +++ /dev/null @@ -1,516 +0,0 @@ -/* - This file is part of solidity. - - solidity 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. - - solidity 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 solidity. If not, see . - - The Implementation originally from https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx -*/ -/// @file RPCSession.cpp -/// Low-level IPC communication between the test framework and the Ethereum node. - -#include "RPCSession.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace std; -using namespace dev; - -struct sessionInfo -{ - sessionInfo( - FILE* _pipe, RPCSession* _session, std::string const& _tmpDir, int _pid, test::ClientConfigID const& _configId) - { - session.reset(_session); - filePipe.reset(_pipe); - tmpDir = _tmpDir; - pipePid = _pid; - isUsed = RPCSession::NotExist; - configId = _configId; - } - std::unique_ptr session; - std::unique_ptr filePipe; - int pipePid; - RPCSession::SessionStatus isUsed; - std::string tmpDir; - test::ClientConfigID configId; -}; - -void closeSession(const string& _threadID); -string const RPCSession::c_errorMiningString = "remote test_mineBlocks = false"; - -std::mutex g_socketMapMutex; -static std::map socketMap; -void RPCSession::runNewInstanceOfAClient(string const& _threadID, ClientConfig const& _config) -{ - if (_config.getSocketType() == Socket::IPC) - { - fs::path tmpDir = test::createUniqueTmpDirectory(); - string ipcPath = tmpDir.string() + "/geth.ipc"; - - string command = "bash"; - std::vector args; - args.push_back(_config.getShellPath().c_str()); - args.push_back(tmpDir.string()); - args.push_back(ipcPath); - - int pid = 0; - test::popenOutput mode = (Options::get().enableClientsOutput) ? - test::popenOutput::EnableALL : - test::popenOutput::DisableAll; - FILE* fp = test::popen2(command, args, "r", pid, mode); - if (!fp) - { - ETH_ERROR_MESSAGE("Failed to start the client: '" + command + "'"); - std::raise(SIGABRT); - } - else - { - int maxSeconds = 25; - while (!boost::filesystem::exists(ipcPath) && maxSeconds-- > 0) - std::this_thread::sleep_for(std::chrono::seconds(1)); - ETH_FAIL_REQUIRE_MESSAGE(maxSeconds > 0, "Client took too long to start ipc!"); - // Client has opened ipc socket. wait for it to initialize - std::this_thread::sleep_for(std::chrono::seconds(4)); - } - sessionInfo info(fp, new RPCSession(Socket::SocketType::IPC, ipcPath), tmpDir.string(), pid, - _config.getId()); - { - std::lock_guard lock( - g_socketMapMutex); // function must be called from lock - socketMap.insert(std::pair(_threadID, std::move(info))); - } - } - else if (_config.getSocketType() == Socket::TCP) - { - std::lock_guard lock(g_socketMapMutex); // function must be called from lock - - DataObject const& ports = (Options::get().nodesoverride.getSubObjects().size() > 0 ? - Options::get().nodesoverride : - _config.getAddressObject()); - - // Create sessionInfo for a tcp address that is still not present in socketMap - for (auto const& addr : ports.getSubObjects()) - { - bool unused = true; - for (auto const& socket : socketMap) - { - sessionInfo const& sInfo = socket.second; - if (sInfo.session.get()->getSocketPath() == addr.asString()) - { - unused = false; - break; - } - } - if (unused) - { - sessionInfo info(NULL, new RPCSession(Socket::SocketType::TCP, addr.asString()), "", - 0, _config.getId()); - socketMap.insert(std::pair(_threadID, std::move(info))); - return; - } - } - } - else if (_config.getSocketType() == Socket::IPCDebug) - { - // connect to already opend .ipc socket - fs::path tmpDir = test::createUniqueTmpDirectory(); - string ipcPath = _config.getAddress(); - int pid = 0; - FILE* fp = NULL; - sessionInfo info(fp, new RPCSession(Socket::SocketType::IPC, ipcPath), tmpDir.string(), pid, - _config.getId()); - { - std::lock_guard lock( - g_socketMapMutex); // function must be called from lock - socketMap.insert(std::pair(_threadID, std::move(info))); - } - } - else - ETH_FAIL_MESSAGE("Unknown Socket Type in runNewInstanceOfAClient"); -} - -RPCSession& RPCSession::instance(const string& _threadID) -{ - bool needToCreateNew = false; - { - std::lock_guard lock(g_socketMapMutex); - test::ClientConfigID currentConfigId = Options::getDynamicOptions().getCurrentConfig().getId(); - if (socketMap.count(_threadID) && socketMap.at(_threadID).configId != currentConfigId) - { - // For this thread a session is opened but it is opened not for current tested client - ETH_FAIL_MESSAGE("A session opened for another client id!"); - } - - if (!socketMap.count(_threadID)) - { - // look for free clients that already instantiated - for (auto& socket : socketMap) - { - if (socket.second.isUsed == SessionStatus::Available) - if (socket.second.configId == currentConfigId) - { - socket.second.isUsed = SessionStatus::Working; - socketMap.insert( - std::pair(_threadID, std::move(socket.second))); - socketMap.erase(socketMap.find(socket.first)); // remove previous threadID - // assigment to this socket - return *(socketMap.at(_threadID).session.get()); - } - } - needToCreateNew = true; - } - } - if (needToCreateNew) - runNewInstanceOfAClient(_threadID, Options::getDynamicOptions().getCurrentConfig()); - - std::lock_guard lock(g_socketMapMutex); - ETH_FAIL_REQUIRE_MESSAGE(socketMap.size() <= Options::get().threadCount, - "Something went wrong. Retesteth connect to more instances than needed!"); - ETH_FAIL_REQUIRE_MESSAGE(socketMap.size() != 0, - "Something went wrong. Retesteth failed to create socket connection!"); - return *(socketMap.at(_threadID).session.get()); -} - -void RPCSession::sessionStart(std::string const& _threadID) -{ - RPCSession::instance(_threadID); // initialize the client if not exist - std::lock_guard lock(g_socketMapMutex); - if (socketMap.count(_threadID)) - socketMap.at(_threadID).isUsed = SessionStatus::Working; -} - -void RPCSession::sessionEnd(std::string const& _threadID, SessionStatus _status) -{ - std::lock_guard lock(g_socketMapMutex); - assert(socketMap.count(_threadID)); - if (socketMap.count(_threadID)) - socketMap.at(_threadID).isUsed = _status; -} - -RPCSession::SessionStatus RPCSession::sessionStatus(std::string const& _threadID) -{ - std::lock_guard lock(g_socketMapMutex); - if (socketMap.count(_threadID)) - return socketMap.at(_threadID).isUsed; - return RPCSession::NotExist; -} - -void closeSession(const string& _threadID) -{ - ETH_FAIL_REQUIRE_MESSAGE(socketMap.count(_threadID), "Socket map is empty in closeSession!"); - sessionInfo& element = socketMap.at(_threadID); - if (element.session.get()->getSocketType() == Socket::SocketType::IPC) - { - test::pclose2(element.filePipe.get(), element.pipePid); - std::this_thread::sleep_for(std::chrono::seconds(4)); - boost::filesystem::remove_all(boost::filesystem::path(element.tmpDir)); - element.filePipe.release(); - element.session.release(); - } -} - -void RPCSession::clear() -{ - std::lock_guard lock(g_socketMapMutex); - std::vector closingThreads; - for (auto& element : socketMap) - closingThreads.push_back(thread(closeSession, element.first)); - for (auto& th : closingThreads) - th.join(); - - socketMap.clear(); - closingThreads.clear(); -} - -scheme_debugAccountRange RPCSession::debug_accountRange( - std::string const& _blockHashOrNumber, int _txIndex, string const& _address, int _maxResults) -{ - return scheme_debugAccountRange(rpcCall( - "debug_accountRange", {quote(toString(u256(dev::fromHex(_blockHashOrNumber)))), - to_string(_txIndex), quote(_address), to_string(_maxResults)})); -} - -DataObject RPCSession::debug_storageRangeAt(std::string const& _blockHashOrNumber, int _txIndex, - string const& _address, string const& _begin, int _maxResults) -{ - return rpcCall("debug_storageRangeAt", - {quote(toString(u256(dev::fromHex(_blockHashOrNumber)))), to_string(_txIndex), - quote(_address), quote(_begin), to_string(_maxResults)}); -} - -scheme_debugTraceTransaction RPCSession::debug_traceTransaction(std::string const& _trHash) -{ - return scheme_debugTraceTransaction(rpcCall("debug_traceTransaction", {quote(_trHash), "{}"})); -} - -string RPCSession::web3_clientVersion() -{ - return rpcCall("web3_clientVersion", { }).asString(); -} - -string RPCSession::eth_getCode(string const& _address, string const& _blockNumber) -{ - return rpcCall("eth_getCode", { quote(_address), quote(_blockNumber) }).asString(); -} - -test::scheme_block RPCSession::eth_getBlockByNumber( - BlockNumber const& _blockNumber, bool _fullObjects) -{ - return test::scheme_block(rpcCall("eth_getBlockByNumber", - {quote(_blockNumber.getBlockNumberAsString()), _fullObjects ? "true" : "false"})); -} - -test::scheme_block RPCSession::eth_getBlockByHash(string const& _blockHash, bool _fullObjects) -{ - return test::scheme_block( - rpcCall("eth_getBlockByHash", {quote(_blockHash), _fullObjects ? "true" : "false"})); -} - -test::scheme_transactionReceipt RPCSession::eth_getTransactionReceipt(string const& _transactionHash) -{ - return test::scheme_transactionReceipt( - rpcCall("eth_getTransactionReceipt", {quote(_transactionHash)})); -} - -string RPCSession::eth_blockNumber() -{ - DataObject res = rpcCall("eth_blockNumber", {}); - return res.type() == DataType::String ? res.asString() : toString(res.asInt()); -} - -string RPCSession::eth_sendTransaction(string const& _transaction) -{ - return rpcCall("eth_sendTransaction", { _transaction }).asString(); -} - -string RPCSession::eth_sendRawTransaction(std::string const& _rlp) -{ - DataObject result = rpcCall("eth_sendRawTransaction", {quote(_rlp)}, true); - - DataObject const& lastError = getLastRPCError(); - if (lastError.type() != DataType::Null) - ETH_ERROR_MESSAGE(lastError.atKey("message").asString()); - if (!isHash(result.asString())) - ETH_ERROR_MESSAGE("eth_sendRawTransaction return invalid hash: '" + result.asString() + "'"); - if (result.type() == DataType::Null) // if the method failed - return ""; - return result.asString(); -} - -int RPCSession::eth_getTransactionCount( - std::string const& _address, std::string const& _blockNumber) -{ - DataObject res = rpcCall("eth_getTransactionCount", {quote(_address), quote(_blockNumber)}); - return (res.type() == DataType::String) ? test::hexOrDecStringToInt(res.asString()) : - res.asInt(); -} - -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(); -} - -string RPCSession::eth_getStorageAt(string const& _address, string const& _position, string const& _blockNumber) -{ - return rpcCall("eth_getStorageAt", { quote(_address), quote(_position), 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) -{ - string addr = rpcCall("personal_newAccount", { quote(_password) }).asString(); - ETH_TEST_MESSAGE("Created account " + addr); - return addr; -} - -string RPCSession::test_getBlockStatus(std::string const& _blockHash) -{ - return rpcCall("test_getBlockStatus", {quote(_blockHash)}).asString(); -} - -string RPCSession::test_getLogHash(std::string const& _txHash) -{ - return rpcCall("test_getLogHash", { quote(_txHash) }).asString(); -} - -string RPCSession::test_importRawBlock(std::string const& _blockRLP) -{ - DataObject res = rpcCall("test_importRawBlock", {quote(_blockRLP)}, true); - if (res.type() != DataType::Null) - return res.asString(); - return string(); -} - -void RPCSession::test_setChainParams(string const& _config) -{ - ETH_FAIL_REQUIRE_MESSAGE(rpcCall("test_setChainParams", { _config }) == true, "remote test_setChainParams = false"); -} - -void RPCSession::test_rewindToBlock(size_t _blockNr) -{ - ETH_FAIL_REQUIRE_MESSAGE(rpcCall("test_rewindToBlock", { to_string(_blockNr) }) == true, "remote test_rewintToBlock = false"); -} - -string RPCSession::test_mineBlocks(int _number, bool _canFail) -{ - DataObject blockNumber = rpcCall("eth_blockNumber"); - u256 startBlock = (blockNumber.type() == DataType::String) ? u256(blockNumber.asString()) : - blockNumber.asInt(); - - if (!_canFail) - ETH_ERROR_REQUIRE_MESSAGE(rpcCall("test_mineBlocks", { to_string(_number) }, true) == true, c_errorMiningString); - else - return c_errorMiningString; - - // 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 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(endTime - startTime).count(); - if (timeSpent > m_maxMiningTime) - break; // could be that some blocks are invalid. - // ETH_FAIL_MESSAGE("Error in test_mineBlocks: block mining timeout! " + - // test::TestOutputHelper::get().testName()); - - blockNumber = rpcCall("eth_blockNumber"); - u256 number = (blockNumber.type() == DataType::String) ? u256(blockNumber.asString()) : - blockNumber.asInt(); - if (number >= startBlock + _number) - return toString(number); - else - sleepTime *= 2; - - if (tries > 1) - { - m_successfulMineRuns = 0; - m_sleepTime += 2; - } - else if (tries == 1) - { - m_successfulMineRuns++; - if (m_successfulMineRuns > 5) - { - m_successfulMineRuns = 0; - if (m_sleepTime > 2) - m_sleepTime--; - } - } - } - - // Better keep it int everywhere in codebase. !!! - return toString(startBlock); -} - -void RPCSession::test_modifyTimestamp(unsigned long long _timestamp) -{ - ETH_FAIL_REQUIRE_MESSAGE(rpcCall("test_modifyTimestamp", { to_string(_timestamp) }) == true, "test_modifyTimestamp was not successfull"); -} - -std::string RPCSession::sendRawRequest(string const& _request) -{ - JsonObjectValidator validator; - return m_socket.sendRequest(_request, validator); -} - -DataObject 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; - - ETH_TEST_MESSAGE("Request: " + request); - JsonObjectValidator validator; // read response while counting `{}` - string reply = m_socket.sendRequest(request, validator); - ETH_TEST_MESSAGE("Reply: " + reply); - - DataObject result = ConvertJsoncppStringToData(reply, string(), true); - if (result.count("error")) - result["result"] = ""; - requireJsonFields(result, "rpcCall_response ('" + request.substr(0, 70) + "')", - {{"jsonrpc", {{DataType::String}, jsonField::Required}}, - {"id", {{DataType::Integer}, jsonField::Required}}, - {"result", {{DataType::String, DataType::Integer, DataType::Bool, DataType::Object, - DataType::Array}, - jsonField::Required}}, - {"error", {{DataType::String, DataType::Object}, jsonField::Optional}}}); - - if (result.count("error")) - { - test::TestOutputHelper const& helper = test::TestOutputHelper::get(); - m_lastRPCError["message"] = "Error on JSON-RPC call (" + helper.testInfo().getMessage() + - "):\nRequest: '" + request + "'" + "\nResult: '" + - result["error"]["message"].asString() + "'\n"; - m_lastRPCError["error"] = result["error"]["message"].asString(); - if (_canFail) - return DataObject(DataType::Null); - ETH_FAIL_MESSAGE(m_lastRPCError.atKey("message").asString()); - } - m_lastRPCError.clear(); //null the error as last RPC call was success. - return result["result"]; -} - -string const& RPCSession::accountCreate() -{ - m_accounts.push_back(personal_newAccount("")); - personal_unlockAccount(m_accounts.back(), "", 100000); - return m_accounts.back(); -} - -string const& RPCSession::accountCreateIfNotExists(size_t _id) -{ - while ((_id + 1) > m_accounts.size()) - accountCreate(); - return m_accounts[_id]; -} - -RPCSession::RPCSession(Socket::SocketType _type, const string& _path) : m_socket(_type, _path) {} diff --git a/retesteth/RPCSession.h b/retesteth/RPCSession.h deleted file mode 100644 index 4e2e891b8..000000000 --- a/retesteth/RPCSession.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -class RPCSession: public boost::noncopyable -{ -public: - enum SessionStatus - { - Working, // test execution in progress - Available, // test execution has finished - HasFinished, // has just finished execution - NotExist // socket yet not initialized - }; - - static RPCSession& instance(std::string const& _threadID); - static void sessionStart(std::string const &_threadID); - static void sessionEnd(std::string const& _threadID, SessionStatus _status); - static SessionStatus sessionStatus(std::string const& _threadID); - static void clear(); - - std::string web3_clientVersion(); - std::string eth_sendTransaction(std::string const& _transaction); - std::string eth_sendRawTransaction(std::string const& _rlp); - - std::string eth_blockNumber(); - test::scheme_transactionReceipt eth_getTransactionReceipt(std::string const& _transactionHash); - int eth_getTransactionCount(std::string const& _address, std::string const& _blockNumber); - std::string eth_getCode(std::string const& _address, std::string const& _blockNumber); - test::scheme_block eth_getBlockByNumber(BlockNumber const& _blockNumber, bool _fullObjects); - test::scheme_block eth_getBlockByHash(string const& _hash, bool _fullObjects); - std::string eth_getBalance(std::string const& _address, std::string const& _blockNumber); - std::string eth_getStorageRoot(std::string const& _address, std::string const& _blockNumber); - std::string eth_getStorageAt(std::string const& _address, std::string const& _position, std::string const& _blockNumber); - - std::string personal_newAccount(std::string const& _password); - void personal_unlockAccount(std::string const& _address, std::string const& _password, int _duration); - scheme_debugAccountRange debug_accountRange(std::string const& _blockHashOrNumber, int _txIndex, - std::string const& _address, int _maxResults); - DataObject debug_storageRangeAt(std::string const& _blockHashOrNumber, int _txIndex, - std::string const& _address, std::string const& _begin, int _maxResults); - scheme_debugTraceTransaction debug_traceTransaction(std::string const& _trHash); - - std::string test_getBlockStatus(std::string const& _blockHash); - std::string test_getLogHash(std::string const& _txHash); - void test_setChainParams(std::string const& _config); - void test_rewindToBlock(size_t _blockNr); - void test_modifyTimestamp(unsigned long long _timestamp); - string test_mineBlocks(int _number, bool _canFail = false); - string test_importRawBlock(std::string const& _blockRLP); - - std::string sendRawRequest(std::string const& _request); - DataObject rpcCall(std::string const& _methodName, - std::vector const& _args = std::vector(), bool _canFail = false); - - std::string const& account(size_t _id) const { return m_accounts.at(_id); } - std::string const& accountCreate(); - std::string const& accountCreateIfNotExists(size_t _id); - - /// Returns empty string if last RPC call had no errors, error string if there was an error - DataObject const& getLastRPCError() const { return m_lastRPCError; } - string const& getLastRPCErrorMessage() const - { - if (m_lastRPCError.type() != DataType::Null) - return m_lastRPCError.atKey("error").asString(); - static const string empty; - return empty; - } - Socket::SocketType getSocketType() const { return m_socket.type(); } - std::string const& getSocketPath() const { return m_socket.path(); } - - static string const c_errorMiningString; - -private: - explicit RPCSession(Socket::SocketType _type, std::string const& _path); - static void runNewInstanceOfAClient(std::string const& _threadID, ClientConfig const& _config); - - inline std::string quote(std::string const& _arg) { return "\"" + _arg + "\""; } - /// Parse std::string replacing keywords to values - void parseString(std::string& _string, std::map const& _varMap); - - Socket m_socket; - size_t m_rpcSequence = 1; - unsigned m_maxMiningTime = 250000; // should be instant with --test (1 sec) - unsigned m_sleepTime = 10; // 10 milliseconds - unsigned m_successfulMineRuns = 0; - DataObject m_lastRPCError; // last RPC error info - std::vector m_accounts; -}; - - diff --git a/retesteth/Socket.cpp b/retesteth/Socket.cpp deleted file mode 100644 index a5b6cb624..000000000 --- a/retesteth/Socket.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include "Socket.h" -#include -#include -#include -#include -#include -#include - - -using namespace std; - -Socket::Socket(SocketType _type, string const& _path): m_path(_path), m_socketType(_type) -{ -#if defined(_WIN32) - 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) - ETH_FAIL_MESSAGE("Error creating IPC socket object!"); - -#else - if (_type == SocketType::IPC) - { - if (_path.length() >= sizeof(sockaddr_un::sun_path)) - ETH_FAIL_MESSAGE("Error opening IPC: socket path is too long!"); - - struct sockaddr_un saun; - memset(&saun, 0, sizeof(sockaddr_un)); - saun.sun_family = AF_UNIX; - strcpy(saun.sun_path, _path.c_str()); - - // 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__) - - if ((m_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - ETH_FAIL_MESSAGE("Error creating IPC socket object"); - - if (connect(m_socket, reinterpret_cast(&saun), sizeof(struct sockaddr_un)) < 0) - { - close(m_socket); - ETH_FAIL_MESSAGE("Error connecting to IPC socket: " + _path); - } - } else if (_type == SocketType::TCP) - { - - struct sockaddr_in sin; - sin.sin_family = AF_INET; - - size_t pos = _path.find_last_of(':'); - string address = _path.substr(0, pos); - int port = atoi(_path.substr(pos + 1).c_str()); - - sin.sin_addr.s_addr = inet_addr(address.c_str()); - sin.sin_port = htons(port); - - if ((m_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) - ETH_FAIL_MESSAGE("Error creating TCP socket object"); - - if (connect(m_socket, reinterpret_cast(&sin), sizeof(struct sockaddr_in)) < 0) - { - close(m_socket); - ETH_FAIL_MESSAGE("Error connecting to TCP socket: " + _path); - } - } -#endif -} - -namespace -{ - std::size_t writecallback( - const char* in, - std::size_t size, - std::size_t num, - std::string* out) - { - const std::size_t totalBytes(size * num); - out->append(in, totalBytes); - return totalBytes; - } - - #if defined(_WIN32) - string sendRequestWin(string const& _req) - { - // Write to the pipe. - DWORD cbWritten; - BOOL fSuccess = WriteFile( - m_socket, // pipe handle - _req.c_str(), // message - _req.size(), // message length - &cbWritten, // bytes written - NULL); // not overlapped - - if (!fSuccess || (_req.size() != cbWritten)) - ETH_FAIL_MESSAGE("WriteFile to pipe failed"); - - // Read from the pipe. - DWORD cbRead; - fSuccess = ReadFile( - 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) - ETH_FAIL_MESSAGE("ReadFile from pipe failed"); - - return string(m_readBuf, m_readBuf + cbRead); - } - #endif - - struct WriteThis - { - const char* readptr; - size_t sizeleft; - }; - - static size_t readcallback(void* dest, size_t size, size_t nmemb, void* userp) - { - struct WriteThis* wt = (struct WriteThis*)userp; - size_t buffer_size = size * nmemb; - - if (wt->sizeleft) - { - /* copy as much as possible from the source to the destination */ - size_t copy_this_much = wt->sizeleft; - if (copy_this_much > buffer_size) - copy_this_much = buffer_size; - memcpy(dest, wt->readptr, copy_this_much); - - wt->readptr += copy_this_much; - wt->sizeleft -= copy_this_much; - - return copy_this_much; /* we copied this many bytes */ - } - - return 0; /* no more data left to deliver */ - } - - string sendRequestTCP(string const& _req, string const& _address) - { - CURL *curl; - CURLcode res; - curl = curl_easy_init(); - - string url = _address; - if (_address.find("http") == string::npos) - url = "http://" + _address; - if (curl) - { - std::unique_ptr httpData(new std::string()); - struct WriteThis wt; - wt.readptr = _req.c_str(); - wt.sizeleft = _req.size(); - - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 3000000); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get()); - curl_easy_setopt(curl, CURLOPT_READFUNCTION, readcallback); - curl_easy_setopt(curl, CURLOPT_READDATA, &wt); - curl_easy_setopt(curl, CURLOPT_POST, 1L); - - struct curl_slist *header = NULL; - header = curl_slist_append(header, "Accept: application/json, text/plain"); - header = curl_slist_append(header, "Content-Type: application/json"); - header = curl_slist_append(header, "Transfer-Encoding: chunked"); - - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 500L); - res = curl_easy_perform(curl); - if(res != CURLE_OK) - ETH_FAIL_MESSAGE("curl_easy_perform() failed " + string(curl_easy_strerror(res))); - curl_slist_free_all(header); - curl_easy_cleanup(curl); - return *httpData.get(); - } - else - ETH_FAIL_MESSAGE("Error initializing Curl"); - return string(); - } -} - -string Socket::sendRequestIPC(string const& _req, SocketResponseValidator& _validator) -{ - char buf; - recv(m_socket, &buf, 1, MSG_PEEK | MSG_DONTWAIT); - if (errno == ENOTCONN) - ETH_FAIL_MESSAGE("Socket connection error! "); - - if (send(m_socket, _req.c_str(), _req.length(), 0) != (ssize_t)_req.length()) - ETH_FAIL_MESSAGE("Writing on socket failed."); - - auto start = chrono::steady_clock::now(); - ssize_t ret = 0; - string reply; - - while ( - _validator.completeResponse() == false && - chrono::duration_cast(chrono::steady_clock::now() - start).count() < - m_readTimeOutMS) - { - ret = recv(m_socket, m_readBuf, sizeof(m_readBuf), 0); - - // Also consider closed socket an error. - if (ret < 0) - ETH_FAIL_MESSAGE("Reading on socket failed!"); - - _validator.acceptResponse(m_readBuf); - memset(&m_readBuf[0], 0, sizeof(m_readBuf)); - } - - reply = _validator.getResponse(); - - if (ret == 0) - ETH_FAIL_MESSAGE("Timeout reading on socket."); - - return reply; -} - -string Socket::sendRequest(string const& _req, SocketResponseValidator& _val) -{ - #if defined(_WIN32) - return sendRequestWin(_req); - #endif - - if (m_socketType == Socket::TCP) - return sendRequestTCP(_req, m_path); - - if (m_socketType == Socket::IPC) - return sendRequestIPC(_req, _val); - - return string(); -} - -JsonObjectValidator::JsonObjectValidator() -{ - m_status = false; - m_bracersCount = 0; -} -void JsonObjectValidator::acceptResponse(std::string const& _response) -{ - m_response += _response; - for (size_t i = 0; i < _response.size(); i++) - { - if (_response[i] == '{') - m_bracersCount++; - else if (_response[i] == '}') - m_bracersCount--; - } - if (m_bracersCount == 0) - m_status = true; -} - -bool JsonObjectValidator::completeResponse() const -{ - return m_status; -} - -std::string JsonObjectValidator::getResponse() const -{ - return m_response; -} diff --git a/retesteth/TestSuite.cpp b/retesteth/TestSuite.cpp index 068b028a1..99fc8ed72 100644 --- a/retesteth/TestSuite.cpp +++ b/retesteth/TestSuite.cpp @@ -25,10 +25,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -107,28 +107,28 @@ void removeComments(dataobject::DataObject& _obj) void addClientInfo( dataobject::DataObject& _v, fs::path const& _testSource, h256 const& _testSourceHash) { - RPCSession &session = RPCSession::instance(TestOutputHelper::getThreadID()); - for (auto& o : _v.getSubObjectsUnsafe()) - { - string comment; - dataobject::DataObject clientinfo; - if (o.count("_info")) - { - dataobject::DataObject const& existingInfo = o.atKey("_info"); - if (existingInfo.count("comment")) - comment = existingInfo.atKey("comment").asString(); - } - - clientinfo.setKey("_info"); - clientinfo["comment"] = comment; - clientinfo["filling-rpc-server"] = session.web3_clientVersion(); - clientinfo["filling-tool-version"] = test::prepareVersionString(); - clientinfo["lllcversion"] = test::prepareLLLCVersionString(); - clientinfo["source"] = _testSource.string(); - clientinfo["sourceHash"] = toString(_testSourceHash); - - o["_info"].replace(clientinfo); - o.setKeyPos("_info", 0); + SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); + for (auto& o : _v.getSubObjectsUnsafe()) + { + string comment; + dataobject::DataObject clientinfo; + if (o.count("_info")) + { + dataobject::DataObject const& existingInfo = o.atKey("_info"); + if (existingInfo.count("comment")) + comment = existingInfo.atKey("comment").asString(); + } + + clientinfo.setKey("_info"); + clientinfo["comment"] = comment; + clientinfo["filling-rpc-server"] = session.web3_clientVersion(); + clientinfo["filling-tool-version"] = test::prepareVersionString(); + clientinfo["lllcversion"] = test::prepareLLLCVersionString(); + clientinfo["source"] = _testSource.string(); + clientinfo["sourceHash"] = toString(_testSourceHash); + + o["_info"].replace(clientinfo); + o.setKeyPos("_info", 0); } } diff --git a/retesteth/configs/ClientConfig.h b/retesteth/configs/ClientConfig.h index 39cd2b855..89a74d0d7 100644 --- a/retesteth/configs/ClientConfig.h +++ b/retesteth/configs/ClientConfig.h @@ -1,7 +1,7 @@ #pragma once -#include #include #include +#include #include #include #include @@ -87,6 +87,14 @@ class ClientConfig : public object ETH_FAIL_REQUIRE_MESSAGE(fs::exists(getAddress()), std::string("Client IPC socket file not found: ") + getAddress()); } + else if (socketTypeStr == "tranition-tool") + { + m_socketType = Socket::SocketType::TransitionTool; + ETH_FAIL_REQUIRE_MESSAGE( + fs::exists(getAddress()), std::string("Client `socketAddress` should contain a " + "path to transition tool executable: ") + + getAddress()); + } else ETH_FAIL_MESSAGE( "Incorrect client socket type: " + socketTypeStr + " in client named '" + diff --git a/retesteth/main.cpp b/retesteth/main.cpp index 6b79fb26b..9548a56e4 100644 --- a/retesteth/main.cpp +++ b/retesteth/main.cpp @@ -3,9 +3,9 @@ #include #include #include -#include #include #include +#include #include #include #include diff --git a/retesteth/session/RPCImplementation.cpp b/retesteth/session/RPCImplementation.cpp new file mode 100644 index 000000000..675ddd6f2 --- /dev/null +++ b/retesteth/session/RPCImplementation.cpp @@ -0,0 +1,288 @@ + +#include +#include +#include + +#include +#include +#include + +std::string RPCImpl::web3_clientVersion() +{ + return rpcCall("web3_clientVersion", {}).asString(); +} + +// ETH Methods +std::string RPCImpl::eth_sendRawTransaction(std::string const& _rlp) +{ + DataObject result = rpcCall("eth_sendRawTransaction", {quote(_rlp)}, true); + + DataObject const& lastError = getLastRPCError(); + if (lastError.type() != DataType::Null) + ETH_ERROR_MESSAGE(lastError.atKey("message").asString()); + if (!isHash(result.asString())) + ETH_ERROR_MESSAGE( + "eth_sendRawTransaction return invalid hash: '" + result.asString() + "'"); + if (result.type() == DataType::Null) // if the method failed + return ""; + return result.asString(); +} + +std::string RPCImpl::eth_sendTransaction(std::string const& _transaction) +{ + return rpcCall("eth_sendTransaction", {_transaction}).asString(); +} + +int RPCImpl::eth_getTransactionCount(std::string const& _address, std::string const& _blockNumber) +{ + DataObject res = rpcCall("eth_getTransactionCount", {quote(_address), quote(_blockNumber)}); + return (res.type() == DataType::String) ? test::hexOrDecStringToInt(res.asString()) : + res.asInt(); +} + +test::scheme_transactionReceipt RPCImpl::eth_getTransactionReceipt( + std::string const& _transactionHash) +{ + return test::scheme_transactionReceipt( + rpcCall("eth_getTransactionReceipt", {quote(_transactionHash)})); +} + +std::string RPCImpl::eth_blockNumber() +{ + DataObject res = rpcCall("eth_blockNumber", {}); + return res.type() == DataType::String ? res.asString() : toString(res.asInt()); +} + +test::scheme_block RPCImpl::eth_getBlockByHash(string const& _hash, bool _fullObjects) +{ + return test::scheme_block( + rpcCall("eth_getBlockByHash", {quote(_hash), _fullObjects ? "true" : "false"})); +} + +test::scheme_block RPCImpl::eth_getBlockByNumber(BlockNumber const& _blockNumber, bool _fullObjects) +{ + return test::scheme_block(rpcCall("eth_getBlockByNumber", + {quote(_blockNumber.getBlockNumberAsString()), _fullObjects ? "true" : "false"})); +} + +std::string RPCImpl::eth_getCode(std::string const& _address, std::string const& _blockNumber) +{ + return rpcCall("eth_getCode", {quote(_address), quote(_blockNumber)}).asString(); +} + +std::string RPCImpl::eth_getBalance(std::string const& _address, std::string const& _blockNumber) +{ + string address = (_address.length() == 20) ? "0x" + _address : _address; + return rpcCall("eth_getBalance", {quote(address), quote(_blockNumber)}).asString(); +} + + +// Debug +scheme_debugAccountRange RPCImpl::debug_accountRange(std::string const& _blockHashOrNumber, + int _txIndex, std::string const& _address, int _maxResults) +{ + return scheme_debugAccountRange(rpcCall( + "debug_accountRange", {quote(toString(u256(dev::fromHex(_blockHashOrNumber)))), + to_string(_txIndex), quote(_address), to_string(_maxResults)})); +} + + +DataObject RPCImpl::debug_storageRangeAt(std::string const& _blockHashOrNumber, int _txIndex, + std::string const& _address, std::string const& _begin, int _maxResults) +{ + return rpcCall("debug_storageRangeAt", + {quote(toString(u256(dev::fromHex(_blockHashOrNumber)))), to_string(_txIndex), + quote(_address), quote(_begin), to_string(_maxResults)}); +} + +scheme_debugTraceTransaction RPCImpl::debug_traceTransaction(std::string const& _trHash) +{ + return scheme_debugTraceTransaction(rpcCall("debug_traceTransaction", {quote(_trHash), "{}"})); +} + +// Test +void RPCImpl::test_setChainParams(std::string const& _config) +{ + ETH_FAIL_REQUIRE_MESSAGE( + rpcCall("test_setChainParams", {_config}) == true, "remote test_setChainParams = false"); +} + +void RPCImpl::test_rewindToBlock(size_t _blockNr) +{ + ETH_FAIL_REQUIRE_MESSAGE(rpcCall("test_rewindToBlock", {to_string(_blockNr)}) == true, + "remote test_rewintToBlock = false"); +} + +void RPCImpl::test_modifyTimestamp(unsigned long long _timestamp) +{ + ETH_FAIL_REQUIRE_MESSAGE(rpcCall("test_modifyTimestamp", {to_string(_timestamp)}) == true, + "test_modifyTimestamp was not successfull"); +} + +string RPCImpl::test_mineBlocks(int _number, bool _canFail) +{ + DataObject blockNumber = rpcCall("eth_blockNumber"); + u256 startBlock = (blockNumber.type() == DataType::String) ? u256(blockNumber.asString()) : + blockNumber.asInt(); + + static const string c_error = "remote test_mineBLocks = false"; + if (!_canFail) + ETH_ERROR_REQUIRE_MESSAGE( + rpcCall("test_mineBlocks", {to_string(_number)}, true) == true, c_error); + else + return c_error; + + // 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 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(endTime - startTime).count(); + if (timeSpent > m_maxMiningTime) + break; // could be that some blocks are invalid. + // ETH_FAIL_MESSAGE("Error in test_mineBlocks: block mining timeout! " + + // test::TestOutputHelper::get().testName()); + + blockNumber = rpcCall("eth_blockNumber"); + u256 number = (blockNumber.type() == DataType::String) ? u256(blockNumber.asString()) : + blockNumber.asInt(); + if (number >= startBlock + _number) + return toString(number); + else + sleepTime *= 2; + + if (tries > 1) + { + m_successfulMineRuns = 0; + m_sleepTime += 2; + } + else if (tries == 1) + { + m_successfulMineRuns++; + if (m_successfulMineRuns > 5) + { + m_successfulMineRuns = 0; + if (m_sleepTime > 2) + m_sleepTime--; + } + } + } + + // Better keep it int everywhere in codebase. !!! + return toString(startBlock); +} + +string RPCImpl::test_importRawBlock(std::string const& _blockRLP) +{ + DataObject res = rpcCall("test_importRawBlock", {quote(_blockRLP)}, true); + if (res.type() != DataType::Null) + return res.asString(); + return string(); +} + +// ?? Deprecated ?? +std::string RPCImpl::test_getBlockStatus(std::string const& _blockHash) +{ + return rpcCall("test_getBlockStatus", {quote(_blockHash)}).asString(); +} + +std::string RPCImpl::test_getLogHash(std::string const& _txHash) +{ + return rpcCall("test_getLogHash", {quote(_txHash)}).asString(); +} + +// ?? Deprecated ?? +std::string RPCImpl::eth_getStorageRoot( + std::string const& _address, std::string const& _blockNumber) +{ + string address = (_address.length() == 20) ? "0x" + _address : _address; + return rpcCall("eth_getStorageRoot", {quote(address), quote(_blockNumber)}).asString(); +} + +std::string RPCImpl::eth_getStorageAt( + std::string const& _address, std::string const& _position, std::string const& _blockNumber) +{ + return rpcCall("eth_getStorageAt", {quote(_address), quote(_position), quote(_blockNumber)}) + .asString(); +} + +std::string RPCImpl::personal_newAccount(std::string const& _password) +{ + string addr = rpcCall("personal_newAccount", {quote(_password)}).asString(); + ETH_TEST_MESSAGE("Created account " + addr); + return addr; +} + +void RPCImpl::personal_unlockAccount( + std::string const& _address, std::string const& _password, int _duration) +{ + rpcCall("personal_unlockAccount", {quote(_address), quote(_password), to_string(_duration)}); +} + +// Internal +std::string RPCImpl::sendRawRequest(std::string const& _request) +{ + JsonObjectValidator validator; + return m_socket.sendRequest(_request, validator); +} + +DataObject RPCImpl::rpcCall( + std::string const& _methodName, std::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++) + "}"; + + ETH_TEST_MESSAGE("Request: " + request); + JsonObjectValidator validator; // read response while counting `{}` + string reply = m_socket.sendRequest(request, validator); + ETH_TEST_MESSAGE("Reply: " + reply); + + DataObject result = ConvertJsoncppStringToData(reply, string(), true); + if (result.count("error")) + result["result"] = ""; + requireJsonFields(result, "rpcCall_response ('" + request.substr(0, 70) + "')", + {{"jsonrpc", {{DataType::String}, jsonField::Required}}, + {"id", {{DataType::Integer}, jsonField::Required}}, + {"result", {{DataType::String, DataType::Integer, DataType::Bool, DataType::Object, + DataType::Array}, + jsonField::Required}}, + {"error", {{DataType::String, DataType::Object}, jsonField::Optional}}}); + + if (result.count("error")) + { + test::TestOutputHelper const& helper = test::TestOutputHelper::get(); + m_lastInterfaceError["message"] = + "Error on JSON-RPC call (" + helper.testInfo().getMessage() + "):\nRequest: '" + + request + "'" + "\nResult: '" + result["error"]["message"].asString() + "'\n"; + m_lastInterfaceError["error"] = result["error"]["message"].asString(); + if (_canFail) + return DataObject(DataType::Null); + ETH_FAIL_MESSAGE(m_lastInterfaceError.atKey("message").asString()); + } + m_lastInterfaceError.clear(); // null the error as last RPC call was success. + return result["result"]; +} + +Socket::SocketType RPCImpl::getSocketType() const +{ + return m_socket.type(); +} + +std::string const& RPCImpl::getSocketPath() const +{ + return m_socket.path(); +} diff --git a/retesteth/session/RPCImplementation.h b/retesteth/session/RPCImplementation.h new file mode 100644 index 000000000..eab0dc089 --- /dev/null +++ b/retesteth/session/RPCImplementation.h @@ -0,0 +1,73 @@ +#pragma once +#include +#include +#include +#include + +class RPCImpl : public SessionInterface +{ +public: + RPCImpl(Socket::SocketType _type, const string& _path) : m_socket(_type, _path) {} + +public: + std::string web3_clientVersion() override; + + // ETH Methods + std::string eth_sendRawTransaction(std::string const& _rlp) override; + std::string eth_sendTransaction(std::string const& _transaction) override; + int eth_getTransactionCount( + std::string const& _address, std::string const& _blockNumber) override; + test::scheme_transactionReceipt eth_getTransactionReceipt( + std::string const& _transactionHash) override; + + std::string eth_blockNumber() override; + test::scheme_block eth_getBlockByHash(string const& _hash, bool _fullObjects) override; + test::scheme_block eth_getBlockByNumber( + BlockNumber const& _blockNumber, bool _fullObjects) override; + + std::string eth_getCode(std::string const& _address, std::string const& _blockNumber) override; + std::string eth_getBalance( + std::string const& _address, std::string const& _blockNumber) override; + + // Debug + scheme_debugAccountRange debug_accountRange(std::string const& _blockHashOrNumber, int _txIndex, + std::string const& _address, int _maxResults) override; + DataObject debug_storageRangeAt(std::string const& _blockHashOrNumber, int _txIndex, + std::string const& _address, std::string const& _begin, int _maxResults) override; + scheme_debugTraceTransaction debug_traceTransaction(std::string const& _trHash) override; + + // Test + void test_setChainParams(std::string const& _config) override; + void test_rewindToBlock(size_t _blockNr) override; + void test_modifyTimestamp(unsigned long long _timestamp) override; + string test_mineBlocks(int _number, bool _canFail = false) override; + string test_importRawBlock(std::string const& _blockRLP) override; + + // ?? Deprecated ?? + std::string test_getBlockStatus(std::string const& _blockHash) override; + std::string test_getLogHash(std::string const& _txHash) override; + + // ?? Deprecated ?? + std::string eth_getStorageRoot( + std::string const& _address, std::string const& _blockNumber) override; + std::string eth_getStorageAt(std::string const& _address, std::string const& _position, + std::string const& _blockNumber) override; + std::string personal_newAccount(std::string const& _password) override; + void personal_unlockAccount( + std::string const& _address, std::string const& _password, int _duration) override; + + // Internal + std::string sendRawRequest(std::string const& _request) override; + DataObject rpcCall(std::string const& _methodName, + std::vector const& _args = std::vector(), + bool _canFail = false) override; + Socket::SocketType getSocketType() const; + std::string const& getSocketPath() const; + +private: + Socket m_socket; + size_t m_rpcSequence = 1; + unsigned m_sleepTime = 10; // 10 milliseconds + unsigned m_successfulMineRuns = 0; + unsigned m_maxMiningTime = 250000; // should be instant with --test (1 sec) +}; diff --git a/retesteth/session/RPCSession.cpp b/retesteth/session/RPCSession.cpp new file mode 100644 index 000000000..33be5d6ce --- /dev/null +++ b/retesteth/session/RPCSession.cpp @@ -0,0 +1,248 @@ +/* + This file is part of solidity. + + solidity 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. + + solidity 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 solidity. If not, see . + + The Implementation originally from + https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx +*/ +/// @file RPCSession.cpp +/// Low-level IPC communication between the test framework and the Ethereum node. + +#include "RPCSession.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace dev; + +struct sessionInfo +{ + sessionInfo(FILE* _pipe, RPCSession* _session, std::string const& _tmpDir, int _pid, + test::ClientConfigID const& _configId) + { + session.reset(_session); + filePipe.reset(_pipe); + tmpDir = _tmpDir; + pipePid = _pid; + isUsed = RPCSession::NotExist; + configId = _configId; + } + std::unique_ptr session; + std::unique_ptr filePipe; + int pipePid; + RPCSession::SessionStatus isUsed; + std::string tmpDir; + test::ClientConfigID configId; +}; + +void closeSession(const string& _threadID); + +std::mutex g_socketMapMutex; +static std::map socketMap; // ! make inside a class static +void RPCSession::runNewInstanceOfAClient(string const& _threadID, ClientConfig const& _config) +{ + if (_config.getSocketType() == Socket::IPC) + { + fs::path tmpDir = test::createUniqueTmpDirectory(); + string ipcPath = tmpDir.string() + "/geth.ipc"; + + string command = "bash"; + std::vector args; + args.push_back(_config.getShellPath().c_str()); + args.push_back(tmpDir.string()); + args.push_back(ipcPath); + + int pid = 0; + test::popenOutput mode = (Options::get().enableClientsOutput) ? + test::popenOutput::EnableALL : + test::popenOutput::DisableAll; + FILE* fp = test::popen2(command, args, "r", pid, mode); + if (!fp) + { + ETH_ERROR_MESSAGE("Failed to start the client: '" + command + "'"); + std::raise(SIGABRT); + } + else + { + int maxSeconds = 25; + while (!boost::filesystem::exists(ipcPath) && maxSeconds-- > 0) + std::this_thread::sleep_for(std::chrono::seconds(1)); + ETH_FAIL_REQUIRE_MESSAGE(maxSeconds > 0, "Client took too long to start ipc!"); + // Client has opened ipc socket. wait for it to initialize + std::this_thread::sleep_for(std::chrono::seconds(4)); + } + sessionInfo info(fp, new RPCSession(new RPCImpl(Socket::SocketType::IPC, ipcPath)), + tmpDir.string(), pid, _config.getId()); + { + std::lock_guard lock(g_socketMapMutex); // function must be called from + // lock + socketMap.insert(std::pair(_threadID, std::move(info))); + } + } + else if (_config.getSocketType() == Socket::TCP) + { + std::lock_guard lock(g_socketMapMutex); // function must be called from lock + + DataObject const& ports = (Options::get().nodesoverride.getSubObjects().size() > 0 ? + Options::get().nodesoverride : + _config.getAddressObject()); + + // Create sessionInfo for a tcp address that is still not present in socketMap + for (auto const& addr : ports.getSubObjects()) + { + bool unused = true; + for (auto const& socket : socketMap) + { + sessionInfo const& sInfo = socket.second; + if (sInfo.session.get()->getImplementation().getSocketPath() == addr.asString()) + { + unused = false; + break; + } + } + if (unused) + { + sessionInfo info(NULL, + new RPCSession(new RPCImpl(Socket::SocketType::TCP, addr.asString())), "", 0, + _config.getId()); + socketMap.insert(std::pair(_threadID, std::move(info))); + return; + } + } + } + else if (_config.getSocketType() == Socket::IPCDebug) + { + // connect to already opend .ipc socket + fs::path tmpDir = test::createUniqueTmpDirectory(); + string ipcPath = _config.getAddress(); + int pid = 0; + FILE* fp = NULL; + sessionInfo info(fp, new RPCSession(new RPCImpl(Socket::SocketType::IPC, ipcPath)), + tmpDir.string(), pid, _config.getId()); + { + std::lock_guard lock(g_socketMapMutex); // function must be called from + // lock + socketMap.insert(std::pair(_threadID, std::move(info))); + } + } + else + ETH_FAIL_MESSAGE("Unknown Socket Type in runNewInstanceOfAClient"); +} + +SessionInterface& RPCSession::instance(const string& _threadID) +{ + bool needToCreateNew = false; + { + std::lock_guard lock(g_socketMapMutex); + test::ClientConfigID currentConfigId = + Options::getDynamicOptions().getCurrentConfig().getId(); + if (socketMap.count(_threadID) && socketMap.at(_threadID).configId != currentConfigId) + { + // For this thread a session is opened but it is opened not for current tested client + ETH_FAIL_MESSAGE("A session opened for another client id!"); + } + + if (!socketMap.count(_threadID)) + { + // look for free clients that already instantiated + for (auto& socket : socketMap) + { + if (socket.second.isUsed == SessionStatus::Available) + if (socket.second.configId == currentConfigId) + { + socket.second.isUsed = SessionStatus::Working; + socketMap.insert( + std::pair(_threadID, std::move(socket.second))); + socketMap.erase(socketMap.find(socket.first)); // remove previous threadID + // assigment to this socket + return socketMap.at(_threadID).session.get()->getImplementation(); + } + } + needToCreateNew = true; + } + } + if (needToCreateNew) + runNewInstanceOfAClient(_threadID, Options::getDynamicOptions().getCurrentConfig()); + + std::lock_guard lock(g_socketMapMutex); + ETH_FAIL_REQUIRE_MESSAGE(socketMap.size() <= Options::get().threadCount, + "Something went wrong. Retesteth connect to more instances than needed!"); + ETH_FAIL_REQUIRE_MESSAGE(socketMap.size() != 0, + "Something went wrong. Retesteth failed to create socket connection!"); + return socketMap.at(_threadID).session.get()->getImplementation(); +} + +void RPCSession::sessionStart(std::string const& _threadID) +{ + RPCSession::instance(_threadID); // initialize the client if not exist + std::lock_guard lock(g_socketMapMutex); + if (socketMap.count(_threadID)) + socketMap.at(_threadID).isUsed = SessionStatus::Working; +} + +void RPCSession::sessionEnd(std::string const& _threadID, SessionStatus _status) +{ + std::lock_guard lock(g_socketMapMutex); + assert(socketMap.count(_threadID)); + if (socketMap.count(_threadID)) + socketMap.at(_threadID).isUsed = _status; +} + +RPCSession::SessionStatus RPCSession::sessionStatus(std::string const& _threadID) +{ + std::lock_guard lock(g_socketMapMutex); + if (socketMap.count(_threadID)) + return socketMap.at(_threadID).isUsed; + return RPCSession::NotExist; +} + +void closeSession(const string& _threadID) +{ + ETH_FAIL_REQUIRE_MESSAGE(socketMap.count(_threadID), "Socket map is empty in closeSession!"); + sessionInfo& element = socketMap.at(_threadID); + if (element.session.get()->getImplementation().getSocketType() == Socket::SocketType::IPC) + { + test::pclose2(element.filePipe.get(), element.pipePid); + std::this_thread::sleep_for(std::chrono::seconds(4)); + boost::filesystem::remove_all(boost::filesystem::path(element.tmpDir)); + element.filePipe.release(); + element.session.release(); + } +} + +void RPCSession::clear() +{ + std::lock_guard lock(g_socketMapMutex); + std::vector closingThreads; + for (auto& element : socketMap) + closingThreads.push_back(thread(closeSession, element.first)); + for (auto& th : closingThreads) + th.join(); + + socketMap.clear(); + closingThreads.clear(); +} + +RPCSession::RPCSession(SessionInterface* _impl) : m_implementation(_impl) {} diff --git a/retesteth/session/RPCSession.h b/retesteth/session/RPCSession.h new file mode 100644 index 000000000..8354b2d89 --- /dev/null +++ b/retesteth/session/RPCSession.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +// Session connections to an instance of a client +class RPCSession : public boost::noncopyable +{ +public: + enum SessionStatus + { + Working, // test execution in progress + Available, // test execution has finished + HasFinished, // has just finished execution + NotExist // socket yet not initialized + }; + + static SessionInterface& instance(std::string const& _threadID); + static void sessionStart(std::string const& _threadID); + static void sessionEnd(std::string const& _threadID, SessionStatus _status); + static SessionStatus sessionStatus(std::string const& _threadID); + static void clear(); + + SessionInterface& getImplementation() { return *m_implementation; } + ~RPCSession() { delete m_implementation; } + +private: + explicit RPCSession(SessionInterface* _impl); + static void runNewInstanceOfAClient(std::string const& _threadID, ClientConfig const& _config); + SessionInterface* m_implementation; + + /// Parse std::string replacing keywords to values + // void parseString(std::string& _string, std::map const& _varMap); +}; diff --git a/retesteth/session/SessionInterface.h b/retesteth/session/SessionInterface.h new file mode 100644 index 000000000..c914390c8 --- /dev/null +++ b/retesteth/session/SessionInterface.h @@ -0,0 +1,78 @@ +#pragma once +#include +#include + +class SessionInterface +{ +public: + virtual std::string web3_clientVersion() = 0; + + // ETH Methods + virtual std::string eth_sendRawTransaction(std::string const& _rlp) = 0; + virtual std::string eth_sendTransaction(std::string const& _transaction) = 0; + virtual int eth_getTransactionCount( + std::string const& _address, std::string const& _blockNumber) = 0; + virtual test::scheme_transactionReceipt eth_getTransactionReceipt( + std::string const& _transactionHash) = 0; + + virtual std::string eth_blockNumber() = 0; + virtual test::scheme_block eth_getBlockByHash(string const& _hash, bool _fullObjects) = 0; + virtual test::scheme_block eth_getBlockByNumber( + BlockNumber const& _blockNumber, bool _fullObjects) = 0; + + virtual std::string eth_getCode( + std::string const& _address, std::string const& _blockNumber) = 0; + virtual std::string eth_getBalance( + std::string const& _address, std::string const& _blockNumber) = 0; + + // Debug + virtual scheme_debugAccountRange debug_accountRange(std::string const& _blockHashOrNumber, + int _txIndex, std::string const& _address, int _maxResults) = 0; + virtual DataObject debug_storageRangeAt(std::string const& _blockHashOrNumber, int _txIndex, + std::string const& _address, std::string const& _begin, int _maxResults) = 0; + virtual scheme_debugTraceTransaction debug_traceTransaction(std::string const& _trHash) = 0; + + // Test + virtual void test_setChainParams(std::string const& _config) = 0; + virtual void test_rewindToBlock(size_t _blockNr) = 0; + virtual void test_modifyTimestamp(unsigned long long _timestamp) = 0; + virtual string test_mineBlocks(int _number, bool _canFail = false) = 0; + virtual string test_importRawBlock(std::string const& _blockRLP) = 0; + + // ?? Deprecated ?? + virtual std::string test_getBlockStatus(std::string const& _blockHash) = 0; + virtual std::string test_getLogHash(std::string const& _txHash) = 0; + + // ?? Deprecated ?? + virtual std::string eth_getStorageRoot( + std::string const& _address, std::string const& _blockNumber) = 0; + virtual std::string eth_getStorageAt(std::string const& _address, std::string const& _position, + std::string const& _blockNumber) = 0; + virtual std::string personal_newAccount(std::string const& _password) = 0; + virtual void personal_unlockAccount( + std::string const& _address, std::string const& _password, int _duration) = 0; + + // Internal + virtual std::string sendRawRequest(std::string const& _request) = 0; + virtual DataObject rpcCall(std::string const& _methodName, + std::vector const& _args = std::vector(), + bool _canFail = false) = 0; + + virtual Socket::SocketType getSocketType() const = 0; + virtual std::string const& getSocketPath() const = 0; + + string const& getLastRPCErrorMessage() const + { + /// Returns empty string if last RPC call had no errors, error string if there was an error + static string const empty; + return (m_lastInterfaceError.type() != DataType::Null) ? + m_lastInterfaceError.atKey("error").asString() : + empty; + } + DataObject const& getLastRPCError() const { return m_lastInterfaceError; } + virtual ~SessionInterface() {} + +protected: + inline std::string quote(std::string const& _arg) { return "\"" + _arg + "\""; } + DataObject m_lastInterfaceError; // last RPC error info +}; diff --git a/retesteth/session/Socket.cpp b/retesteth/session/Socket.cpp new file mode 100644 index 000000000..7b8e80262 --- /dev/null +++ b/retesteth/session/Socket.cpp @@ -0,0 +1,273 @@ +#include "Socket.h" +#include +#include +#include +#include +#include +#include + + +using namespace std; + +Socket::Socket(SocketType _type, string const& _path) : m_path(_path), m_socketType(_type) +{ +#if defined(_WIN32) + 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) + ETH_FAIL_MESSAGE("Error creating IPC socket object!"); + +#else + if (_type == SocketType::IPC) + { + if (_path.length() >= sizeof(sockaddr_un::sun_path)) + ETH_FAIL_MESSAGE("Error opening IPC: socket path is too long!"); + + struct sockaddr_un saun; + memset(&saun, 0, sizeof(sockaddr_un)); + saun.sun_family = AF_UNIX; + strcpy(saun.sun_path, _path.c_str()); + +// 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__) + + if ((m_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + ETH_FAIL_MESSAGE("Error creating IPC socket object"); + + if (connect(m_socket, reinterpret_cast(&saun), + sizeof(struct sockaddr_un)) < 0) + { + close(m_socket); + ETH_FAIL_MESSAGE("Error connecting to IPC socket: " + _path); + } + } + else if (_type == SocketType::TCP) + { + struct sockaddr_in sin; + sin.sin_family = AF_INET; + + size_t pos = _path.find_last_of(':'); + string address = _path.substr(0, pos); + int port = atoi(_path.substr(pos + 1).c_str()); + + sin.sin_addr.s_addr = inet_addr(address.c_str()); + sin.sin_port = htons(port); + + if ((m_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) + ETH_FAIL_MESSAGE("Error creating TCP socket object"); + + if (connect(m_socket, reinterpret_cast(&sin), + sizeof(struct sockaddr_in)) < 0) + { + close(m_socket); + ETH_FAIL_MESSAGE("Error connecting to TCP socket: " + _path); + } + } +#endif +} + +namespace +{ +std::size_t writecallback(const char* in, std::size_t size, std::size_t num, std::string* out) +{ + const std::size_t totalBytes(size * num); + out->append(in, totalBytes); + return totalBytes; +} + +#if defined(_WIN32) +string sendRequestWin(string const& _req) +{ + // Write to the pipe. + DWORD cbWritten; + BOOL fSuccess = WriteFile(m_socket, // pipe handle + _req.c_str(), // message + _req.size(), // message length + &cbWritten, // bytes written + NULL); // not overlapped + + if (!fSuccess || (_req.size() != cbWritten)) + ETH_FAIL_MESSAGE("WriteFile to pipe failed"); + + // Read from the pipe. + DWORD cbRead; + fSuccess = ReadFile(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) + ETH_FAIL_MESSAGE("ReadFile from pipe failed"); + + return string(m_readBuf, m_readBuf + cbRead); +} +#endif + +struct WriteThis +{ + const char* readptr; + size_t sizeleft; +}; + +static size_t readcallback(void* dest, size_t size, size_t nmemb, void* userp) +{ + struct WriteThis* wt = (struct WriteThis*)userp; + size_t buffer_size = size * nmemb; + + if (wt->sizeleft) + { + /* copy as much as possible from the source to the destination */ + size_t copy_this_much = wt->sizeleft; + if (copy_this_much > buffer_size) + copy_this_much = buffer_size; + memcpy(dest, wt->readptr, copy_this_much); + + wt->readptr += copy_this_much; + wt->sizeleft -= copy_this_much; + + return copy_this_much; /* we copied this many bytes */ + } + + return 0; /* no more data left to deliver */ +} + +string sendRequestTCP(string const& _req, string const& _address) +{ + CURL* curl; + CURLcode res; + curl = curl_easy_init(); + + string url = _address; + if (_address.find("http") == string::npos) + url = "http://" + _address; + if (curl) + { + std::unique_ptr httpData(new std::string()); + struct WriteThis wt; + wt.readptr = _req.c_str(); + wt.sizeleft = _req.size(); + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 3000000); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get()); + curl_easy_setopt(curl, CURLOPT_READFUNCTION, readcallback); + curl_easy_setopt(curl, CURLOPT_READDATA, &wt); + curl_easy_setopt(curl, CURLOPT_POST, 1L); + + struct curl_slist* header = NULL; + header = curl_slist_append(header, "Accept: application/json, text/plain"); + header = curl_slist_append(header, "Content-Type: application/json"); + header = curl_slist_append(header, "Transfer-Encoding: chunked"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 500L); + res = curl_easy_perform(curl); + if (res != CURLE_OK) + ETH_FAIL_MESSAGE("curl_easy_perform() failed " + string(curl_easy_strerror(res))); + curl_slist_free_all(header); + curl_easy_cleanup(curl); + return *httpData.get(); + } + else + ETH_FAIL_MESSAGE("Error initializing Curl"); + return string(); +} +} // namespace + +string Socket::sendRequestIPC(string const& _req, SocketResponseValidator& _validator) +{ + char buf; + recv(m_socket, &buf, 1, MSG_PEEK | MSG_DONTWAIT); + if (errno == ENOTCONN) + ETH_FAIL_MESSAGE("Socket connection error! "); + + if (send(m_socket, _req.c_str(), _req.length(), 0) != (ssize_t)_req.length()) + ETH_FAIL_MESSAGE("Writing on socket failed."); + + auto start = chrono::steady_clock::now(); + ssize_t ret = 0; + string reply; + + while ( + _validator.completeResponse() == false && + chrono::duration_cast(chrono::steady_clock::now() - start).count() < + m_readTimeOutMS) + { + ret = recv(m_socket, m_readBuf, sizeof(m_readBuf), 0); + + // Also consider closed socket an error. + if (ret < 0) + ETH_FAIL_MESSAGE("Reading on socket failed!"); + + _validator.acceptResponse(m_readBuf); + memset(&m_readBuf[0], 0, sizeof(m_readBuf)); + } + + reply = _validator.getResponse(); + + if (ret == 0) + ETH_FAIL_MESSAGE("Timeout reading on socket."); + + return reply; +} + +string Socket::sendRequest(string const& _req, SocketResponseValidator& _val) +{ +#if defined(_WIN32) + return sendRequestWin(_req); +#endif + + if (m_socketType == Socket::TCP) + return sendRequestTCP(_req, m_path); + + if (m_socketType == Socket::IPC) + return sendRequestIPC(_req, _val); + + return string(); +} + +JsonObjectValidator::JsonObjectValidator() +{ + m_status = false; + m_bracersCount = 0; +} +void JsonObjectValidator::acceptResponse(std::string const& _response) +{ + m_response += _response; + for (size_t i = 0; i < _response.size(); i++) + { + if (_response[i] == '{') + m_bracersCount++; + else if (_response[i] == '}') + m_bracersCount--; + } + if (m_bracersCount == 0) + m_status = true; +} + +bool JsonObjectValidator::completeResponse() const +{ + return m_status; +} + +std::string JsonObjectValidator::getResponse() const +{ + return m_response; +} diff --git a/retesteth/Socket.h b/retesteth/session/Socket.h similarity index 95% rename from retesteth/Socket.h rename to retesteth/session/Socket.h index d59693626..0a13bea5b 100644 --- a/retesteth/Socket.h +++ b/retesteth/session/Socket.h @@ -3,15 +3,15 @@ #if defined(_WIN32) #include #else -#include +#include +#include #include +#include #include -#include -#include #endif -#include #include +#include class SocketResponseValidator { @@ -51,14 +51,15 @@ class Socket : public boost::noncopyable TCHAR m_readBuf[512000]; }; #else -class Socket: public boost::noncopyable +class Socket : public boost::noncopyable { public: enum SocketType { IPC, TCP, - IPCDebug + IPCDebug, + TransitionTool }; explicit Socket(SocketType _type, std::string const& _path); std::string sendRequest(std::string const& _req, SocketResponseValidator& _responseValidator); @@ -68,7 +69,6 @@ class Socket: public boost::noncopyable SocketType type() const { return m_socketType; } private: - std::string m_path; int m_socket; SocketType m_socketType; diff --git a/retesteth/testSuites/Common.cpp b/retesteth/testSuites/Common.cpp index 001039d60..fe6404211 100644 --- a/retesteth/testSuites/Common.cpp +++ b/retesteth/testSuites/Common.cpp @@ -1,12 +1,12 @@ #include "Common.h" #include #include -#include +#include using namespace std; namespace test { void validatePostHash( - RPCSession& _session, string const& _postHash, scheme_block const& _latestInfo) + SessionInterface& _session, string const& _postHash, scheme_block const& _latestInfo) { string actualHash = _latestInfo.getStateHash(); if (actualHash != _postHash) @@ -57,7 +57,7 @@ void checkTestNameIsEqualToFileName(DataObject const& _input) "'"); } -scheme_account remoteGetAccount(RPCSession& _session, string const& _account, +scheme_account remoteGetAccount(SessionInterface& _session, string const& _account, scheme_block const& _latestInfo, size_t& _totalSize) { DataObject accountObj; @@ -93,7 +93,7 @@ scheme_account remoteGetAccount(RPCSession& _session, string const& _account, return scheme_account(accountObj); } -scheme_state getRemoteState(RPCSession& _session, scheme_block const& _latestInfo) +scheme_state getRemoteState(SessionInterface& _session, scheme_block const& _latestInfo) { const int c_accountLimitBeforeHash = 20; DataObject accountsObj; @@ -148,7 +148,7 @@ scheme_state getRemoteState(RPCSession& _session, scheme_block const& _latestInf return scheme_state(accountsObj); } -void printVmTrace(RPCSession& _session, string const& _trHash, string const& _stateRoot) +void printVmTrace(SessionInterface& _session, string const& _trHash, string const& _stateRoot) { scheme_debugTraceTransaction ret = _session.debug_traceTransaction(_trHash); for (auto const& entry : ret.getEntries()) diff --git a/retesteth/testSuites/Common.h b/retesteth/testSuites/Common.h index 6789da9e4..f64816a1a 100644 --- a/retesteth/testSuites/Common.h +++ b/retesteth/testSuites/Common.h @@ -19,18 +19,18 @@ along with cpp-ethereum. If not, see . */ #pragma once -#include +#include #include namespace test { // Check post condition on a client -// void checkExpectSection(RPCSession& _session, LatestInfo const& _expectedInfo); +// void checkExpectSection(SessionInterface& _session, LatestInfo const& _expectedInfo); void validatePostHash( - RPCSession& _session, string const& _postHash, scheme_block const& _latestInfo); + SessionInterface& _session, string const& _postHash, scheme_block const& _latestInfo); // Get Remote State From Client -scheme_state getRemoteState(RPCSession& _session, scheme_block const& _latestInfo); +scheme_state getRemoteState(SessionInterface& _session, scheme_block const& _latestInfo); // Check that test has data object void checkDataObject(DataObject const& _input); @@ -45,18 +45,18 @@ void checkAtLeastOneTest(DataObject const& _input); void checkTestNameIsEqualToFileName(DataObject const& _input); // Compare states with session asking post state data on the fly -void compareStates( - scheme_expectState const& _stateExpect, RPCSession& _session, scheme_block const& _latestInfo); +void compareStates(scheme_expectState const& _stateExpect, SessionInterface& _session, + scheme_block const& _latestInfo); void compareStates(scheme_expectState const& _stateExpect, scheme_state const& _statePost); string CompareResultToString(CompareResult res); // Get account from remote state. inline function -scheme_account remoteGetAccount(RPCSession& _session, string const& _account, +scheme_account remoteGetAccount(SessionInterface& _session, string const& _account, scheme_block const& _latestInfo, size_t& _totalSize); // Get list of account from remote client -DataObject getRemoteAccountList(RPCSession& _session, scheme_block const& _latestInfo); +DataObject getRemoteAccountList(SessionInterface& _session, scheme_block const& _latestInfo); // json trace vm -void printVmTrace(RPCSession& _session, std::string const& _trHash, string const& _stateRoot); +void printVmTrace(SessionInterface& _session, std::string const& _trHash, string const& _stateRoot); } diff --git a/retesteth/testSuites/CompareStates.cpp b/retesteth/testSuites/CompareStates.cpp index 066f4c695..add819295 100644 --- a/retesteth/testSuites/CompareStates.cpp +++ b/retesteth/testSuites/CompareStates.cpp @@ -1,7 +1,7 @@ #include "Common.h" #include #include -#include +#include using namespace std; namespace test { @@ -80,7 +80,7 @@ CompareResult compareAccounts( return result; } -DataObject getRemoteAccountList(RPCSession& _session, scheme_block const& _latestInfo) +DataObject getRemoteAccountList(SessionInterface& _session, scheme_block const& _latestInfo) { DataObject accountList; string startHash = "0"; @@ -113,8 +113,8 @@ DataObject getRemoteAccountList(RPCSession& _session, scheme_block const& _lates //} // compare states with session asking post state data on the fly -void compareStates( - scheme_expectState const& _stateExpect, RPCSession& _session, scheme_block const& _latestInfo) +void compareStates(scheme_expectState const& _stateExpect, SessionInterface& _session, + scheme_block const& _latestInfo) { CompareResult result = CompareResult::Success; DataObject accountList = getRemoteAccountList(_session, _latestInfo); diff --git a/retesteth/testSuites/RPCTests.cpp b/retesteth/testSuites/RPCTests.cpp index 4dc847149..2aa448746 100644 --- a/retesteth/testSuites/RPCTests.cpp +++ b/retesteth/testSuites/RPCTests.cpp @@ -23,10 +23,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -41,7 +41,7 @@ DataObject FillTest(DataObject const& _testFile, TestSuite::TestSuiteOptions& _o DataObject filledTest; scheme_RPCTestFiller rpcTestFiller(_testFile); - RPCSession& session = RPCSession::instance(TestOutputHelper::getThreadID()); + SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); if (rpcTestFiller.hasGenesis()) session.test_setChainParams(rpcTestFiller.getGenesisForRPC().asJson()); diff --git a/retesteth/testSuites/StateTests.cpp b/retesteth/testSuites/StateTests.cpp index f45935c7e..999ff8cf3 100644 --- a/retesteth/testSuites/StateTests.cpp +++ b/retesteth/testSuites/StateTests.cpp @@ -31,11 +31,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -62,7 +62,7 @@ DataObject FillTestAsBlockchain(DataObject const& _testFile) DataObject filledTest; test::scheme_stateTestFiller test(_testFile); - RPCSession& session = RPCSession::instance(TestOutputHelper::getThreadID()); + SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); // run transactions on all networks that we need for (auto const& net : test.getExpectSection().getAllNetworksFromExpectSection()) { @@ -169,7 +169,7 @@ DataObject FillTest(DataObject const& _testFile) filledTest.setAutosort(true); test::scheme_stateTestFiller test(_testFile); - RPCSession& session = RPCSession::instance(TestOutputHelper::getThreadID()); + SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); if (test.getData().count("_info")) filledTest["_info"] = test.getData().atKey("_info"); filledTest["env"] = test.getEnv().getData(); @@ -255,7 +255,7 @@ DataObject FillTest(DataObject const& _testFile) void RunTest(DataObject const& _testFile) { test::scheme_stateTest test(_testFile); - RPCSession& session = RPCSession::instance(TestOutputHelper::getThreadID()); + SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); // read post state results for (auto const& post: test.getPost().getResults()) diff --git a/retesteth/testSuites/VMTestsConverter.cpp b/retesteth/testSuites/VMTestsConverter.cpp index d84ae5f78..89570240a 100644 --- a/retesteth/testSuites/VMTestsConverter.cpp +++ b/retesteth/testSuites/VMTestsConverter.cpp @@ -31,11 +31,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include diff --git a/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp b/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp index e7b07c3e9..84dbe5067 100644 --- a/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp +++ b/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp @@ -1,7 +1,7 @@ #include "BlockchainTestLogic.h" #include "fillers/BlockchainTestFillerLogic.h" #include -#include +#include #include @@ -19,7 +19,7 @@ void RunTest(DataObject const& _testObject, TestSuite::TestSuiteOptions const& _ std::cout << "Running " << TestOutputHelper::get().testName() << std::endl; scheme_blockchainTest inputTest(_testObject, _opt.isLegacyTests); TestOutputHelper::get().setUnitTestExceptions(inputTest.getUnitTestExceptions()); - RPCSession& session = RPCSession::instance(TestOutputHelper::getThreadID()); + SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); // Info for genesis TestInfo errorInfo (inputTest.getNetwork(), 0); diff --git a/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp index 1a20b0550..abd524b78 100644 --- a/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp +++ b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp @@ -16,7 +16,7 @@ void FillTest(scheme_blockchainTestFiller const& _testObject, string const& _net if (_testObject.getData().count("_info")) _testOut["_info"] = _testObject.getData().atKey("_info"); - RPCSession& session = RPCSession::instance(TestOutputHelper::getThreadID()); + SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); // Initialise chain manager ETH_LOGC("FILL GENESIS INFO: ", 6, LogColor::LIME); diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp b/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp index 4c9fb2a00..0abb6091c 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp @@ -175,7 +175,7 @@ string TestBlockchain::prepareDebugInfoString(string const& _newBlockChainName) // Restore this chain on remote client up to < _number block // Restore chain up to _number of blocks. if _number is 0 restore the whole chain -void TestBlockchain::restoreUpToNumber(RPCSession& _session, size_t _number, bool _samechain) +void TestBlockchain::restoreUpToNumber(SessionInterface& _session, size_t _number, bool _samechain) { size_t firstBlock; if (_samechain) diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchain.h b/retesteth/testSuites/blockchain/fillers/TestBlockchain.h index 23e6e145e..653784e67 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchain.h +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchain.h @@ -1,7 +1,7 @@ #pragma once #include "TestBlock.h" #include -#include +#include #include #include @@ -16,7 +16,7 @@ class TestBlockchain TRUE, FALSE }; - TestBlockchain(RPCSession& _session, scheme_blockchainTestFiller const& _testObject, + TestBlockchain(SessionInterface& _session, scheme_blockchainTestFiller const& _testObject, std::string const& _network, RegenerateGenesis _regenerateGenesis) : m_session(_session), m_testObject(_testObject), m_network(_network) { @@ -48,7 +48,7 @@ class TestBlockchain // Restore this chain on remote client up to < _number block // Restore chain up to _number of blocks. if _number is 0 restore the whole chain - void restoreUpToNumber(RPCSession& _session, size_t _number, bool _samechain); + void restoreUpToNumber(SessionInterface& _session, size_t _number, bool _samechain); std::vector const& getBlocks() const { return m_blocks; } @@ -80,7 +80,7 @@ class TestBlockchain test::scheme_block postmineBlockHeader(blockSection const& _block, BlockNumber const& _latestBlockNumber, std::vector const& _uncles); - RPCSession& m_session; // Session with the client + SessionInterface& m_session; // Session with the client scheme_blockchainTestFiller const& m_testObject; // Test data information std::string m_network; // Forkname in genesis diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.h b/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.h index 860cf4e72..eca9d5181 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.h +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchainManager.h @@ -1,7 +1,7 @@ #pragma once #include "TestBlockchain.h" #include -#include +#include #include #include @@ -9,8 +9,8 @@ class TestBlockchainManager { public: - TestBlockchainManager(RPCSession& _session, scheme_blockchainTestFiller const& _testObject, - std::string const& _network) + TestBlockchainManager(SessionInterface& _session, + scheme_blockchainTestFiller const& _testObject, std::string const& _network) : m_session(_session), m_testObject(_testObject), m_sDefaultChainName(scheme_blockchainTestFiller::blockSection::getDefaultChainName()), @@ -50,7 +50,7 @@ class TestBlockchainManager test::scheme_block prepareUncle( scheme_uncleHeader _uncleOverwrite, vectorOfSchemeBlock const& _currentBlockPreparedUncles); - RPCSession& m_session; // session with the client + SessionInterface& m_session; // session with the client scheme_blockchainTestFiller const& m_testObject; // testData to generate genesis std::string m_sCurrentChainName; // Chain name that is mining blocks From d939758b2753fe16fd423a7e2b2761a6a5e555b8 Mon Sep 17 00:00:00 2001 From: Dimitry Kh Date: Thu, 23 Apr 2020 00:07:01 +0300 Subject: [PATCH 2/5] remove deprecated rpc methods --- retesteth/session/RPCImplementation.cpp | 33 ------------------------- retesteth/session/RPCImplementation.h | 12 --------- retesteth/session/SessionInterface.h | 13 ---------- 3 files changed, 58 deletions(-) diff --git a/retesteth/session/RPCImplementation.cpp b/retesteth/session/RPCImplementation.cpp index 675ddd6f2..eb2fb107b 100644 --- a/retesteth/session/RPCImplementation.cpp +++ b/retesteth/session/RPCImplementation.cpp @@ -187,44 +187,11 @@ string RPCImpl::test_importRawBlock(std::string const& _blockRLP) return string(); } -// ?? Deprecated ?? -std::string RPCImpl::test_getBlockStatus(std::string const& _blockHash) -{ - return rpcCall("test_getBlockStatus", {quote(_blockHash)}).asString(); -} - std::string RPCImpl::test_getLogHash(std::string const& _txHash) { return rpcCall("test_getLogHash", {quote(_txHash)}).asString(); } -// ?? Deprecated ?? -std::string RPCImpl::eth_getStorageRoot( - std::string const& _address, std::string const& _blockNumber) -{ - string address = (_address.length() == 20) ? "0x" + _address : _address; - return rpcCall("eth_getStorageRoot", {quote(address), quote(_blockNumber)}).asString(); -} - -std::string RPCImpl::eth_getStorageAt( - std::string const& _address, std::string const& _position, std::string const& _blockNumber) -{ - return rpcCall("eth_getStorageAt", {quote(_address), quote(_position), quote(_blockNumber)}) - .asString(); -} - -std::string RPCImpl::personal_newAccount(std::string const& _password) -{ - string addr = rpcCall("personal_newAccount", {quote(_password)}).asString(); - ETH_TEST_MESSAGE("Created account " + addr); - return addr; -} - -void RPCImpl::personal_unlockAccount( - std::string const& _address, std::string const& _password, int _duration) -{ - rpcCall("personal_unlockAccount", {quote(_address), quote(_password), to_string(_duration)}); -} // Internal std::string RPCImpl::sendRawRequest(std::string const& _request) diff --git a/retesteth/session/RPCImplementation.h b/retesteth/session/RPCImplementation.h index eab0dc089..4abdb1a59 100644 --- a/retesteth/session/RPCImplementation.h +++ b/retesteth/session/RPCImplementation.h @@ -42,20 +42,8 @@ class RPCImpl : public SessionInterface void test_modifyTimestamp(unsigned long long _timestamp) override; string test_mineBlocks(int _number, bool _canFail = false) override; string test_importRawBlock(std::string const& _blockRLP) override; - - // ?? Deprecated ?? - std::string test_getBlockStatus(std::string const& _blockHash) override; std::string test_getLogHash(std::string const& _txHash) override; - // ?? Deprecated ?? - std::string eth_getStorageRoot( - std::string const& _address, std::string const& _blockNumber) override; - std::string eth_getStorageAt(std::string const& _address, std::string const& _position, - std::string const& _blockNumber) override; - std::string personal_newAccount(std::string const& _password) override; - void personal_unlockAccount( - std::string const& _address, std::string const& _password, int _duration) override; - // Internal std::string sendRawRequest(std::string const& _request) override; DataObject rpcCall(std::string const& _methodName, diff --git a/retesteth/session/SessionInterface.h b/retesteth/session/SessionInterface.h index c914390c8..30afa1b11 100644 --- a/retesteth/session/SessionInterface.h +++ b/retesteth/session/SessionInterface.h @@ -19,7 +19,6 @@ class SessionInterface virtual test::scheme_block eth_getBlockByHash(string const& _hash, bool _fullObjects) = 0; virtual test::scheme_block eth_getBlockByNumber( BlockNumber const& _blockNumber, bool _fullObjects) = 0; - virtual std::string eth_getCode( std::string const& _address, std::string const& _blockNumber) = 0; virtual std::string eth_getBalance( @@ -38,20 +37,8 @@ class SessionInterface virtual void test_modifyTimestamp(unsigned long long _timestamp) = 0; virtual string test_mineBlocks(int _number, bool _canFail = false) = 0; virtual string test_importRawBlock(std::string const& _blockRLP) = 0; - - // ?? Deprecated ?? - virtual std::string test_getBlockStatus(std::string const& _blockHash) = 0; virtual std::string test_getLogHash(std::string const& _txHash) = 0; - // ?? Deprecated ?? - virtual std::string eth_getStorageRoot( - std::string const& _address, std::string const& _blockNumber) = 0; - virtual std::string eth_getStorageAt(std::string const& _address, std::string const& _position, - std::string const& _blockNumber) = 0; - virtual std::string personal_newAccount(std::string const& _password) = 0; - virtual void personal_unlockAccount( - std::string const& _address, std::string const& _password, int _duration) = 0; - // Internal virtual std::string sendRawRequest(std::string const& _request) = 0; virtual DataObject rpcCall(std::string const& _methodName, From 3c8dfd33a07db5e8cea70182d10b66de700ac398 Mon Sep 17 00:00:00 2001 From: Dimitry Kh Date: Thu, 23 Apr 2020 00:11:14 +0300 Subject: [PATCH 3/5] circle fix --- circle.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/circle.yml b/circle.yml index 9a7038c71..aa253e20b 100644 --- a/circle.yml +++ b/circle.yml @@ -26,9 +26,9 @@ defaults: command: | cmake ../project -G "$GENERATOR" -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCOVERAGE=ON $CMAKE_OPTIONS - configure: &configureMac + configureMac: &configureMac run: - name: "Configure" + name: "ConfigureMac" working_directory: ~/build command: | cmake ../project -G "$GENERATOR" -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCOVERAGE=ON $CMAKE_OPTIONS -DCMAKE_TOOLCHAIN_FILE=~/project/toolchain.cmake @@ -68,7 +68,7 @@ defaults: $GCOV --version codecov --required --gcov-exec "$GCOV" --gcov-root ~/build - install-deps: &install-solidity-mac + install-solidity-mac: &install-solidity-mac run: name: "Install solidity" command: | @@ -86,7 +86,7 @@ defaults: cd build cmake .. -DLLL=1 -DUSE_Z3=0 sudo make install lllc -j $BUILD_PARALLEL_JOBS - install-deps: &install-solidity + install-solidity: &install-solidity run: name: "Install solidity" command: | From 8a31fbc809b5f0de18ad87abbceab857e2c2a9b6 Mon Sep 17 00:00:00 2001 From: Dimitry Kh Date: Fri, 24 Apr 2020 18:27:08 +0300 Subject: [PATCH 4/5] Tool Impl WIP --- .../{RPCImplementation.cpp => RPCImpl.cpp} | 25 +- .../{RPCImplementation.h => RPCImpl.h} | 14 +- retesteth/session/RPCSession.cpp | 12 +- retesteth/session/SessionInterface.h | 9 +- retesteth/session/ToolImpl.cpp | 220 ++++++++++++++++++ retesteth/session/ToolImpl.h | 70 ++++++ retesteth/testSuites/RPCTests.cpp | 2 +- retesteth/testSuites/StateTests.cpp | 13 +- .../blockchain/BlockchainTestLogic.cpp | 2 +- .../blockchain/fillers/TestBlockchain.cpp | 2 +- .../blockchain/fillers/TestBlockchain.h | 2 +- 11 files changed, 325 insertions(+), 46 deletions(-) rename retesteth/session/{RPCImplementation.cpp => RPCImpl.cpp} (91%) rename retesteth/session/{RPCImplementation.h => RPCImpl.h} (81%) create mode 100644 retesteth/session/ToolImpl.cpp create mode 100644 retesteth/session/ToolImpl.h diff --git a/retesteth/session/RPCImplementation.cpp b/retesteth/session/RPCImpl.cpp similarity index 91% rename from retesteth/session/RPCImplementation.cpp rename to retesteth/session/RPCImpl.cpp index eb2fb107b..c4a1e74fe 100644 --- a/retesteth/session/RPCImplementation.cpp +++ b/retesteth/session/RPCImpl.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include std::string RPCImpl::web3_clientVersion() { @@ -13,9 +13,10 @@ std::string RPCImpl::web3_clientVersion() } // ETH Methods -std::string RPCImpl::eth_sendRawTransaction(std::string const& _rlp) +std::string RPCImpl::eth_sendRawTransaction(scheme_transaction const& _transaction) { - DataObject result = rpcCall("eth_sendRawTransaction", {quote(_rlp)}, true); + DataObject result = + rpcCall("eth_sendRawTransaction", {quote(_transaction.getSignedRLP())}, true); DataObject const& lastError = getLastRPCError(); if (lastError.type() != DataType::Null) @@ -28,11 +29,6 @@ std::string RPCImpl::eth_sendRawTransaction(std::string const& _rlp) return result.asString(); } -std::string RPCImpl::eth_sendTransaction(std::string const& _transaction) -{ - return rpcCall("eth_sendTransaction", {_transaction}).asString(); -} - int RPCImpl::eth_getTransactionCount(std::string const& _address, std::string const& _blockNumber) { DataObject res = rpcCall("eth_getTransactionCount", {quote(_address), quote(_blockNumber)}); @@ -40,13 +36,6 @@ int RPCImpl::eth_getTransactionCount(std::string const& _address, std::string co res.asInt(); } -test::scheme_transactionReceipt RPCImpl::eth_getTransactionReceipt( - std::string const& _transactionHash) -{ - return test::scheme_transactionReceipt( - rpcCall("eth_getTransactionReceipt", {quote(_transactionHash)})); -} - std::string RPCImpl::eth_blockNumber() { DataObject res = rpcCall("eth_blockNumber", {}); @@ -101,10 +90,10 @@ scheme_debugTraceTransaction RPCImpl::debug_traceTransaction(std::string const& } // Test -void RPCImpl::test_setChainParams(std::string const& _config) +void RPCImpl::test_setChainParams(DataObject const& _config) { - ETH_FAIL_REQUIRE_MESSAGE( - rpcCall("test_setChainParams", {_config}) == true, "remote test_setChainParams = false"); + ETH_FAIL_REQUIRE_MESSAGE(rpcCall("test_setChainParams", {_config.asJson()}) == true, + "remote test_setChainParams = false"); } void RPCImpl::test_rewindToBlock(size_t _blockNr) diff --git a/retesteth/session/RPCImplementation.h b/retesteth/session/RPCImpl.h similarity index 81% rename from retesteth/session/RPCImplementation.h rename to retesteth/session/RPCImpl.h index 4abdb1a59..dce296015 100644 --- a/retesteth/session/RPCImplementation.h +++ b/retesteth/session/RPCImpl.h @@ -13,13 +13,9 @@ class RPCImpl : public SessionInterface std::string web3_clientVersion() override; // ETH Methods - std::string eth_sendRawTransaction(std::string const& _rlp) override; - std::string eth_sendTransaction(std::string const& _transaction) override; + std::string eth_sendRawTransaction(scheme_transaction const& _rlp) override; int eth_getTransactionCount( std::string const& _address, std::string const& _blockNumber) override; - test::scheme_transactionReceipt eth_getTransactionReceipt( - std::string const& _transactionHash) override; - std::string eth_blockNumber() override; test::scheme_block eth_getBlockByHash(string const& _hash, bool _fullObjects) override; test::scheme_block eth_getBlockByNumber( @@ -37,7 +33,7 @@ class RPCImpl : public SessionInterface scheme_debugTraceTransaction debug_traceTransaction(std::string const& _trHash) override; // Test - void test_setChainParams(std::string const& _config) override; + void test_setChainParams(DataObject const& _config) override; void test_rewindToBlock(size_t _blockNr) override; void test_modifyTimestamp(unsigned long long _timestamp) override; string test_mineBlocks(int _number, bool _canFail = false) override; @@ -45,12 +41,12 @@ class RPCImpl : public SessionInterface std::string test_getLogHash(std::string const& _txHash) override; // Internal - std::string sendRawRequest(std::string const& _request) override; + std::string sendRawRequest(std::string const& _request); DataObject rpcCall(std::string const& _methodName, std::vector const& _args = std::vector(), bool _canFail = false) override; - Socket::SocketType getSocketType() const; - std::string const& getSocketPath() const; + Socket::SocketType getSocketType() const override; + std::string const& getSocketPath() const override; private: Socket m_socket; diff --git a/retesteth/session/RPCSession.cpp b/retesteth/session/RPCSession.cpp index 33be5d6ce..7f7f45f2a 100644 --- a/retesteth/session/RPCSession.cpp +++ b/retesteth/session/RPCSession.cpp @@ -32,7 +32,8 @@ #include #include #include -#include +#include +#include using namespace std; using namespace dev; @@ -147,6 +148,15 @@ void RPCSession::runNewInstanceOfAClient(string const& _threadID, ClientConfig c socketMap.insert(std::pair(_threadID, std::move(info))); } } + else if (_config.getSocketType() == Socket::TransitionTool) + { + sessionInfo info(NULL, + new RPCSession(new ToolImpl(Socket::SocketType::TCP, _config.getAddress())), "", 0, + _config.getId()); + std::lock_guard lock(g_socketMapMutex); // function must be called from lock + socketMap.insert(std::pair(_threadID, std::move(info))); + return; + } else ETH_FAIL_MESSAGE("Unknown Socket Type in runNewInstanceOfAClient"); } diff --git a/retesteth/session/SessionInterface.h b/retesteth/session/SessionInterface.h index 30afa1b11..af1623e97 100644 --- a/retesteth/session/SessionInterface.h +++ b/retesteth/session/SessionInterface.h @@ -8,12 +8,9 @@ class SessionInterface virtual std::string web3_clientVersion() = 0; // ETH Methods - virtual std::string eth_sendRawTransaction(std::string const& _rlp) = 0; - virtual std::string eth_sendTransaction(std::string const& _transaction) = 0; + virtual std::string eth_sendRawTransaction(scheme_transaction const& _transaction) = 0; virtual int eth_getTransactionCount( std::string const& _address, std::string const& _blockNumber) = 0; - virtual test::scheme_transactionReceipt eth_getTransactionReceipt( - std::string const& _transactionHash) = 0; virtual std::string eth_blockNumber() = 0; virtual test::scheme_block eth_getBlockByHash(string const& _hash, bool _fullObjects) = 0; @@ -32,7 +29,7 @@ class SessionInterface virtual scheme_debugTraceTransaction debug_traceTransaction(std::string const& _trHash) = 0; // Test - virtual void test_setChainParams(std::string const& _config) = 0; + virtual void test_setChainParams(DataObject const& _config) = 0; virtual void test_rewindToBlock(size_t _blockNr) = 0; virtual void test_modifyTimestamp(unsigned long long _timestamp) = 0; virtual string test_mineBlocks(int _number, bool _canFail = false) = 0; @@ -40,11 +37,9 @@ class SessionInterface virtual std::string test_getLogHash(std::string const& _txHash) = 0; // Internal - virtual std::string sendRawRequest(std::string const& _request) = 0; virtual DataObject rpcCall(std::string const& _methodName, std::vector const& _args = std::vector(), bool _canFail = false) = 0; - virtual Socket::SocketType getSocketType() const = 0; virtual std::string const& getSocketPath() const = 0; diff --git a/retesteth/session/ToolImpl.cpp b/retesteth/session/ToolImpl.cpp new file mode 100644 index 000000000..799827018 --- /dev/null +++ b/retesteth/session/ToolImpl.cpp @@ -0,0 +1,220 @@ +#include +#include +#include + +#include +#include +#include + +void ToolImpl::executeTool() +{ + /* +#if defined(_WIN32) + BOOST_ERROR("LLL compilation only supported on posix systems."); + return ""; +#else + fs::path path(fs::temp_directory_path() / fs::unique_path()); + + string cmd = string(m_toolPath); + cmd += path.string(); + + writeFile(path.string(), _code); + string result = executeCmd(cmd); + fs::remove_all(path); + result = "0x" + result; + checkHexHasEvenLength(result); + return result; +#endif +*/ + return; +} + +std::string ToolImpl::web3_clientVersion() +{ + ETH_TEST_MESSAGE("Request: web3_clientVersion"); + return ""; +} + +// ETH Methods +std::string ToolImpl::eth_sendRawTransaction(scheme_transaction const& _transaction) +{ + ETH_TEST_MESSAGE("Request: eth_sendRawTransaction \n" + _transaction.getData().asJson()); + m_transactions.push_back(_transaction); + return ""; +} + +int ToolImpl::eth_getTransactionCount(std::string const& _address, std::string const& _blockNumber) +{ + ETH_TEST_MESSAGE("Request: eth_getTransactionCount"); + (void)_address; + (void)_blockNumber; + return 0; +} + +std::string ToolImpl::eth_blockNumber() +{ + ETH_TEST_MESSAGE("Request: eth_blockNumber"); + return ""; +} + +test::scheme_block ToolImpl::eth_getBlockByHash(string const& _hash, bool _fullObjects) +{ + ETH_TEST_MESSAGE("Request: eth_getBlockByHash"); + (void)_fullObjects; + return test::scheme_block(DataObject(_hash)); +} + +test::scheme_block ToolImpl::eth_getBlockByNumber( + BlockNumber const& _blockNumber, bool _fullObjects) +{ + ETH_TEST_MESSAGE("Request: eth_getBlockByNumber"); + (void)_fullObjects; + (void)_blockNumber; + return test::scheme_block(DataObject()); +} + +std::string ToolImpl::eth_getCode(std::string const& _address, std::string const& _blockNumber) +{ + ETH_TEST_MESSAGE("Request: eth_getCode"); + (void)_address; + (void)_blockNumber; + return ""; +} + +std::string ToolImpl::eth_getBalance(std::string const& _address, std::string const& _blockNumber) +{ + ETH_TEST_MESSAGE("Request: eth_getBalance"); + (void)_address; + (void)_blockNumber; + return ""; +} + +// Debug +scheme_debugAccountRange ToolImpl::debug_accountRange(std::string const& _blockHashOrNumber, + int _txIndex, std::string const& _address, int _maxResults) +{ + ETH_TEST_MESSAGE("Request: debug_accountRange"); + (void)_txIndex; + (void)_address; + (void)_maxResults; + return scheme_debugAccountRange(DataObject(_blockHashOrNumber)); +} + + +DataObject ToolImpl::debug_storageRangeAt(std::string const& _blockHashOrNumber, int _txIndex, + std::string const& _address, std::string const& _begin, int _maxResults) +{ + ETH_TEST_MESSAGE("Request: debug_storageRangeAt"); + (void)_txIndex; + (void)_address; + (void)_begin; + (void)_maxResults; + return DataObject(_blockHashOrNumber); +} + +scheme_debugTraceTransaction ToolImpl::debug_traceTransaction(std::string const& _trHash) +{ + ETH_TEST_MESSAGE("Request: debug_traceTransaction"); + return scheme_debugTraceTransaction(DataObject(_trHash)); +} + +// Test +void ToolImpl::test_setChainParams(DataObject const& _config) +{ + ETH_TEST_MESSAGE("Request: test_setChainParams \n" + _config.asJson()); + m_chainParams = _config; +} + +void ToolImpl::test_rewindToBlock(size_t _blockNr) +{ + ETH_TEST_MESSAGE("Request: test_rewindToBlock"); + (void)_blockNr; +} + +void ToolImpl::test_modifyTimestamp(unsigned long long _timestamp) +{ + ETH_TEST_MESSAGE("Request: test_modifyTimestamp \n{" + DataObject(_timestamp).asJson() + "}"); + m_timestamp = _timestamp; +} + +string ToolImpl::getGenesisForTool(DataObject const& _genesis) const +{ + DataObject env; + env["currentCoinbase"] = _genesis.atKey("author"); + env["currentDifficulty"] = _genesis.atKey("difficulty"); + env["currentGasLimit"] = _genesis.atKey("gasLimit"); + env["currentNumber"] = "0x01"; + env["currentTimestamp"] = dev::toCompactHexPrefixed(m_timestamp, 1); + env["previousHash"] = "0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"; + return env.asJson(); +} + +string ToolImpl::getTxsForTool() const +{ + DataObject txs; + for (auto const& tx : m_transactions) + { + DataObject txToolFormat = tx.getDataForBCTest(); + txToolFormat.renameKey("data", "input"); + txToolFormat.renameKey("gasLimit", "gas"); + txToolFormat["hash"] = "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673"; + txs.addArrayObject(txToolFormat); + } + return txs.asJson(); +} + +string ToolImpl::test_mineBlocks(int _number, bool _canFail) +{ + ETH_TEST_MESSAGE("Request: test_mineBlocks"); + + // env.json file + fs::path envPath = m_tmpDir / "env.json"; + writeFile(envPath.string(), getGenesisForTool(m_chainParams["genesis"])); + + // txs.json file + fs::path txsPath = m_tmpDir / "txs.json"; + writeFile(txsPath.string(), getTxsForTool()); + + ETH_TEST_MESSAGE(txsPath.string()); + // m_tmpDir = ; + + (void)_number; + (void)_canFail; + return ""; +} + +string ToolImpl::test_importRawBlock(std::string const& _blockRLP) +{ + ETH_TEST_MESSAGE("Request: test_importRawBlock"); + (void)_blockRLP; + return string(); +} + +std::string ToolImpl::test_getLogHash(std::string const& _txHash) +{ + ETH_TEST_MESSAGE("Request: test_getLogHash"); + (void)_txHash; + return string(); +} + + +// Internal +DataObject ToolImpl::rpcCall( + std::string const& _methodName, std::vector const& _args, bool _canFail) +{ + ETH_TEST_MESSAGE("Request: rpcCall"); + (void)_methodName; + (void)_args; + (void)_canFail; + return DataObject(); +} + +Socket::SocketType ToolImpl::getSocketType() const +{ + return m_sockType; +} + +std::string const& ToolImpl::getSocketPath() const +{ + return m_toolPath; +} diff --git a/retesteth/session/ToolImpl.h b/retesteth/session/ToolImpl.h new file mode 100644 index 000000000..80a586610 --- /dev/null +++ b/retesteth/session/ToolImpl.h @@ -0,0 +1,70 @@ +#pragma once +#include +#include +#include +#include +#include + +class ToolImpl : public SessionInterface +{ +public: + ToolImpl(Socket::SocketType _type, const string& _path) : m_sockType(_type), m_toolPath(_path) + { + m_tmpDir = test::createUniqueTmpDirectory(); + } + +public: + std::string web3_clientVersion() override; + + // ETH Methods + std::string eth_sendRawTransaction(scheme_transaction const& _transaction) override; + int eth_getTransactionCount( + std::string const& _address, std::string const& _blockNumber) override; + std::string eth_blockNumber() override; + test::scheme_block eth_getBlockByHash(string const& _hash, bool _fullObjects) override; + test::scheme_block eth_getBlockByNumber( + BlockNumber const& _blockNumber, bool _fullObjects) override; + + std::string eth_getCode(std::string const& _address, std::string const& _blockNumber) override; + std::string eth_getBalance( + std::string const& _address, std::string const& _blockNumber) override; + + // Debug + scheme_debugAccountRange debug_accountRange(std::string const& _blockHashOrNumber, int _txIndex, + std::string const& _address, int _maxResults) override; + DataObject debug_storageRangeAt(std::string const& _blockHashOrNumber, int _txIndex, + std::string const& _address, std::string const& _begin, int _maxResults) override; + scheme_debugTraceTransaction debug_traceTransaction(std::string const& _trHash) override; + + // Test + void test_setChainParams(DataObject const& _config) override; + void test_rewindToBlock(size_t _blockNr) override; + void test_modifyTimestamp(unsigned long long _timestamp) override; + string test_mineBlocks(int _number, bool _canFail = false) override; + string test_importRawBlock(std::string const& _blockRLP) override; + std::string test_getLogHash(std::string const& _txHash) override; + + // Internal + DataObject rpcCall(std::string const& _methodName, + std::vector const& _args = std::vector(), + bool _canFail = false) override; + Socket::SocketType getSocketType() const override; + std::string const& getSocketPath() const override; + +private: + Socket::SocketType m_sockType; + string m_toolPath; + + size_t m_rpcSequence = 1; + unsigned m_sleepTime = 10; // 10 milliseconds + unsigned m_successfulMineRuns = 0; + unsigned m_maxMiningTime = 250000; // should be instant with --test (1 sec) + + fs::path m_tmpDir; + DataObject m_chainParams; + unsigned long long m_timestamp; + std::list m_transactions; + void executeTool(); + string getGenesisForTool(DataObject const& _genesis) const; + string getTxsForTool() const; +}; diff --git a/retesteth/testSuites/RPCTests.cpp b/retesteth/testSuites/RPCTests.cpp index 2aa448746..3fdc5d529 100644 --- a/retesteth/testSuites/RPCTests.cpp +++ b/retesteth/testSuites/RPCTests.cpp @@ -44,7 +44,7 @@ DataObject FillTest(DataObject const& _testFile, TestSuite::TestSuiteOptions& _o SessionInterface& session = RPCSession::instance(TestOutputHelper::getThreadID()); if (rpcTestFiller.hasGenesis()) - session.test_setChainParams(rpcTestFiller.getGenesisForRPC().asJson()); + session.test_setChainParams(rpcTestFiller.getGenesisForRPC()); DataObject returnedData = session.rpcCall(rpcTestFiller.get_method(), rpcTestFiller.get_params()); diff --git a/retesteth/testSuites/StateTests.cpp b/retesteth/testSuites/StateTests.cpp index 999ff8cf3..19e8e63fa 100644 --- a/retesteth/testSuites/StateTests.cpp +++ b/retesteth/testSuites/StateTests.cpp @@ -92,11 +92,10 @@ DataObject FillTestAsBlockchain(DataObject const& _testFile) mexpect.correctMiningReward(net, test.getEnv().getCoinbase()); string sEngine = scheme_blockchainTestBase::m_sNoProof; - session.test_setChainParams(test.getGenesisForRPC(net, sEngine).asJson()); + session.test_setChainParams(test.getGenesisForRPC(net, sEngine)); u256 a(test.getEnv().getData().atKey("currentTimestamp").asString()); session.test_modifyTimestamp(a.convert_to()); - string signedTransactionRLP = tr.transaction.getSignedRLP(); - string trHash = session.eth_sendRawTransaction(signedTransactionRLP); + string trHash = session.eth_sendRawTransaction(tr.transaction); if (session.getLastRPCError().type() != DataType::Null) ETH_ERROR_MESSAGE(session.getLastRPCError().atKey("message").asString()); @@ -181,7 +180,7 @@ DataObject FillTest(DataObject const& _testFile) { DataObject forkResults; forkResults.setKey(net); - session.test_setChainParams(test.getGenesisForRPC(net, "NoReward").asJson()); + session.test_setChainParams(test.getGenesisForRPC(net, "NoReward")); // run transactions for defined expect sections only for (auto const& expect : test.getExpectSection().getExpectSections()) @@ -206,7 +205,7 @@ DataObject FillTest(DataObject const& _testFile) u256 a(test.getEnv().getData().atKey("currentTimestamp").asString()); session.test_modifyTimestamp(a.convert_to()); - string trHash = session.eth_sendRawTransaction(tr.transaction.getSignedRLP()); + string trHash = session.eth_sendRawTransaction(tr.transaction); string latestBlockNumber = session.test_mineBlocks(1); tr.executed = true; @@ -266,7 +265,7 @@ void RunTest(DataObject const& _testFile) !inArray(Options::getDynamicOptions().getCurrentConfig().getNetworks(), network)) networkSkip = true; else - session.test_setChainParams(test.getGenesisForRPC(network, "NoReward").asJson()); + session.test_setChainParams(test.getGenesisForRPC(network, "NoReward")); // One test could have many transactions on same chainParams // It is expected that for a setted chainParams there going to be a transaction @@ -295,7 +294,7 @@ void RunTest(DataObject const& _testFile) { u256 a(test.getEnv().getData().atKey("currentTimestamp").asString()); session.test_modifyTimestamp(a.convert_to()); - string trHash = session.eth_sendRawTransaction(tr.transaction.getSignedRLP()); + string trHash = session.eth_sendRawTransaction(tr.transaction); string latestBlockNumber = session.test_mineBlocks(1); tr.executed = true; diff --git a/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp b/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp index 84dbe5067..2e08d1705 100644 --- a/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp +++ b/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp @@ -25,7 +25,7 @@ void RunTest(DataObject const& _testObject, TestSuite::TestSuiteOptions const& _ TestInfo errorInfo (inputTest.getNetwork(), 0); TestOutputHelper::get().setCurrentTestInfo(errorInfo); session.test_setChainParams( - inputTest.getGenesisForRPC(inputTest.getNetwork(), inputTest.getEngine()).asJson()); + inputTest.getGenesisForRPC(inputTest.getNetwork(), inputTest.getEngine())); // for all blocks size_t blockNumber = 0; diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp b/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp index 0abb6091c..b3c87276d 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp @@ -131,7 +131,7 @@ DataObject TestBlockchain::importTransactions(blockSection const& _block) ETH_LOGC("Import transactions: " + m_sDebugString, 6, LogColor::YELLOW); for (auto const& tr : _block.getTransactions()) { - string const trHash = m_session.eth_sendRawTransaction(tr.getSignedRLP()); + string const trHash = m_session.eth_sendRawTransaction(tr); if (!tr.isMarkedInvalid()) { transactionsArray.addArrayObject(tr.getDataForBCTest()); diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchain.h b/retesteth/testSuites/blockchain/fillers/TestBlockchain.h index 653784e67..ced7ca8fa 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchain.h +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchain.h @@ -40,7 +40,7 @@ class TestBlockchain { DataObject genesisObject = m_testObject.getGenesisForRPC(m_network, m_testObject.getSealEngine()); - m_session.test_setChainParams(genesisObject.asJson()); + m_session.test_setChainParams(genesisObject); } void generateBlock( From 6ac0fc89d8fd3ca652afef3b7976678f8d050b09 Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Mon, 27 Apr 2020 16:46:21 +0200 Subject: [PATCH 5/5] add subroutine tests for berlin fork --- retesteth/configs/ClientConfig.cpp | 13 +++++++++---- retesteth/configs/Genesis.h | 1 + retesteth/configs/Options.cpp | 1 + retesteth/configs/genesis/default/Berlin.cpp | 19 +++++++++++++++++++ .../genesis/default/correctMiningReward.cpp | 3 ++- retesteth/testSuites/LegacyTestsBoost.cpp | 6 ++++++ retesteth/testSuites/StateTestsBoost.cpp | 3 +++ retesteth/testSuites/VMTestsConverter.cpp | 2 +- .../testSuites/blockchain/BlockchainTests.cpp | 3 +++ 9 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 retesteth/configs/genesis/default/Berlin.cpp diff --git a/retesteth/configs/ClientConfig.cpp b/retesteth/configs/ClientConfig.cpp index b69a30d78..a9012c1d3 100644 --- a/retesteth/configs/ClientConfig.cpp +++ b/retesteth/configs/ClientConfig.cpp @@ -36,6 +36,7 @@ string default_config = R"({ "Constantinople", "ConstantinopleFix", "Istanbul" + "Berlin" ], "additionalForks" : [ "FrontierToHomesteadAt5", @@ -150,7 +151,8 @@ string besu_config = R"({ "Byzantium", "Constantinople", "ConstantinopleFix", - "Istanbul" + "Istanbul", + "Berlin" ], "additionalForks" : [ "FrontierToHomesteadAt5", @@ -180,7 +182,8 @@ string alethTCP_config = R"({ "Byzantium", "Constantinople", "ConstantinopleFix", - "Istanbul" + "Istanbul", + "Berlin" ], "additionalForks" : [ "FrontierToHomesteadAt5", @@ -224,7 +227,8 @@ string alethIPCDebug_config = R"({ "Byzantium", "Constantinople", "ConstantinopleFix", - "Istanbul" + "Istanbul", + "Berlin" ], "additionalForks" : [ "FrontierToHomesteadAt5", @@ -267,7 +271,8 @@ string aleth_config = R"({ "Byzantium", "Constantinople", "ConstantinopleFix", - "Istanbul" + "Istanbul", + "Berlin" ], "additionalForks" : [ "FrontierToHomesteadAt5", diff --git a/retesteth/configs/Genesis.h b/retesteth/configs/Genesis.h index bbc543a78..442511abd 100644 --- a/retesteth/configs/Genesis.h +++ b/retesteth/configs/Genesis.h @@ -10,6 +10,7 @@ extern std::string default_Byzantium_config; extern std::string default_Constantinople_config; extern std::string default_ConstantinopleFix_config; extern std::string default_Istanbul_config; +extern std::string default_Berlin_config; // Transition test configs extern std::string default_FrontierToHomesteadAt5_config; diff --git a/retesteth/configs/Options.cpp b/retesteth/configs/Options.cpp index 9034d5412..0d8fb2cee 100644 --- a/retesteth/configs/Options.cpp +++ b/retesteth/configs/Options.cpp @@ -63,6 +63,7 @@ void deployFirstRunConfigs() writeFile(genesisDir / "Constantinople.json", default_Constantinople_config); writeFile(genesisDir / "ConstantinopleFix.json", default_ConstantinopleFix_config); writeFile(genesisDir / "Istanbul.json", default_Istanbul_config); + writeFile(genesisDir / "Berlin.json", default_Berlin_config); writeFile(genesisDir / "FrontierToHomesteadAt5.json", default_FrontierToHomesteadAt5_config); writeFile(genesisDir / "HomesteadToDaoAt5.json", default_HomesteadToDaoAt5_config); diff --git a/retesteth/configs/genesis/default/Berlin.cpp b/retesteth/configs/genesis/default/Berlin.cpp new file mode 100644 index 000000000..912febf55 --- /dev/null +++ b/retesteth/configs/genesis/default/Berlin.cpp @@ -0,0 +1,19 @@ +#include +#include +using namespace std; + +string default_Berlin_config = R"({ + "params" : { + "homesteadForkBlock" : "0x00", + "EIP150ForkBlock" : "0x00", + "EIP158ForkBlock" : "0x00", + "byzantiumForkBlock" : "0x00", + "constantinopleForkBlock" : "0x00", + "constantinopleFixForkBlock" : "0x00", + "istanbulForkBlock" : "0x00", + "berlinForkBlock" : "0x00", + "chainID" : "0x01" + }, + "accounts" : { + } +})"; diff --git a/retesteth/configs/genesis/default/correctMiningReward.cpp b/retesteth/configs/genesis/default/correctMiningReward.cpp index 97ba56e05..ae125c559 100644 --- a/retesteth/configs/genesis/default/correctMiningReward.cpp +++ b/retesteth/configs/genesis/default/correctMiningReward.cpp @@ -11,5 +11,6 @@ string default_correctMiningReward_config = R"({ "Byzantium": "3000000000000000000", "Constantinople": "2000000000000000000", "ConstantinopleFix": "2000000000000000000", - "Istanbul": "2000000000000000000" + "Istanbul": "2000000000000000000", + "Berlin": "2000000000000000000" })"; diff --git a/retesteth/testSuites/LegacyTestsBoost.cpp b/retesteth/testSuites/LegacyTestsBoost.cpp index dcc407b64..e324665b6 100644 --- a/retesteth/testSuites/LegacyTestsBoost.cpp +++ b/retesteth/testSuites/LegacyTestsBoost.cpp @@ -64,6 +64,9 @@ BOOST_AUTO_TEST_SUITE(LegacyTests) BOOST_AUTO_TEST_CASE(stExtCodeHash) {} BOOST_AUTO_TEST_CASE(stSStoreTest) {} + //Berlin Tests + BOOST_AUTO_TEST_CASE(stSubroutine) {} + // Stress Tests BOOST_AUTO_TEST_CASE(stAttackTest) {} BOOST_AUTO_TEST_CASE(stMemoryStressTest) {} @@ -136,6 +139,9 @@ BOOST_AUTO_TEST_SUITE(LegacyTests) BOOST_AUTO_TEST_CASE(stExtCodeHash) {} BOOST_AUTO_TEST_CASE(stSStoreTest) {} + //Berlin Tests + BOOST_AUTO_TEST_CASE(stSubroutine) {} + // Stress Tests BOOST_AUTO_TEST_CASE(stAttackTest) {} BOOST_AUTO_TEST_CASE(stMemoryStressTest) {} diff --git a/retesteth/testSuites/StateTestsBoost.cpp b/retesteth/testSuites/StateTestsBoost.cpp index ee553c7b2..c323d551a 100644 --- a/retesteth/testSuites/StateTestsBoost.cpp +++ b/retesteth/testSuites/StateTestsBoost.cpp @@ -93,6 +93,9 @@ BOOST_AUTO_TEST_CASE(stCreate2) {} BOOST_AUTO_TEST_CASE(stExtCodeHash) {} BOOST_AUTO_TEST_CASE(stSStoreTest) {} +//Berlin Tests +BOOST_AUTO_TEST_CASE(stSubroutine) {} + // Stress Tests BOOST_AUTO_TEST_CASE(stAttackTest) {} BOOST_AUTO_TEST_CASE(stMemoryStressTest) {} diff --git a/retesteth/testSuites/VMTestsConverter.cpp b/retesteth/testSuites/VMTestsConverter.cpp index 89570240a..fd540fa94 100644 --- a/retesteth/testSuites/VMTestsConverter.cpp +++ b/retesteth/testSuites/VMTestsConverter.cpp @@ -154,7 +154,7 @@ DataObject VMTestConverterSuite::doTests(DataObject const& _input, TestSuiteOpti // Construct expect section DataObject expectSection; - expectSection["network"].addArrayObject(DataObject(">=Istanbul")); + expectSection["network"].addArrayObject(DataObject(">=Berlin")); if (vmFiller.count("expect")) expectSection["result"] = vmFiller.atKey("expect"); else diff --git a/retesteth/testSuites/blockchain/BlockchainTests.cpp b/retesteth/testSuites/blockchain/BlockchainTests.cpp index 5dc32280b..30aa4506f 100644 --- a/retesteth/testSuites/blockchain/BlockchainTests.cpp +++ b/retesteth/testSuites/blockchain/BlockchainTests.cpp @@ -252,6 +252,9 @@ BOOST_AUTO_TEST_CASE(stCreate2) {} BOOST_AUTO_TEST_CASE(stExtCodeHash) {} BOOST_AUTO_TEST_CASE(stSStoreTest) {} +//Berlin Tests +BOOST_AUTO_TEST_CASE(stSubroutine) {} + // Stress Tests BOOST_AUTO_TEST_CASE(stAttackTest) {} BOOST_AUTO_TEST_CASE(stMemoryStressTest) {}