diff --git a/test/tools/jsontests/StateTests.cpp b/test/tools/jsontests/StateTests.cpp index bc8394b483b..e8596d1e909 100644 --- a/test/tools/jsontests/StateTests.cpp +++ b/test/tools/jsontests/StateTests.cpp @@ -60,10 +60,6 @@ void doStateTests(json_spirit::mValue& _v, bool _fillin) if (_fillin == false && Options::get().fillchain) continue; - BOOST_REQUIRE_MESSAGE(o.count("env") > 0, testname + "env not set!"); - BOOST_REQUIRE_MESSAGE(o.count("pre") > 0, testname + "pre not set!"); - BOOST_REQUIRE_MESSAGE(o.count("transaction") > 0, testname + "transaction not set!"); - ImportTest importer(o); Listener::ExecTimeGuard guard{i.first}; diff --git a/test/tools/libtesteth/ImportTest.cpp b/test/tools/libtesteth/ImportTest.cpp index bc91ab60d1e..aec384861c7 100644 --- a/test/tools/libtesteth/ImportTest.cpp +++ b/test/tools/libtesteth/ImportTest.cpp @@ -43,12 +43,19 @@ vector lastHashes(u256 _currentBlockNumber) ImportTest::ImportTest(json_spirit::mObject& _o): m_statePre(0, OverlayDB(), eth::BaseState::Empty), - m_statePost(0, OverlayDB(), eth::BaseState::Empty), m_testObject(_o) { + BOOST_REQUIRE_MESSAGE(_o.count("env"), TestOutputHelper::testName() + " env not set!"); + BOOST_REQUIRE_MESSAGE(_o.count("pre"), TestOutputHelper::testName() + " pre not set!"); importEnv(_o["env"].get_obj()); - importTransaction(_o["transaction"].get_obj()); importState(_o["pre"].get_obj(), m_statePre); + + if (_o.count("post")) + importPostStates(_o["post"].get_obj()); + else if (_o.count("transaction")) + importFillerTransaction(_o["transaction"].get_obj()); + else + BOOST_ERROR(TestOutputHelper::testName() + " has no transaction or post state section"); } bytes ImportTest::executeTest() @@ -74,7 +81,7 @@ bytes ImportTest::executeTest() if(opt.trValueIndex != -1 && opt.trValueIndex != tr.valInd) continue; - std::tie(tr.postState, tr.output, tr.changeLog) = + std::tie(tr.postState, tr.logs, tr.changeLog) = executeTransaction(net, *m_envInfo, m_statePre, tr.transaction); tr.netId = netIdToString(net); transactionResults.push_back(tr); @@ -204,7 +211,7 @@ void ImportTest::checkBalance(eth::State const& _pre, eth::State const& _post, b BOOST_REQUIRE_MESSAGE(preBalance + _miningReward >= postBalance, "Error when comparing states: preBalance + miningReward < postBalance (" + toString(preBalance) + " < " + toString(postBalance) + ") " + TestOutputHelper::testName()); } -std::tuple ImportTest::executeTransaction(eth::Network const _sealEngineNetwork, eth::EnvInfo const& _env, eth::State const& _preState, eth::Transaction const& _tr) +std::tuple ImportTest::executeTransaction(eth::Network const _sealEngineNetwork, eth::EnvInfo const& _env, eth::State const& _preState, eth::Transaction const& _tr) { assert(m_envInfo); @@ -219,7 +226,7 @@ std::tuple ImportTest::execu //Finalize the state manually (clear logs) bool removeEmptyAccounts = m_envInfo->number() >= se->chainParams().u256Param("EIP158ForkBlock"); initialState.commit(removeEmptyAccounts ? State::CommitBehaviour::RemoveEmptyAccounts : State::CommitBehaviour::KeepEmptyAccounts); - return std::make_tuple(initialState, out, changeLog); + return std::make_tuple(initialState, out.second.log(), changeLog); } catch (Exception const& _e) { @@ -231,8 +238,7 @@ std::tuple ImportTest::execu } initialState.commit(State::CommitBehaviour::KeepEmptyAccounts); - ExecOutput emptyOutput(std::make_pair(eth::ExecutionResult(), eth::TransactionReceipt(h256(), u256(), eth::LogEntries()))); - return std::make_tuple(initialState, emptyOutput, initialState.changeLog()); + return std::make_tuple(initialState, eth::LogEntries(), initialState.changeLog()); } json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o, bool _isHeader) @@ -323,7 +329,7 @@ void ImportTest::importState(json_spirit::mObject const& _o, State& _state) BOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); } -void ImportTest::importTransaction (json_spirit::mObject const& _o, eth::Transaction& o_tr) +void ImportTest::importTransaction(json_spirit::mObject const& _o, eth::Transaction& o_tr) { if (_o.count("secretKey") > 0) { @@ -379,7 +385,7 @@ void ImportTest::importTransaction (json_spirit::mObject const& _o, eth::Transac } } -void ImportTest::importTransaction(json_spirit::mObject const& o_tr) +void ImportTest::importFillerTransaction(json_spirit::mObject const& o_tr) { BOOST_REQUIRE(o_tr.count("gasLimit") > 0); size_t dataVectorSize = o_tr.at("data").get_array().size(); @@ -399,13 +405,29 @@ void ImportTest::importTransaction(json_spirit::mObject const& o_tr) o_tr_tmp["gasLimit"] = gas; o_tr_tmp["value"] = value; - importTransaction(o_tr_tmp, m_transaction); - - transactionToExecute execData(d, g, v, m_transaction); - m_transactions.push_back(execData); + eth::Transaction tx; + importTransaction(o_tr_tmp, tx); + m_transactions.emplace_back(d, g, v, tx); } } +void ImportTest::importPostStates(json_spirit::mObject const& _postStates) +{ + for (auto const& ns: _postStates) + { + for (auto const& postv: ns.second.get_array()) + { + auto post = postv.get_obj(); + auto ix = post["indexes"].get_obj(); + eth::Transaction rawtx(fromHex(post["tx"].get_str()), CheckTransaction::None); + transactionToExecute tx(ix["data"].get_int(), ix["gas"].get_int(), ix["value"].get_int(), rawtx); + tx.netId = ns.first; + tx.logs = importLog(post["logs"].get_array()); + m_transactions.push_back(tx); + } + } +} + int ImportTest::compareStates(State const& _stateExpect, State const& _statePost, AccountMaskMap const _expectedStateOptions, WhenError _throw) { bool wasError = false; @@ -644,14 +666,18 @@ void ImportTest::traceStateDiff() void ImportTest::exportTest() { + BOOST_REQUIRE(m_testObject.count("expect")); + + // Compute post state indexes that should be included. vector stateIndexesToPrint; - if (m_testObject.count("expect") > 0) - { - for (auto const& exp: m_testObject["expect"].get_array()) - checkGeneralTestSection(exp.get_obj(), stateIndexesToPrint); - m_testObject.erase(m_testObject.find("expect")); - } + for (auto const& exp: m_testObject["expect"].get_array()) + checkGeneralTestSection(exp.get_obj(), stateIndexesToPrint); + + // Remove filler-only fields. + m_testObject.erase("expect"); + m_testObject.erase("transaction"); + // Get the post states. json_spirit::mObject postStates; for(size_t i = 0; i < m_transactions.size(); i++) { @@ -663,8 +689,9 @@ void ImportTest::exportTest() json_spirit::mObject obj; obj["indexes"] = indexes; - obj["hash"] = toHex(tr.postState.rootHash().asBytes(), 2, HexPrefix::Add); - obj["logs"] = exportLog(tr.output.second.log()); + obj["hash"] = toHex(tr.postState.rootHash().ref(), 2, HexPrefix::Add); + obj["tx"] = toHex(tr.transaction.rlp(), 2, HexPrefix::Add); + obj["logs"] = exportLog(tr.logs); if (Options::get().checkstate) { auto it = std::find(std::begin(stateIndexesToPrint), std::end(stateIndexesToPrint), i); @@ -672,7 +699,9 @@ void ImportTest::exportTest() obj["postState"] = fillJsonWithState(tr.postState); } if (Options::get().statediff) + { obj["stateDiff"] = fillJsonWithStateChange(m_statePre, tr.postState, tr.changeLog); + } if (!postStates.count(tr.netId)) postStates[tr.netId] = json_spirit::mArray(); @@ -682,5 +711,4 @@ void ImportTest::exportTest() m_testObject["post"] = postStates; m_testObject["pre"] = fillJsonWithState(m_statePre); m_testObject["env"] = makeAllFieldsHex(m_testObject["env"].get_obj()); - m_testObject["transaction"] = makeAllFieldsHex(m_testObject["transaction"].get_obj()); } diff --git a/test/tools/libtesteth/ImportTest.h b/test/tools/libtesteth/ImportTest.h index 0fe1690a2cc..6eac0105125 100644 --- a/test/tools/libtesteth/ImportTest.h +++ b/test/tools/libtesteth/ImportTest.h @@ -35,11 +35,9 @@ class ImportTest ImportTest(json_spirit::mObject& _o); // imports - void importEnv(json_spirit::mObject& _o); static void importState(json_spirit::mObject const& _o, eth::State& _state); static void importState(json_spirit::mObject const& _o, eth::State& _state, eth::AccountMaskMap& o_mask); - static void importTransaction (json_spirit::mObject const& _o, eth::Transaction& o_tr); - void importTransaction(json_spirit::mObject const& _o); + static void importTransaction(json_spirit::mObject const& _o, eth::Transaction& o_tr); static json_spirit::mObject& makeAllFieldsHex(json_spirit::mObject& _o, bool _isHeader = false); static void parseJsonStrValueIntoVector(json_spirit::mValue const& _json, std::vector& _out); @@ -52,32 +50,36 @@ class ImportTest void checkGeneralTestSection(json_spirit::mObject const& _expects, std::vector& _errorTransactions, std::string const& _network="") const; void traceStateDiff(); - eth::State m_statePre; - eth::State m_statePost; - private: using ExecOutput = std::pair; - std::tuple executeTransaction(eth::Network const _sealEngineNetwork, eth::EnvInfo const& _env, eth::State const& _preState, eth::Transaction const& _tr); + std::tuple executeTransaction(eth::Network const _sealEngineNetwork, eth::EnvInfo const& _env, eth::State const& _preState, eth::Transaction const& _tr); + + void importEnv(json_spirit::mObject&); + void importFillerTransaction(json_spirit::mObject const&); + void importPostStates(json_spirit::mObject const&); std::unique_ptr m_lastBlockHashes; std::unique_ptr m_envInfo; - eth::Transaction m_transaction; + eth::State m_statePre; //General State Tests struct transactionToExecute { transactionToExecute(int d, int g, int v, eth::Transaction const& t): - dataInd(d), gasInd(g), valInd(v), transaction(t), postState(0), netId(""), - output(std::make_pair(eth::ExecutionResult(), eth::TransactionReceipt(h256(), u256(), eth::LogEntries()))) {} + netId(""), dataInd(d), gasInd(g), valInd(v), transaction(t), logs(eth::LogEntries()), + postState(0), changeLog(eth::ChangeLog()) {} + // fields used in filler and actual test: + std::string netId; int dataInd; int gasInd; int valInd; eth::Transaction transaction; + eth::LogEntries logs; + // filler-only fields: eth::State postState; eth::ChangeLog changeLog; - std::string netId; - ExecOutput output; }; + std::vector m_transactions; using StateAndMap = std::pair; using TrExpectSection = std::pair;