diff --git a/CMakeLists.txt b/CMakeLists.txt index e99aba558..30fa4058e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,8 @@ HunterGate( LOCAL ) -project(retesteth VERSION 0.0.9) -set(VERSION_SUFFIX "berlin") +project(retesteth VERSION 0.1.0) +set(VERSION_SUFFIX "accesslist") set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) diff --git a/Dockerfile b/Dockerfile index e3d65b70c..9d06c0d2d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,8 +40,8 @@ RUN apt-get install wget && wget https://github.com/ethereum/solidity/releases/d # Geth RUN git clone --depth 1 -b master https://github.com/ethereum/go-ethereum.git /geth RUN cd /geth && apt-get install wget \ - && wget https://dl.google.com/go/go1.13.3.linux-amd64.tar.gz \ - && tar -xvf go1.13.3.linux-amd64.tar.gz \ + && wget https://dl.google.com/go/go1.15.7.linux-amd64.tar.gz \ + && tar -xvf go1.15.7.linux-amd64.tar.gz \ && mv go /usr/local && ln -s /usr/local/go/bin/go /bin/go \ && make all && cp /geth/build/bin/evm /bin/evm \ && cp /geth/build/bin/geth /bin/geth \ diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 9f26e2233..e330c2834 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -36,7 +36,7 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA add_compile_options(-Wno-unknown-pragmas) # Configuration-specific compiler settings. - set(CMAKE_CXX_FLAGS_DEBUG "-Og -pg -DETH_DEBUG") + set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") diff --git a/retesteth/Options.cpp b/retesteth/Options.cpp index ec42db51d..62d6bde5a 100644 --- a/retesteth/Options.cpp +++ b/retesteth/Options.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,7 @@ void printHelp() cout << setw(40) << "--singletest " << setw(0) << "Run on a single test. `Testname` is filename without Filler.json\n"; cout << setw(40) << "--singletest /" << setw(0) << "`Subtest` is a test name inside the file\n"; + cout << setw(40) << "--singlenet " << setw(0) << "Run only specific fork configuration\n"; cout << "\nDebugging\n"; cout << setw(30) << "-d " << setw(25) << "Set the transaction data array index when running GeneralStateTests\n"; @@ -331,7 +333,22 @@ Options::Options(int argc, const char** argv) else if (arg == "-d") { throwIfNoArgumentFollows(); - trDataIndex = atoi(argv[++i]); + string const& argValue = argv[++i]; + DigitsType type = stringIntegerType(argValue); + switch (type) + { + case DigitsType::Decimal: + trDataIndex = atoi(argValue.c_str()); + break; + case DigitsType::String: + trDataLabel = argValue; + break; + default: + { + ETH_STDERROR_MESSAGE("Wrong argument format: " + argValue); + exit(0); + } + } } else if (arg == "-g") { @@ -476,3 +493,12 @@ void displayTestSuites() cout << "\n"; } +string Options::getGStateTransactionFilter() const +{ + string filter; + filter += trDataIndex == -1 ? string() : " dInd: " + to_string(trDataIndex); + filter += trDataLabel.empty() ? string() : " dLbl: " + trDataLabel; + filter += trGasIndex == -1 ? string() : " gInd: " + to_string(trGasIndex); + filter += trValueIndex == -1 ? string() : " vInd: " + to_string(trValueIndex); + return filter; +} diff --git a/retesteth/Options.h b/retesteth/Options.h index ddbcac1ba..36945ebcd 100644 --- a/retesteth/Options.h +++ b/retesteth/Options.h @@ -70,6 +70,7 @@ class Options std::string singleTestName; // A test name (usually a file.json test) std::string singleSubTestName; // A test name inside a file.json (for blockchain tests) std::string singleTestNet; + std::string trDataLabel; ///< GeneralState data int trDataIndex; ///< GeneralState data int trGasIndex; ///< GeneralState gas int trValueIndex; ///< GeneralState value @@ -82,6 +83,7 @@ class Options /// The first time used, options are parsed with argc, argv static Options const& get(int argc = 0, const char** argv = 0); static DynamicOptions& getDynamicOptions() { return m_dynamicOptions; } + string getGStateTransactionFilter() const; private: Options(int argc = 0, const char** argv = 0); diff --git a/retesteth/TestHelper.cpp b/retesteth/TestHelper.cpp index 4e57ce06c..f815648d7 100644 --- a/retesteth/TestHelper.cpp +++ b/retesteth/TestHelper.cpp @@ -175,6 +175,47 @@ vector levenshteinDistance(std::string const& _needle, std::vector lock(g_strFindMutex); // string.find is not thread safe + static + for (size_t i = _wasPrefix ? 2 : 0; i < _string.length(); i++) + { + if (!isxdigit(_string[i])) + return DigitsType::String; + + if (isDecimalOnly && !isdigit(_string[i])) + isDecimalOnly = false; + } + + if (isDecimalOnly) + return DigitsType::Decimal; + + if (_string.size() % 2 == 0) + return DigitsType::Hex; + + return DigitsType::UnEvenHex; +} + void parseJsonStrValueIntoSet(DataObject const& _json, set& _out) { if (_json.type() == DataType::Array) @@ -194,12 +235,40 @@ void parseJsonStrValueIntoSet(DataObject const& _json, set& _out) void parseJsonIntValueIntoSet(DataObject const& _json, set& _out) { + auto parseRange = [&_out](DataObject const& a) { + string const& s = a.asString(); + size_t delimeter = s.find('-'); + if (delimeter != string::npos) + { + string const firstPartString = s.substr(0, delimeter); + if (stringIntegerType(firstPartString) != DigitsType::Decimal) + ETH_ERROR_MESSAGE("parseJsonIntValueIntoSet require x to be decimal in `x-y` range! `" + firstPartString); + + string const secondPartString = s.substr(delimeter + 1); + if (stringIntegerType(secondPartString) != DigitsType::Decimal) + ETH_ERROR_MESSAGE("parseJsonIntValueIntoSet require y to be decimal in `x-y` range! `" + secondPartString); + + size_t const indexStart = atoi(firstPartString.c_str()); + size_t const indexEnd = atoi(secondPartString.c_str()); + for (size_t i = indexStart; i <= indexEnd; i++) + _out.emplace(i); + } + else + ETH_ERROR_MESSAGE("parseJsonIntValueIntoSet: Error parsing integer range string! format: \"x-y\", got: `" + s); + }; + if (_json.type() == DataType::Array) { for (auto const& val: _json.getSubObjects()) { - ETH_ERROR_REQUIRE_MESSAGE(val.type() == DataType::Integer, "parseJsonIntValueIntoSet expected value type = int!"); - _out.emplace(val.asInt()); + if (val.type() == DataType::Integer) + _out.emplace(val.asInt()); + else + { + ETH_ERROR_REQUIRE_MESSAGE( + val.type() == DataType::String, "parseJsonIntValueIntoSet expected value type = int, \"int-int\" range!"); + parseRange(val); + } } } else if (_json.type() == DataType::Integer) @@ -207,6 +276,11 @@ void parseJsonIntValueIntoSet(DataObject const& _json, set& _out) ETH_ERROR_REQUIRE_MESSAGE(_json.type() == DataType::Integer, "parseJsonIntValueIntoSet expected json type = int!"); _out.emplace(_json.asInt()); } + else if (_json.type() == DataType::String) + { + // Try to parse range into values "x-y" + parseRange(_json); + } } string prepareVersionString() diff --git a/retesteth/TestHelper.h b/retesteth/TestHelper.h index e4ae80679..a64efe169 100644 --- a/retesteth/TestHelper.h +++ b/retesteth/TestHelper.h @@ -9,6 +9,7 @@ #include #include #include +#include using namespace dataobject; namespace fs = boost::filesystem; @@ -94,6 +95,18 @@ bool inArray(std::list const& _array, const T& _val) /// Explode string into array of strings by `delim` std::vector explode(std::string const& s, char delim); +/// See what kind of a string is str +enum class DigitsType +{ + Decimal, + Hex, + UnEvenHex, + HexPrefixed, + UnEvenHexPrefixed, + String +}; +DigitsType stringIntegerType(std::string const& _string, bool _wasPrefix = false); + /// popen with pid at return enum popenOutput { @@ -114,5 +127,4 @@ string fto_string(t _val) { return std::to_string(_val); } - } // namespace test diff --git a/retesteth/TestOutputHelper.cpp b/retesteth/TestOutputHelper.cpp index 9f9ab4fea..0bf5bf181 100644 --- a/retesteth/TestOutputHelper.cpp +++ b/retesteth/TestOutputHelper.cpp @@ -399,5 +399,9 @@ std::string TestInfo::errorDebug() const message += ", block: " + to_string(m_blockNumber); else if (m_isStateTransactionInfo) message += ", TrInfo: d: " + to_string(m_trD) + ", g: " + to_string(m_trG) + ", v: " + to_string(m_trV); - return message + ")" + cRed; + + if (!m_sTransactionData.empty()) + message += ", TrData: `" + m_sTransactionData + "`"; + + return message + ")" + cDefault; } diff --git a/retesteth/TestOutputHelper.h b/retesteth/TestOutputHelper.h index 11f96c312..253ceae25 100644 --- a/retesteth/TestOutputHelper.h +++ b/retesteth/TestOutputHelper.h @@ -58,14 +58,15 @@ struct TestInfo TestInfo(): m_isStateTransactionInfo(false), m_isBlockchainTestInfo(false) {} std::string errorDebug() const; - static std::string caseName() - { - return boost::unit_test::framework::current_test_case().p_name; - } + static std::string caseName() { return boost::unit_test::framework::current_test_case().p_name; } + + void setTrDataDebug(std::string const& _data) { m_sTransactionData = _data; } private: std::string m_sFork, m_sChainName; std::string m_currentTestCaseName; + std::string m_sTransactionData; + int m_trD, m_trG, m_trV; size_t m_blockNumber; bool m_isStateTransactionInfo = false; diff --git a/retesteth/TestSuite.cpp b/retesteth/TestSuite.cpp index 4eaa1f031..e6f2960c8 100644 --- a/retesteth/TestSuite.cpp +++ b/retesteth/TestSuite.cpp @@ -111,20 +111,24 @@ void addClientInfo(DataObject& _v, fs::path const& _testSource, h256 const& _tes { string comment; DataObject clientinfo; + clientinfo.setKey("_info"); if (o.count("_info")) { DataObject const& existingInfo = o.atKey("_info"); if (existingInfo.count("comment")) comment = existingInfo.atKey("comment").asString(); + if (existingInfo.count("labels")) + clientinfo["labels"] = existingInfo.atKey("labels"); } - 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); + if (clientinfo.count("labels")) + clientinfo.setKeyPos("labels", clientinfo.getSubObjects().size() - 1); o["_info"].replace(clientinfo); o.setKeyPos("_info", 0); @@ -224,6 +228,8 @@ void TestSuite::runTestWithoutFiller(boost::filesystem::path const& _file) const if (Options::get().filltests) { TestFileData testData = readTestFile(_file); + removeComments(testData.data); + string fileName = _file.stem().c_str(); if (fileName.find("Filler") == string::npos) ETH_ERROR_MESSAGE("Trying to fill `" + string(_file.c_str()) + "`, but file does not have Filler suffix!"); @@ -261,9 +267,7 @@ string TestSuite::checkFillerExistance(string const& _testFolder) const string const testNameFilter = opt.singleTestName.empty() ? string() : opt.singleTestName; string filter = testNameFilter; filter += opt.singleTestNet.empty() ? string() : " " + opt.singleTestNet; - filter += opt.trDataIndex == -1 ? string() : " dInd: " + to_string(opt.trDataIndex); - filter += opt.trGasIndex == -1 ? string() : " gInd: " + to_string(opt.trGasIndex); - filter += opt.trValueIndex == -1 ? string() : " vInd: " + to_string(opt.trValueIndex); + filter += opt.getGStateTransactionFilter(); ETH_LOG("Checking test filler hashes for " + boost::unit_test::framework::current_test_case().full_name(), 4); if (!filter.empty()) ETH_LOG("Filter: '" + filter + "'", 0); @@ -276,6 +280,32 @@ string TestSuite::checkFillerExistance(string const& _testFolder) const vector compiledFiles = test::getFiles(testsPath.path(), {".json", ".yml"}, testNameFilter); AbsoluteFillerPath fullPathToFillers = getFullPathFiller(_testFolder); + // Check unfilled tests + if (Options::get().checkhash) + { + vector fillerFiles = test::getFiles(fullPathToFillers.path(), {".json", ".yml"}, testNameFilter); + if (fillerFiles.size() > compiledFiles.size()) + { + string message = "Tests are not generated: "; + for (auto const& filler : fillerFiles) + { + bool found = false; + for (auto const& filled : compiledFiles) + { + string const fillerName = filler.stem().string(); + if (fillerName.substr(0, fillerName.size() - 6) == filled.stem().string()) + { + found = true; + break; + } + } + if (!found) + message += "\n " + string(filler.c_str()); + } + ETH_ERROR_MESSAGE(message + "\n"); + } + } + bool checkFillerWhenFilterIsSetButNoTestsFilled = false; if (compiledFiles.size() == 0) { @@ -370,6 +400,7 @@ void TestSuite::runAllTestsInFolder(string const& _testFolder) const string filter; try { + TestOutputHelper::get().setCurrentTestInfo(TestInfo("checkFillerExistance", _testFolder)); filter = checkFillerExistance(_testFolder); } catch (std::exception const&) @@ -544,6 +575,12 @@ void TestSuite::executeTest(string const& _testFolder, fs::path const& _testFile // Add client info for all of the tests in output addClientInfo(output, boostRelativeTestPath, testData.hash); writeFile(boostTestPath.path(), asBytes(output.asJson())); + + if (!Options::get().getGStateTransactionFilter().empty()) + { + ETH_WARNING("GState transaction filter is set. Disabling generated test run!"); + opt.disableSecondRun = true; + } } catch (test::EthError const& _ex) { @@ -606,6 +643,10 @@ void TestSuite::executeFile(boost::filesystem::path const& _file) const TestSuiteOptions opt; opt.isLegacyTests = Options::get().rCurrentTestSuite.find("LegacyTests") != string::npos; opt.isLegacyTests = opt.isLegacyTests || legacyTestSuiteFlag(); + + if (_file.extension() != ".json") + ETH_ERROR_MESSAGE("The generated test must have `.json` format!"); + doTests(test::readJsonData(_file), opt); } } diff --git a/retesteth/compiler/Compiler.cpp b/retesteth/compiler/Compiler.cpp index 568898b22..856be56aa 100644 --- a/retesteth/compiler/Compiler.cpp +++ b/retesteth/compiler/Compiler.cpp @@ -20,11 +20,20 @@ string compileLLL(string const& _code) fs::path path(fs::temp_directory_path() / fs::unique_path()); string cmd = string("lllc ") + path.string(); writeFile(path.string(), _code); - string result = executeCmd(cmd); - fs::remove_all(path); - result = "0x" + result; - test::compiler::utiles::checkHexHasEvenLength(result); - return result; + try + { + string result = executeCmd(cmd); + fs::remove_all(path); + result = "0x" + result; + test::compiler::utiles::checkHexHasEvenLength(result); + return result; + } + catch (EthError const& _ex) + { + fs::remove_all(path); + ETH_WARNING("Error compiling lll code: " + _code.substr(0, 50) + ".."); + throw _ex; + } #endif } } // namespace @@ -54,7 +63,8 @@ string replaceCode(string const& _code, solContracts const& _preSolidity) { utiles::checkHexHasEvenLength(_code); if (Options::get().filltests && _code.size() > 2) - ETH_WARNING("Filling raw bytecode, please provide the source!" + TestOutputHelper::get().testInfo().errorDebug()); + ETH_WARNING("Filling raw bytecode ('" + _code.substr(0, 10) + "..'), please provide the source!" + + TestOutputHelper::get().testInfo().errorDebug()); return _code; } @@ -62,6 +72,7 @@ string replaceCode(string const& _code, solContracts const& _preSolidity) string const c_rawPrefix = ":raw"; string const c_abiPrefix = ":abi"; string const c_solidityPrefix = ":solidity"; + if (_code.find("pragma solidity") != string::npos) { solContracts const contracts = compileSolidity(_code); diff --git a/retesteth/configs/Options.h b/retesteth/configs/Options.h index 56932b506..a879ae1ee 100644 --- a/retesteth/configs/Options.h +++ b/retesteth/configs/Options.h @@ -9,7 +9,6 @@ extern dataobject::DataObject map_configs; class alethcfg { public: alethcfg(); }; class alethIpcDebugcfg { public: alethIpcDebugcfg(); }; class besucfg { public: besucfg(); }; -class gethcfg { public: gethcfg(); }; class t8ntoolcfg { public: t8ntoolcfg(); }; // Genesis configs for clients @@ -41,7 +40,6 @@ class OptionsInit alethcfg aleth; alethIpcDebugcfg alethIpcDebug; besucfg besu; - gethcfg geth; t8ntoolcfg t8ntool; // Genesis configs for clients diff --git a/retesteth/configs/clientconfigs/geth.cpp b/retesteth/configs/clientconfigs/geth.cpp deleted file mode 100644 index 05923c840..000000000 --- a/retesteth/configs/clientconfigs/geth.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include -using namespace std; -using namespace dataobject; - -string const geth_config = R"({ - "name" : "Ethereum GO on TCP", - "socketType" : "tcp", - "socketAddress" : [ - "127.0.0.1:8545", - "127.0.0.1:8546", - "127.0.0.1:8547", - "127.0.0.1:8548", - "127.0.0.1:8549", - "127.0.0.1:8550", - "127.0.0.1:8551", - "127.0.0.1:8552" - ], - "initializeTime" : "1", - "forks" : [ - "Frontier", - "Homestead", - "EIP150", - "EIP158", - "Byzantium", - "Constantinople", - "ConstantinopleFix", - "Istanbul" - ], - "additionalForks" : [ - "FrontierToHomesteadAt5", - "HomesteadToEIP150At5", - "EIP158ToByzantiumAt5", - "HomesteadToDaoAt5", - "ByzantiumToConstantinopleFixAt5" - ], - "exceptions" : { - "ExtraDataTooBig" : "extra-data too long", - "InvalidDifficulty" : "invalid difficulty", - "InvalidDifficulty2" : "invalid difficulty", - "InvalidDifficulty_TooLarge" : "invalid difficulty", - "InvalidGasLimit" : "invalid gasLimit:", - "TooMuchGasUsed" : "invalid gasUsed:", - "TooMuchGasUsed2" : "invalid gasUsed:", - "InvalidNumber" : "invalid block number", - "InvalidTimestampEqualParent" : "timestamp equals parent's", - "InvalidTimestampOlderParent" : "timestamp older than parent", - "InvalidLogBloom" : "invalid bloom (remote:", - "InvalidStateRoot" : "invalid merkle root (remote:", - "InvalidGasLimit2" : "invalid gas limit:", - "InvalidGasUsed" : "invalid gas used (remote:", - "InvalidGasUsed2" : "invalid gas used (remote:", - "InvalidBlockMixHash" : "invalid mix digest", - "InvalidBlockNonce" : "", - "UnknownParent" : "unknown ancestor", - "UnknownParent2" : "unknown ancestor", - "InvalidReceiptsStateRoot" : "invalid receipt root hash (remote:", - "InvalidTransactionsRoot" : "transaction root hash mismatch: have", - "InvalidUnclesHash" : "uncle root hash mismatch: have", - "InvalidUncleParentHash" : "uncle's parent is not ancestor", - "UncleInChain" : "duplicate uncle", - "UncleIsAncestor" : "uncle is ancestor", - "UncleIsBrother" : "duplicate uncle", - "UncleParentIsNotAncestor" : "uncle's parent is not ancestor", - "TooManyUncles" : "too many uncles", - "OutOfGas" : "out of gas", - "IntrinsicGas" : "intrinsic gas too low", - "ExtraDataIncorrectDAO" : "bad DAO pro-fork extra-data", - "InvalidTransactionVRS" : "invalid transaction v, r, s values", - "BLOCKHEADER_VALUE_TOOLARGE" : "Blockheader parse error: VALUE >u256", - "TRANSACTION_VALUE_TOOLARGE" : "transaction root hash mismatch: have", - "TRANSACTION_VALUE_TOOSHORT" : "transaction root hash mismatch: have", - "OVERSIZE_RLP" : "Error importing raw rlp block: OversizeRLP", - "RLP_InputContainsMoreThanOneValue" : "rlp: input contains more than one value", - "RLP_VALUESIZE_MORE_AVAILABLEINPUTLENGTH" : "rlp: value size exceeds available input length", - "RLP_ELEMENT_LARGER_CONTAININGLIST_UNDERSIZE" : "rlp: element is larger than containing list", - "RLP_ELEMENT_LARGER_CONTAININGLIST_OVERSIZE" : "rlp: element is larger than containing list", - "RLP_ExpectedInputList_EXTBLOCK" : "rlp: expected input list for types.extblock", - "RLP_InvalidArg0_UNMARSHAL_BYTES" : "invalid argument 0: json: cannot unmarshal invalid hex string into Go value of type hexutil.Bytes", - "RLP_ExpectedInputList_HEADER_DECODEINTO_BLOCK_EXTBLOCK" : "rlp: expected input list for types.Header, decoding into (types.Block)(types.extblock).Header", - "RLP_InputList_TooManyElements_HEADER_DECODEINTO_BLOCK_EXTBLOCK_HEADER" : "rlp: input list has too many elements for types.Header, decoding into (types.Block)(types.extblock).Header", - "RLP_InputList_TooManyElements_TXDATA_DECODEINTO_BLOCK_EXTBLOCK_TXS0" : "rlp: input list has too many elements for types.txdata, decoding into (types.Block)(types.extblock).Txs[0]", - "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "rlp: input string too short for common.Address, decoding into (types.Block)(types.extblock).Header.Coinbase", - "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE2" : "rlp: input string too short for common.Address, decoding into (types.Block)(types.extblock).Header.Coinbase", - "RLP_InputString_TooShort_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TXS0_RECIPIENT" : "rlp: input string too short for common.Address, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).Recipient", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.Root", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT2" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.Root", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.MixDigest", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST2" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.MixDigest", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.ParentHash", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH2" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.ParentHash", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.ReceiptHash", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH2" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.ReceiptHash", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.TxHash", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.UncleHash", - "RLP_InputString_TooLong_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH2" : "rlp: input string too long for common.Hash, decoding into (types.Block)(types.extblock).Header.UncleHash", - "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "rlp: input string too long for uint64, decoding into (types.Block)(types.extblock).Header.GasLimit", - "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "rlp: input string too long for uint64, decoding into (types.Block)(types.extblock).Header.GasUsed", - "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "rlp: input string too long for uint64, decoding into (types.Block)(types.extblock).Header.Time", - "RLP_InputString_TooLong_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "rlp: input string too long for uint64, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).GasLimit", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.ReceiptHash", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH2" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.ReceiptHash", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.Root", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.MixDigest", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST2" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.MixDigest", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.ParentHash", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH2" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.ParentHash", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.UncleHash", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH2" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.UncleHash", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.TxHash", - "RLP_InputString_TooShort_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH2" : "rlp: input string too short for common.Hash, decoding into (types.Block)(types.extblock).Header.TxHash", - "RLP_InputString_TooShort_BLOOM_DECODEINTO_BLOCK_EXTBLOCK_HEADER_BLOOM" : "rlp: input string too short for types.Bloom, decoding into (types.Block)(types.extblock).Header.Bloom", - "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Block)(types.extblock).Header.Difficulty", - "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY2" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Block)(types.extblock).Header.Difficulty", - "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Block)(types.extblock).Header.GasLimit", - "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT2" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Block)(types.extblock).Header.GasLimit", - "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Block)(types.extblock).Header.GasUsed", - "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED2" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Block)(types.extblock).Header.GasUsed", - "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Block)(types.extblock).Header.Time", - "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME2" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Block)(types.extblock).Header.Time", - "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).GasLimit", - "RLP_NonCanonicalINT_LeadingZeros_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT2" : "rlp: non-canonical integer (leading zero bytes) for uint64, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).GasLimit", - "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NUMBER" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Block)(types.extblock).Header.Number", - "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NUMBER2" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Block)(types.extblock).Header.Number", - "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_PRICE" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).Price", - "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_R" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).R", - "RLP_NonCanonicalINT_LeadingZeros_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXDATA_S" : "rlp: non-canonical integer (leading zero bytes) for *big.Int, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).S", - "RLP_InputString_TooLong_BLOOM_DECODEINTO_BLOCK_EXTBLOCK_HEADER_BLOOM" : "rlp: input string too long for types.Bloom, decoding into (types.Block)(types.extblock).Header.Bloom", - "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_PARENTHASH" : "rlp: expected input string or byte for common.Hash, decoding into (types.Block)(types.extblock).Header.ParentHash", - "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_RECEIPTHASH" : "rlp: expected input string or byte for common.Hash, decoding into (types.Block)(types.extblock).Header.ReceiptHash", - "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_ROOT" : "rlp: expected input string or byte for common.Hash, decoding into (types.Block)(types.extblock).Header.Root", - "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_MIXDIGEST" : "rlp: expected input string or byte for common.Hash, decoding into (types.Block)(types.extblock).Header.MixDigest", - "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TXHASH" : "rlp: expected input string or byte for common.Hash, decoding into (types.Block)(types.extblock).Header.TxHash", - "RLP_ExpectedInputString_HASH_DECODEINTO_BLOCK_EXTBLOCK_HEADER_UNCLEHASH" : "rlp: expected input string or byte for common.Hash, decoding into (types.Block)(types.extblock).Header.UncleHash", - "RLP_ExpectedInputString_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "rlp: expected input string or byte for common.Address, decoding into (types.Block)(types.extblock).Header.Coinbase", - "RLP_ExpectedInputString_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TX0_RECIPIENT" : "rlp: expected input string or byte for common.Address, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).Recipient", - "RLP_InputString_TooLong_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_HEADER_COINBASE" : "rlp: input string too long for common.Address, decoding into (types.Block)(types.extblock).Header.Coinbase", - "RLP_InputString_TooLong_ADDRESS_DECODEINTO_BLOCK_EXTBLOCK_TXS0_RECIPIENT" : "rlp: input string too long for common.Address, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).Recipient", - "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_HEADER_DIFFICULTY" : "rlp: expected input string or byte for *big.Int, decoding into (types.Block)(types.extblock).Header.Difficulty", - "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXR" : "rlp: expected input string or byte for *big.Int, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).R", - "RLP_ExpectedInputString_BIGINT_DECODEINTO_BLOCK_EXTBLOCK_TXS0_TXS" : "rlp: expected input string or byte for *big.Int, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).S", - "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASLIMIT" : "rlp: expected input string or byte for uint64, decoding into (types.Block)(types.extblock).Header.GasLimit", - "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_GASUSED" : "rlp: expected input string or byte for uint64, decoding into (types.Block)(types.extblock).Header.GasUsed", - "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_HEADER_TIME" : "rlp: expected input string or byte for uint64, decoding into (types.Block)(types.extblock).Header.Time", - "RLP_ExpectedInputString_UINT64_DECODEINTO_BLOCK_EXTBLOCK_TXS0_GASLIMIT" : "rlp: expected input string or byte for uint64, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).GasLimit", - "RLP_ExpectedInputString_NONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE" : "rlp: expected input string or byte for types.BlockNonce, decoding into (types.Block)(types.extblock).Header.Nonce", - "RLP_ExpectedInputString_UINT8_DECODEINTO_BLOCK_EXTBLOCK_TXS0_PAYLOAD" : "rlp: expected input string or byte for []uint8, decoding into (types.Block)(types.extblock).Txs[0](types.txdata).Payload", - "RLP_InputString_TooLong_BLOCKNONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE" : "rlp: input string too long for types.BlockNonce, decoding into (types.Block)(types.extblock).Header.Nonce", - "RLP_InputString_TooLong_BLOCKNONCE_DECODEINTO_BLOCK_EXTBLOCK_HEADER_NONCE2" : "rlp: input string too long for types.BlockNonce, decoding into (types.Block)(types.extblock).Header.Nonce", - "RLP_NonCanonical_SizeInfo_EXTBLOCK" : "rlp: non-canonical size information for types.extblock", - "RLP_ExpectedInputList_TRANSACTION_DECODEINTO_BLOCK_EXTBLOCK_TXS" : "rlp: expected input list for []*types.Transaction, decoding into (types.Block)(types.extblock).Txs", - "RLP_ExpectedInputList_HEADER_DECODEINTO_BLOCK_EXTBLOCK_UNCLES" : "rlp: expected input list for []*types.Header, decoding into (types.Block)(types.extblock).Uncles", - "RLP_ExpectedInputList_TXDATA_DECODEINTO_BLOCK_EXTBLOCK_TXS0" : "rlp: expected input list for types.txdata, decoding into (types.Block)(types.extblock).Txs[0]" - } -})"; - -string const geth_start = R"(#!/bin/sh -threads=1 -if [ "${1:-0}" -gt 1 ] -then - threads=$1 -fi - -i=0 -while [ "$i" -lt $threads ]; do - geth retesteth --rpcport $((8545+$i)) & - i=$(( i + 1 )) -done -)"; - -string const geth_stop = R"(#!/bin/sh -killall geth -)"; - -gethcfg::gethcfg() -{ - { - DataObject obj; - obj["path"] = "default/config"; - obj["content"] = geth_config; - map_configs.addArrayObject(obj); - } - { - DataObject obj; - obj["exec"] = true; - obj["path"] = "default/start.sh"; - obj["content"] = geth_start; - map_configs.addArrayObject(obj); - } - { - DataObject obj; - obj["exec"] = true; - obj["path"] = "default/stop.sh"; - obj["content"] = geth_stop; - map_configs.addArrayObject(obj); - } - - { - DataObject obj; - obj["path"] = "geth/config"; - obj["content"] = geth_config; - map_configs.addArrayObject(obj); - } - { - DataObject obj; - obj["exec"] = true; - obj["path"] = "geth/start.sh"; - obj["content"] = geth_start; - map_configs.addArrayObject(obj); - } - { - DataObject obj; - obj["exec"] = true; - obj["path"] = "geth/stop.sh"; - obj["content"] = geth_stop; - map_configs.addArrayObject(obj); - } -} diff --git a/retesteth/configs/clientconfigs/t8ntool.cpp b/retesteth/configs/clientconfigs/t8ntool.cpp index 07554c8e0..87a138700 100644 --- a/retesteth/configs/clientconfigs/t8ntool.cpp +++ b/retesteth/configs/clientconfigs/t8ntool.cpp @@ -149,7 +149,7 @@ string const t8ntool_start = R"(#!/bin/sh if [ $1 = "-v" ]; then /bin/evm -v else - /bin/evm t8n $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 + /bin/evm t8n $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $20 --verbosity 2 fi )"; @@ -168,4 +168,17 @@ t8ntoolcfg::t8ntoolcfg() obj["content"] = t8ntool_start; map_configs.addArrayObject(obj); } + { + DataObject obj; + obj["path"] = "default/config"; + obj["content"] = t8ntool_config; + map_configs.addArrayObject(obj); + } + { + DataObject obj; + obj["exec"] = true; + obj["path"] = "default/start.sh"; + obj["content"] = t8ntool_start; + map_configs.addArrayObject(obj); + } } diff --git a/retesteth/configs/genesis/default/Berlin.cpp b/retesteth/configs/genesis/default/Berlin.cpp index a12c0a63c..e1091e916 100644 --- a/retesteth/configs/genesis/default/Berlin.cpp +++ b/retesteth/configs/genesis/default/Berlin.cpp @@ -21,7 +21,7 @@ const string default_Berlin_config = R"({ const string t8ntool_Berlin_config = R"({ "params" : { - "fork" : "YOLOv2", + "fork" : "YOLOv3", "constantinopleForkBlock" : "0x00", "byzantiumForkBlock" : "0x00", "homesteadForkBlock" : "0x00" @@ -33,12 +33,12 @@ const string t8ntool_Berlin_config = R"({ genBerlinCfg::genBerlinCfg() { DataObject obj; - obj["path"] = "default/genesis/Berlin.json"; + obj["path"] = "besu/genesis/Berlin.json"; obj["content"] = default_Berlin_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/Berlin.json"; + obj2["path"] = "default/genesis/Berlin.json"; obj2["content"] = t8ntool_Berlin_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/Byzantium.cpp b/retesteth/configs/genesis/default/Byzantium.cpp index 4196a35ab..a3fe9a703 100644 --- a/retesteth/configs/genesis/default/Byzantium.cpp +++ b/retesteth/configs/genesis/default/Byzantium.cpp @@ -27,12 +27,12 @@ const string t8ntool_Byzantium_config = R"({ genByzantiumCfg::genByzantiumCfg() { DataObject obj; - obj["path"] = "default/genesis/Byzantium.json"; + obj["path"] = "besu/genesis/Byzantium.json"; obj["content"] = default_Byzantium_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/Byzantium.json"; + obj2["path"] = "default/genesis/Byzantium.json"; obj2["content"] = t8ntool_Byzantium_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/ByzantiumToConstantinopleFixAt5.cpp b/retesteth/configs/genesis/default/ByzantiumToConstantinopleFixAt5.cpp index 2f28cb9e0..d0486f0b2 100644 --- a/retesteth/configs/genesis/default/ByzantiumToConstantinopleFixAt5.cpp +++ b/retesteth/configs/genesis/default/ByzantiumToConstantinopleFixAt5.cpp @@ -30,12 +30,12 @@ const string t8ntool_ByzantiumToConstantinopleFixAt5_config = R"({ genByzantiumToConstantinopleFixCfg::genByzantiumToConstantinopleFixCfg() { DataObject obj; - obj["path"] = "default/genesis/ByzantiumToConstantinopleFixAt5.json"; + obj["path"] = "besu/genesis/ByzantiumToConstantinopleFixAt5.json"; obj["content"] = default_ByzantiumToConstantinopleFixAt5_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/ByzantiumToConstantinopleFixAt5.json"; + obj2["path"] = "default/genesis/ByzantiumToConstantinopleFixAt5.json"; obj2["content"] = t8ntool_ByzantiumToConstantinopleFixAt5_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/Constantinople.cpp b/retesteth/configs/genesis/default/Constantinople.cpp index 9c01fe2ae..d15a259bc 100644 --- a/retesteth/configs/genesis/default/Constantinople.cpp +++ b/retesteth/configs/genesis/default/Constantinople.cpp @@ -29,12 +29,12 @@ const string t8ntool_Constantinople_config = R"({ genConstantinopleCfg::genConstantinopleCfg() { DataObject obj; - obj["path"] = "default/genesis/Constantinople.json"; + obj["path"] = "besu/genesis/Constantinople.json"; obj["content"] = default_Constantinople_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/Constantinople.json"; + obj2["path"] = "default/genesis/Constantinople.json"; obj2["content"] = t8ntool_Constantinople_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/ConstantinopleFix.cpp b/retesteth/configs/genesis/default/ConstantinopleFix.cpp index 3571349d5..5eb4dffe7 100644 --- a/retesteth/configs/genesis/default/ConstantinopleFix.cpp +++ b/retesteth/configs/genesis/default/ConstantinopleFix.cpp @@ -30,12 +30,12 @@ const string t8ntool_ConstantinopleFix_config = R"({ genConstantinopleFixCfg::genConstantinopleFixCfg() { DataObject obj; - obj["path"] = "default/genesis/ConstantinopleFix.json"; + obj["path"] = "besu/genesis/ConstantinopleFix.json"; obj["content"] = default_ConstantinopleFix_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/ConstantinopleFix.json"; + obj2["path"] = "default/genesis/ConstantinopleFix.json"; obj2["content"] = t8ntool_ConstantinopleFix_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/EIP150.cpp b/retesteth/configs/genesis/default/EIP150.cpp index 88046c70b..0cf67a950 100644 --- a/retesteth/configs/genesis/default/EIP150.cpp +++ b/retesteth/configs/genesis/default/EIP150.cpp @@ -24,12 +24,12 @@ const string t8ntool_EIP150_config = R"({ genEIP150Cfg::genEIP150Cfg() { DataObject obj; - obj["path"] = "default/genesis/EIP150.json"; + obj["path"] = "besu/genesis/EIP150.json"; obj["content"] = default_EIP150_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/EIP150.json"; + obj2["path"] = "default/genesis/EIP150.json"; obj2["content"] = t8ntool_EIP150_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/EIP158.cpp b/retesteth/configs/genesis/default/EIP158.cpp index d8c2cb04f..0b77d9ac8 100644 --- a/retesteth/configs/genesis/default/EIP158.cpp +++ b/retesteth/configs/genesis/default/EIP158.cpp @@ -25,12 +25,12 @@ const string t8ntool_EIP158_config = R"({ genEIP158Cfg::genEIP158Cfg() { DataObject obj; - obj["path"] = "default/genesis/EIP158.json"; + obj["path"] = "besu/genesis/EIP158.json"; obj["content"] = default_EIP158_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/EIP158.json"; + obj2["path"] = "default/genesis/EIP158.json"; obj2["content"] = t8ntool_EIP158_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/EIP158ToByzantiumAt5.cpp b/retesteth/configs/genesis/default/EIP158ToByzantiumAt5.cpp index 5762166ce..c0d75ff0d 100644 --- a/retesteth/configs/genesis/default/EIP158ToByzantiumAt5.cpp +++ b/retesteth/configs/genesis/default/EIP158ToByzantiumAt5.cpp @@ -27,12 +27,12 @@ const string t8ntool_EIP158ToByzantiumAt5_config = R"({ genEIP158ToByzantiumCfg::genEIP158ToByzantiumCfg() { DataObject obj; - obj["path"] = "default/genesis/EIP158ToByzantiumAt5.json"; + obj["path"] = "besu/genesis/EIP158ToByzantiumAt5.json"; obj["content"] = default_EIP158ToByzantiumAt5_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/EIP158ToByzantiumAt5.json"; + obj2["path"] = "default/genesis/EIP158ToByzantiumAt5.json"; obj2["content"] = t8ntool_EIP158ToByzantiumAt5_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/Frontier.cpp b/retesteth/configs/genesis/default/Frontier.cpp index c83c6bcc8..30d84a4bf 100644 --- a/retesteth/configs/genesis/default/Frontier.cpp +++ b/retesteth/configs/genesis/default/Frontier.cpp @@ -21,12 +21,12 @@ const string t8ntool_Frontier_config = R"({ genFrontierCfg::genFrontierCfg() { DataObject obj; - obj["path"] = "default/genesis/Frontier.json"; + obj["path"] = "besu/genesis/Frontier.json"; obj["content"] = default_Frontier_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/Frontier.json"; + obj2["path"] = "default/genesis/Frontier.json"; obj2["content"] = t8ntool_Frontier_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/FrontierToHomesteadAt5.cpp b/retesteth/configs/genesis/default/FrontierToHomesteadAt5.cpp index 48348590c..55770d51b 100644 --- a/retesteth/configs/genesis/default/FrontierToHomesteadAt5.cpp +++ b/retesteth/configs/genesis/default/FrontierToHomesteadAt5.cpp @@ -23,12 +23,12 @@ const string t8ntool_FrontierToHomesteadAt5_config = R"({ genFrontierToHomesteadCfg::genFrontierToHomesteadCfg() { DataObject obj; - obj["path"] = "default/genesis/FrontierToHomesteadAt5.json"; + obj["path"] = "besu/genesis/FrontierToHomesteadAt5.json"; obj["content"] = default_FrontierToHomesteadAt5_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/FrontierToHomesteadAt5.json"; + obj2["path"] = "default/genesis/FrontierToHomesteadAt5.json"; obj2["content"] = t8ntool_FrontierToHomesteadAt5_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/Homestead.cpp b/retesteth/configs/genesis/default/Homestead.cpp index 4efa880ee..c53cc15b1 100644 --- a/retesteth/configs/genesis/default/Homestead.cpp +++ b/retesteth/configs/genesis/default/Homestead.cpp @@ -23,12 +23,12 @@ const string t8ntool_Homestead_config = R"({ genHomesteadCfg::genHomesteadCfg() { DataObject obj; - obj["path"] = "default/genesis/Homestead.json"; + obj["path"] = "besu/genesis/Homestead.json"; obj["content"] = default_Homestead_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/Homestead.json"; + obj2["path"] = "default/genesis/Homestead.json"; obj2["content"] = t8ntool_Homestead_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/HomesteadToDaoAt5.cpp b/retesteth/configs/genesis/default/HomesteadToDaoAt5.cpp index 13c3f640e..642530362 100644 --- a/retesteth/configs/genesis/default/HomesteadToDaoAt5.cpp +++ b/retesteth/configs/genesis/default/HomesteadToDaoAt5.cpp @@ -24,12 +24,12 @@ const string t8ntool_HomesteadToDaoAt5_config = R"({ genHomesteadToDaoCfg::genHomesteadToDaoCfg() { DataObject obj; - obj["path"] = "default/genesis/HomesteadToDaoAt5.json"; + obj["path"] = "besu/genesis/HomesteadToDaoAt5.json"; obj["content"] = default_HomesteadToDaoAt5_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/HomesteadToDaoAt5.json"; + obj2["path"] = "default/genesis/HomesteadToDaoAt5.json"; obj2["content"] = t8ntool_HomesteadToDaoAt5_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/HomesteadToEIP150At5.cpp b/retesteth/configs/genesis/default/HomesteadToEIP150At5.cpp index 212479212..156e957ff 100644 --- a/retesteth/configs/genesis/default/HomesteadToEIP150At5.cpp +++ b/retesteth/configs/genesis/default/HomesteadToEIP150At5.cpp @@ -24,12 +24,12 @@ const string t8ntool_HomesteadToEIP150At5_config = R"({ genHomesteadToEIP150Cfg::genHomesteadToEIP150Cfg() { DataObject obj; - obj["path"] = "default/genesis/HomesteadToEIP150At5.json"; + obj["path"] = "besu/genesis/HomesteadToEIP150At5.json"; obj["content"] = default_HomesteadToEIP150At5_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/HomesteadToEIP150At5.json"; + obj2["path"] = "default/genesis/HomesteadToEIP150At5.json"; obj2["content"] = t8ntool_HomesteadToEIP150At5_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/Istanbul.cpp b/retesteth/configs/genesis/default/Istanbul.cpp index 7a665ee00..fba679c02 100644 --- a/retesteth/configs/genesis/default/Istanbul.cpp +++ b/retesteth/configs/genesis/default/Istanbul.cpp @@ -32,12 +32,12 @@ const string t8ntool_Istanbul_config = R"({ genIstanbulCfg::genIstanbulCfg() { DataObject obj; - obj["path"] = "default/genesis/Istanbul.json"; + obj["path"] = "besu/genesis/Istanbul.json"; obj["content"] = default_Istanbul_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/Istanbul.json"; + obj2["path"] = "default/genesis/Istanbul.json"; obj2["content"] = t8ntool_Istanbul_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/configs/genesis/default/correctMiningReward.cpp b/retesteth/configs/genesis/default/correctMiningReward.cpp index 76227d9e2..9254b5ffd 100644 --- a/retesteth/configs/genesis/default/correctMiningReward.cpp +++ b/retesteth/configs/genesis/default/correctMiningReward.cpp @@ -30,18 +30,19 @@ const string t8ntool_correctMiningReward_config = R"({ "//comment" : "Retesteth calculate rewards on behalf of the tool when filling state tests", "YOLOv1" : "2000000000000000000", - "YOLOv2" : "2000000000000000000" + "YOLOv2" : "2000000000000000000", + "YOLOv3" : "2000000000000000000" })"; genRewardsCfg::genRewardsCfg() { DataObject obj; - obj["path"] = "default/genesis/correctMiningReward.json"; + obj["path"] = "besu/genesis/correctMiningReward.json"; obj["content"] = default_correctMiningReward_config; map_configs.addArrayObject(obj); DataObject obj2; - obj2["path"] = "t8ntool/genesis/correctMiningReward.json"; + obj2["path"] = "default/genesis/correctMiningReward.json"; obj2["content"] = t8ntool_correctMiningReward_config; map_configs.addArrayObject(obj2); } diff --git a/retesteth/dataObject/ConvertFile.cpp b/retesteth/dataObject/ConvertFile.cpp index 90096b860..6530181eb 100644 --- a/retesteth/dataObject/ConvertFile.cpp +++ b/retesteth/dataObject/ConvertFile.cpp @@ -237,8 +237,13 @@ DataObject ConvertJsoncppStringToData( { if (actualRoot->type() == DataType::Array || actualRoot->type() == DataType::Object) { - DataObject* newObj = &actualRoot->addSubObject(DataObject(DataType::Array)); - newObj->setAutosort(_autosort); + DataObject newObj(DataType::Array); + newObj.setAutosort(_autosort); + applyDepth.push_back(actualRoot); + actualRoot = &actualRoot->addSubObject(newObj); + + // DataObject* newObj = &actualRoot->addSubObject(DataObject(DataType::Array)); + // newObj->setAutosort(_autosort); continue; } diff --git a/retesteth/dataObject/DataObject.cpp b/retesteth/dataObject/DataObject.cpp index cb30be697..b4968520f 100644 --- a/retesteth/dataObject/DataObject.cpp +++ b/retesteth/dataObject/DataObject.cpp @@ -361,8 +361,8 @@ std::string DataObject::asJson(int level, bool pretty, bool nokey) const else out << "\"" << m_strKey << "\":"; } - //out << "\"" << "null" << "\""; - out << "{}"; + out << "null"; + //out << "{}"; // why??? break; case DataType::Object: if (!m_strKey.empty() && !nokey) diff --git a/retesteth/main.cpp b/retesteth/main.cpp index df5f18c63..0028f223d 100644 --- a/retesteth/main.cpp +++ b/retesteth/main.cpp @@ -127,7 +127,9 @@ int main(int argc, const char* argv[]) std::string arg = std::string{argv[i]}; if (arg == "-t" && i + 1 < argc && string(argv[i + 1]) == "UnitTests") { - argv[i + 1] = "LLLCSuite,SOLCSuite,DataObjectTestSuite,EthObjectsSuite,OptionsSuite,TestHelperSuite"; + argv[i + 1] = + "LLLCSuite,SOLCSuite,DataObjectTestSuite,EthObjectsSuite,OptionsSuite,TestHelperSuite,ExpectSectionSuite," + "trDataCompileSuite"; break; } } diff --git a/retesteth/session/RPCImpl.cpp b/retesteth/session/RPCImpl.cpp index 3d895c2d9..2a59a0833 100644 --- a/retesteth/session/RPCImpl.cpp +++ b/retesteth/session/RPCImpl.cpp @@ -25,13 +25,13 @@ FH32 RPCImpl::eth_sendRawTransaction(BYTES const& _rlp) return FH32(result); } -size_t RPCImpl::eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) +VALUE RPCImpl::eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) { DataObject const response = rpcCall("eth_getTransactionCount", {quote(_address.asString()), quote(_blockNumber.asString())}); if (response.type() == DataType::String) - return hexOrDecStringToInt(response.asString()); - return response.asInt(); + return VALUE(response); + return VALUE(response.asInt()); } VALUE RPCImpl::eth_blockNumber() diff --git a/retesteth/session/RPCImpl.h b/retesteth/session/RPCImpl.h index 3fccb75b9..d023aa378 100644 --- a/retesteth/session/RPCImpl.h +++ b/retesteth/session/RPCImpl.h @@ -13,7 +13,7 @@ class RPCImpl : public SessionInterface // ETH Methods FH32 eth_sendRawTransaction(BYTES const& _rlp) override; - size_t eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) override; + VALUE eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) override; VALUE eth_blockNumber() override; EthGetBlockBy eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) override; EthGetBlockBy eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) override; diff --git a/retesteth/session/SessionInterface.h b/retesteth/session/SessionInterface.h index 526e1e3a7..87061a526 100644 --- a/retesteth/session/SessionInterface.h +++ b/retesteth/session/SessionInterface.h @@ -43,7 +43,7 @@ class SessionInterface // ETH Methods virtual FH32 eth_sendRawTransaction(BYTES const& _rlp) = 0; - virtual size_t eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) = 0; + virtual VALUE eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) = 0; virtual VALUE eth_blockNumber() = 0; virtual EthGetBlockBy eth_getBlockByHash(FH32 const& _blockHash, Request _fullObjects) = 0; diff --git a/retesteth/session/ToolBackend/ToolChain.cpp b/retesteth/session/ToolBackend/ToolChain.cpp index 7828fdaf9..cd6d42a86 100644 --- a/retesteth/session/ToolBackend/ToolChain.cpp +++ b/retesteth/session/ToolBackend/ToolChain.cpp @@ -62,7 +62,7 @@ void ToolChain::mineBlock(EthereumBlockState const& _pendingBlock, Mining _req) for (auto const& tr : _pendingBlock.transactions()) { bool found = false; - FH32 const trHash = tr.hash(); + FH32 const trHash = tr.getCContent().hash(); for (auto const& trReceipt : res.receipts()) { if (trReceipt.trHash() == trHash) @@ -180,10 +180,11 @@ ToolResponse ToolChain::mineBlockOnTool(EthereumBlockState const& _block, SealEn static u256 c_maxGasLimit = u256("0xffffffffffffffff"); for (auto const& tr : _block.transactions()) { - if (tr.gasLimit().asU256() <= c_maxGasLimit) // tool fails on limits here. - txs.addArrayObject(tr.asDataObject(ExportOrder::ToolStyle)); + if (tr.getCContent().gasLimit().asU256() <= c_maxGasLimit) // tool fails on limits here. + txs.addArrayObject(tr.getCContent().asDataObject(ExportOrder::ToolStyle)); else - ETH_WARNING("Retesteth rejecting tx with gasLimit > 64 bits for tool"); + ETH_WARNING( + "Retesteth rejecting tx with gasLimit > 64 bits for tool" + TestOutputHelper::get().testInfo().errorDebug()); } writeFile(txsPath.string(), txs.asJson()); @@ -233,14 +234,15 @@ ToolResponse ToolChain::mineBlockOnTool(EthereumBlockState const& _block, SealEn { fs::path txTraceFile; string const trNumber = test::fto_string(i++); - txTraceFile = m_tmpDir / string("trace-" + trNumber + "-" + tr.hash().asString() + ".jsonl"); + txTraceFile = m_tmpDir / string("trace-" + trNumber + "-" + tr.getCContent().hash().asString() + ".jsonl"); if (fs::exists(txTraceFile)) { - string const preinfo = "\nTransaction number: " + trNumber + ", hash: " + tr.hash().asString() + "\n"; + string const preinfo = + "\nTransaction number: " + trNumber + ", hash: " + tr.getCContent().hash().asString() + "\n"; string const info = TestOutputHelper::get().testInfo().errorDebug(); string const traceinfo = "\nVMTrace:" + info + cDefault + preinfo; - toolResponse.attachDebugTrace( - tr.hash(), DebugVMTrace(traceinfo, trNumber, tr.hash(), contentsString(txTraceFile))); + toolResponse.attachDebugTrace(tr.getCContent().hash(), + DebugVMTrace(traceinfo, trNumber, tr.getCContent().hash(), contentsString(txTraceFile))); } else ETH_LOG("Trace file `" + txTraceFile.string() + "` not found!", 1); diff --git a/retesteth/session/ToolBackend/ToolChainManager.cpp b/retesteth/session/ToolBackend/ToolChainManager.cpp index 38d62804b..9c563e2db 100644 --- a/retesteth/session/ToolBackend/ToolChainManager.cpp +++ b/retesteth/session/ToolBackend/ToolChainManager.cpp @@ -96,9 +96,9 @@ FH32 ToolChainManager::importRawBlock(BYTES const& _rlp) m_pendingBlock = spEthereumBlockState(new EthereumBlockState(header, lastBlock().state(), FH32::zero())); for (auto const& trRLP : rlp[1].toList()) { - Transaction tr(trRLP); - ETH_TEST_MESSAGE(tr.asDataObject().asJson()); - addPendingTransaction(tr); + spTransaction spTr = readTransaction(trRLP); + ETH_TEST_MESSAGE(spTr.getCContent().asDataObject().asJson()); + addPendingTransaction(spTr); } if (rlp[2].toList().size() > 2) diff --git a/retesteth/session/ToolBackend/ToolChainManager.h b/retesteth/session/ToolBackend/ToolChainManager.h index 9245d6b29..29b57258e 100644 --- a/retesteth/session/ToolBackend/ToolChainManager.h +++ b/retesteth/session/ToolBackend/ToolChainManager.h @@ -15,7 +15,7 @@ class ToolChainManager : public GCP_SPointerBase { public: ToolChainManager(SetChainParamsArgs const& _config, fs::path const& _toolPath, fs::path const& _tmpDir); - void addPendingTransaction(Transaction const& _tr) { m_pendingBlock.getContent().addTransaction(_tr); } + void addPendingTransaction(spTransaction const& _tr) { m_pendingBlock.getContent().addTransaction(_tr); } ToolChain const& currentChain() const { diff --git a/retesteth/session/ToolBackend/ToolImplHelper.cpp b/retesteth/session/ToolBackend/ToolImplHelper.cpp index 7060719cf..8d4b266a3 100644 --- a/retesteth/session/ToolBackend/ToolImplHelper.cpp +++ b/retesteth/session/ToolBackend/ToolImplHelper.cpp @@ -34,12 +34,12 @@ DataObject constructEthGetBlockBy(EthereumBlockState const& _block) constructResponse["transactions"] = DataObject(DataType::Array); for (auto const& tr : _block.transactions()) { - DataObject fullTransaction = tr.asDataObject(); + DataObject fullTransaction = tr.getCContent().asDataObject(); fullTransaction["blockHash"] = _block.header().hash().asString(); // We don't know the hash its in tool response fullTransaction["blockNumber"] = _block.header().number().asString(); fullTransaction["from"] = FH20::zero().asString(); // Can be recovered from vrs fullTransaction["transactionIndex"] = "0x00"; // Its in tool response - fullTransaction["hash"] = tr.hash().asString(); + fullTransaction["hash"] = tr.getCContent().hash().asString(); constructResponse["transactions"].addArrayObject(fullTransaction); } @@ -112,14 +112,23 @@ void verifyBlockRLP(dev::RLP const& _rlp) for (auto const& tr : _rlp[1]) { - if (!tr.isList()) - throw dev::RLPException("Transaction RLP is expected to be list"); - - for (size_t i = 0; i < 9; i++) + if (tr.isList()) + { + // check legacy transaction. otherwise accept byte array + for (size_t i = 0; i < 9; i++) + { + if (!tr[i].isData()) + throw dev::RLPException("Transaction RLP field is not data!"); + } + } + else if (tr.isData()) { - if (!tr[i].isData()) - throw dev::RLPException("Transaction RLP field is not data!"); + // Transaction type 1 is allowed + if ((int)tr.payload()[0] != 1) + throw dev::RLPException("Transaction RLP is expected to be list"); } + else + throw dev::RLPException("Transaction RLP is expected to be list"); } for (auto const& un : _rlp[2]) diff --git a/retesteth/session/ToolImpl.cpp b/retesteth/session/ToolImpl.cpp index 42aa1717c..72aded585 100644 --- a/retesteth/session/ToolImpl.cpp +++ b/retesteth/session/ToolImpl.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "ToolBackend/ToolImplHelper.h" @@ -26,20 +27,21 @@ FH32 ToolImpl::eth_sendRawTransaction(BYTES const& _rlp) { rpcCall("", {}); ETH_TEST_MESSAGE("\nRequest: eth_sendRawTransaction \n" + _rlp.asString()); - Transaction tr(_rlp); - m_toolChainManager.getContent().addPendingTransaction(tr); - FH32 trHash = tr.hash(); + + spTransaction spTr = readTransaction(_rlp); + m_toolChainManager.getContent().addPendingTransaction(spTr); + FH32 trHash = spTr.getContent().hash(); ETH_TEST_MESSAGE("Response: " + trHash.asString()); return trHash; } -size_t ToolImpl::eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) +VALUE ToolImpl::eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) { rpcCall("", {}); ETH_TEST_MESSAGE("\nRequest: eth_getTransactionCount " + _blockNumber.asString() + " " + _address.asString()); VALUE const& nonce = blockchain().blockByNumber(_blockNumber).state().getAccount(_address).nonce(); ETH_TEST_MESSAGE("Response: eth_getTransactionCount " + nonce.asDecString()); - return (size_t)nonce.asU256(); + return nonce; } VALUE ToolImpl::eth_blockNumber() diff --git a/retesteth/session/ToolImpl.h b/retesteth/session/ToolImpl.h index c601d4188..9b3c72e22 100644 --- a/retesteth/session/ToolImpl.h +++ b/retesteth/session/ToolImpl.h @@ -18,7 +18,7 @@ class ToolImpl : public SessionInterface // ETH Methods FH32 eth_sendRawTransaction(BYTES const& _rlp) override; - size_t eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) override; + VALUE eth_getTransactionCount(FH20 const& _address, VALUE const& _blockNumber) override; VALUE eth_blockNumber() override; EthGetBlockBy eth_getBlockByHash(FH32 const& _hash, Request _fullObjects) override; EthGetBlockBy eth_getBlockByNumber(VALUE const& _blockNumber, Request _fullObjects) override; diff --git a/retesteth/testStructures/Common.cpp b/retesteth/testStructures/Common.cpp index eac88c8ad..4e8303f46 100644 --- a/retesteth/testStructures/Common.cpp +++ b/retesteth/testStructures/Common.cpp @@ -26,16 +26,15 @@ bool isHexDigitsType(DigitsType _dtype) void removeLeadingZeroes(string& _hexStr) { - bool replacePossible = true; - while (replacePossible) + size_t i = 0; + for (i = 2; i < _hexStr.length() - 1; i++) { - if (_hexStr[0] == '0' && _hexStr[1] == 'x' && _hexStr[2] == '0' && _hexStr.size() >= 4) - { - _hexStr = "0x" + _hexStr.substr(3); + if (_hexStr.at(i) == '0') continue; - } - replacePossible = false; + else + break; } + _hexStr = "0x" + _hexStr.substr(i); } } // namespace @@ -267,9 +266,7 @@ DataObject convertDecBlockheaderIncompleteToHex(DataObject const& _data) { // Convert to HEX DataObject tmpD = _data; - tmpD.removeKey("updatePoW"); // BlockchainTestFiller fields tmpD.removeKey("RelTimestamp"); // BlockchainTestFiller fields - tmpD.removeKey("expectException"); // BlockchainTestFiller fields tmpD.removeKey("chainname"); // BlockchainTestFiller fields std::vector hashKeys = {"parentHash", "coinbase", "bloom"}; @@ -287,47 +284,6 @@ DataObject convertDecBlockheaderIncompleteToHex(DataObject const& _data) return tmpD; } -std::mutex g_strFindMutex; -DigitsType stringIntegerType(std::string const& _string, bool _wasPrefix) -{ - if (_string[0] == '0' && _string[1] == 'x' && !_wasPrefix) - { - DigitsType substringType = stringIntegerType(_string, true); - if (substringType == DigitsType::Hex) - return DigitsType::HexPrefixed; - - if (substringType == DigitsType::Decimal) - { - if (_string.size() % 2 == 0) - return DigitsType::HexPrefixed; - else - return DigitsType::UnEvenHexPrefixed; - } - - if (substringType == DigitsType::UnEvenHex) - return DigitsType::UnEvenHexPrefixed; - } - - bool isDecimalOnly = true; - std::lock_guard lock(g_strFindMutex); // string.find is not thread safe + static - for (size_t i = _wasPrefix ? 2 : 0; i < _string.length(); i++) - { - if (!isxdigit(_string[i])) - return DigitsType::String; - - if (isDecimalOnly && !isdigit(_string[i])) - isDecimalOnly = false; - } - - if (isDecimalOnly) - return DigitsType::Decimal; - - if (_string.size() % 2 == 0) - return DigitsType::Hex; - - return DigitsType::UnEvenHex; -} - // Construct comapasion string string compareBlockHeaders(DataObject const& _blockA, DataObject const& _blockB, string& _whatField) { diff --git a/retesteth/testStructures/Common.h b/retesteth/testStructures/Common.h index d179aabbb..87fc92f80 100644 --- a/retesteth/testStructures/Common.h +++ b/retesteth/testStructures/Common.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include using namespace dataobject; using namespace test::compiler; @@ -19,18 +20,6 @@ void mod_valueToCompactEvenHexPrefixed(DataObject&); void mod_keyToCompactEvenHexPrefixed(DataObject&); long long int hexOrDecStringToInt(string const& _str); -// See what kind of a string is str -enum class DigitsType -{ - Decimal, - Hex, - UnEvenHex, - HexPrefixed, - UnEvenHexPrefixed, - String -}; -DigitsType stringIntegerType(std::string const& _string, bool _wasPrefix = false); - // Check the presents of fields in a DataObject with a validation map typedef std::set possibleType; void requireJsonFields(DataObject const& _o, std::string const& _section, @@ -44,6 +33,8 @@ enum jsonField using jsonTypeSet = std::set; using jsonType = std::pair; +static VALUE c_maxNonce(DataObject("0xffffffffffffffff")); + // Check the json object with validation map that reuires certain field of certain type to be present in json // _o a json object to check // _configName a string with json object name. Will apper in error message. diff --git a/retesteth/testStructures/basetypes/FH.cpp b/retesteth/testStructures/basetypes/FH.cpp index 4242fd5e2..46b38e16f 100644 --- a/retesteth/testStructures/basetypes/FH.cpp +++ b/retesteth/testStructures/basetypes/FH.cpp @@ -2,6 +2,7 @@ #include "../Common.h" #include #include +using namespace test; using namespace test::teststruct; namespace diff --git a/retesteth/testStructures/basetypes/VALUE.h b/retesteth/testStructures/basetypes/VALUE.h index d9242133e..2ea4ae677 100644 --- a/retesteth/testStructures/basetypes/VALUE.h +++ b/retesteth/testStructures/basetypes/VALUE.h @@ -27,6 +27,7 @@ struct VALUE : GCP_SPointerBase bool operator==(VALUE const& _rhs) const { return m_data == _rhs.asU256(); } VALUE operator-(VALUE const& _rhs) const { return VALUE(m_data - _rhs.asU256()); } VALUE operator+(VALUE const& _rhs) const { return VALUE(m_data + _rhs.asU256()); } + VALUE operator++(int) { m_data++; return *this; } string asString(size_t _roundBytes = 1) const { return dev::toCompactHexPrefixed(m_data, _roundBytes); } string asDecString() const; diff --git a/retesteth/testStructures/types/BlockchainTests/BlockchainTestFiller.cpp b/retesteth/testStructures/types/BlockchainTests/BlockchainTestFiller.cpp index 4a9b55226..1678f7cc2 100644 --- a/retesteth/testStructures/types/BlockchainTests/BlockchainTestFiller.cpp +++ b/retesteth/testStructures/types/BlockchainTests/BlockchainTestFiller.cpp @@ -15,6 +15,12 @@ BlockchainTestInFiller::BlockchainTestInFiller(DataObject const& _data) m_info = spInfoIncomplete(new InfoIncomplete(_data.atKey("_info"))); m_pre = spState(new State(convertDecStateToHex(_data.atKey("pre")))); + // Prepare nonce map for transaction 'auto' nonce parsing + NonceMap nonceMap; + for (auto const& acc : m_pre.getCContent().accounts()) + nonceMap.emplace(acc.first.asString(), spVALUE(new VALUE(acc.second.getCContent().nonce().asU256()))); + // nonce map + m_sealEngine = SealEngine::NoProof; if (_data.count("sealEngine")) { @@ -53,7 +59,7 @@ BlockchainTestInFiller::BlockchainTestInFiller(DataObject const& _data) m_hasAtLeastOneUncle = false; for (auto const& el : _data.atKey("blocks").getSubObjects()) { - m_blocks.push_back(BlockchainTestFillerBlock(el)); + m_blocks.push_back(BlockchainTestFillerBlock(el, nonceMap)); if (m_blocks.at(m_blocks.size() - 1).uncles().size() > 0) m_hasAtLeastOneUncle = true; } diff --git a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.cpp b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.cpp index bb1a27174..b2be42731 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.cpp +++ b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.cpp @@ -23,7 +23,7 @@ BlockchainTestBlock::BlockchainTestBlock(DataObject const& _data) m_blockHeader = spBlockHeader(new BlockHeader(_data.atKey("blockHeader"))); for (auto const& tr : _data.atKey("transactions").getSubObjects()) - m_transactions.push_back(Transaction(tr)); + m_transactions.push_back(readTransaction(tr)); for (auto const& un : _data.atKey("uncleHeaders").getSubObjects()) m_uncles.push_back(BlockHeader(un)); diff --git a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.h b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.h index a5d4e97bd..dfff6bae0 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.h +++ b/retesteth/testStructures/types/BlockchainTests/Filled/BlockchainTestBlock.h @@ -18,7 +18,7 @@ struct BlockchainTestBlock : GCP_SPointerBase BlockHeader const& header() const { return m_blockHeader.getCContent(); } std::vector const& uncles() const { return m_uncles; } - std::vector const& transactions() const { return m_transactions; } + std::vector const& transactions() const { return m_transactions; } private: BlockchainTestBlock() {} @@ -26,7 +26,7 @@ struct BlockchainTestBlock : GCP_SPointerBase spVALUE m_blockNumber; spBlockHeader m_blockHeader; std::vector m_uncles; - std::vector m_transactions; + std::vector m_transactions; spBYTES m_rlp; }; diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.cpp b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.cpp index f08e8e35d..044bb5064 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.cpp +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.cpp @@ -8,7 +8,7 @@ namespace test { namespace teststruct { -BlockchainTestFillerBlock::BlockchainTestFillerBlock(DataObject const& _data) +BlockchainTestFillerBlock::BlockchainTestFillerBlock(DataObject const& _data, NonceMap& _nonceMap) : m_chainName(BlockchainTestFillerBlock::defaultChainName()) { try @@ -39,37 +39,51 @@ BlockchainTestFillerBlock::BlockchainTestFillerBlock(DataObject const& _data) if (_data.count("transactions")) for (auto const& tr : _data.atKey("transactions").getSubObjects()) - m_transactions.push_back(BlockchainTestFillerTransaction(tr)); + m_transactions.push_back(BlockchainTestFillerTransaction(tr, _nonceMap)); if (_data.count("uncleHeaders")) for (auto const& un : _data.atKey("uncleHeaders").getSubObjects()) m_uncles.push_back(BlockchainTestFillerUncle(un)); - if (_data.count("blockHeader")) + if (_data.count("expectException")) { - DataObject tmpD = convertDecBlockheaderIncompleteToHex(_data.atKey("blockHeader")); - if (tmpD.getSubObjects().size() > 0) - m_blockHeaderIncomplete = spBlockHeaderIncomplete(new BlockHeaderIncomplete(tmpD)); + for (auto const& rec : _data.atKey("expectException").getSubObjects()) + { + // Parse ">=Frontier" : "EXCEPTION" + ClientConfig const& cfg = Options::get().getDynamicOptions().getCurrentConfig(); + std::set forksString = {rec.getKey()}; + std::vector parsedForks = cfg.translateNetworks(forksString); + for (auto const& el : parsedForks) + m_expectExceptions.emplace(el, rec.asString()); + } + } - if (_data.atKey("blockHeader").count("expectException")) + if (_data.count("blockHeader")) + { + if (_data.atKey("blockHeader").getSubObjects().size() && + _data.atKey("blockHeader").getSubObjects().at(0).type() == DataType::Object) { - for (auto const& rec : _data.atKey("blockHeader").atKey("expectException").getSubObjects()) + // Read overwrite rules specific to fork + for (auto const& rec : _data.atKey("blockHeader").getSubObjects()) { - // Parse ">=Frontier" : "EXCEPTION" + // Parse ">=Frontier" : "BlockHeaderOverwrite" ClientConfig const& cfg = Options::get().getDynamicOptions().getCurrentConfig(); - std::set forksString = { rec.getKey() }; + std::set forksString = {rec.getKey()}; std::vector parsedForks = cfg.translateNetworks(forksString); for (auto const& el : parsedForks) - m_expectExceptions.emplace(el, rec.asString()); + m_overwriteHeaderByForkMap.emplace(el, spBlockHeaderOverwrite(new BlockHeaderOverwrite(rec))); } } - m_relTimeStamp = 0; - if (_data.atKey("blockHeader").count("RelTimestamp")) + else { - m_hasRelTimeStamp = true; - m_relTimeStamp = hexOrDecStringToInt(_data.atKey("blockHeader").atKey("RelTimestamp").asString()); + // Treat the whole blockHeader section as the overwrite rule for all forks + ClientConfig const& cfg = Options::get().getDynamicOptions().getCurrentConfig(); + spBlockHeaderOverwrite overwrite(new BlockHeaderOverwrite(_data.atKey("blockHeader"))); + for (auto const& el : cfg.cfgFile().allowedForks()) + m_overwriteHeaderByForkMap.emplace(el, overwrite); } } + requireJsonFields(_data, "BlockchainTestFillerBlock " + _data.getKey(), {{"rlp", {{DataType::String}, jsonField::Optional}}, {"chainname", {{DataType::String}, jsonField::Optional}}, @@ -78,6 +92,7 @@ BlockchainTestFillerBlock::BlockchainTestFillerBlock(DataObject const& _data) {"chainnetwork", {{DataType::String}, jsonField::Optional}}, {"transactions", {{DataType::Array}, jsonField::Optional}}, {"uncleHeaders", {{DataType::Array}, jsonField::Optional}}, + {"expectException", {{DataType::Object}, jsonField::Optional}}, {"blockHeader", {{DataType::Object}, jsonField::Optional}}}); } catch (std::exception const& _ex) diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.h index 11ff4438b..015e1b667 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.h +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlock.h @@ -3,11 +3,13 @@ #include "../../../configs/FORK.h" #include "../../Ethereum/BlockHeaderIncomplete.h" #include "../../Ethereum/Transaction.h" +#include "BlockchainTestFillerBlockHeaderOverwrite.h" #include "BlockchainTestFillerTransaction.h" #include "BlockchainTestFillerUncle.h" #include #include using namespace dataobject; +using namespace test::teststruct; namespace test { @@ -16,7 +18,7 @@ namespace teststruct // BlockchainTestFiller block instructions struct BlockchainTestFillerBlock : GCP_SPointerBase { - BlockchainTestFillerBlock(DataObject const&); + BlockchainTestFillerBlock(DataObject const&, NonceMap&); // Block can be represented as raw RLP without any of other fields // other then BlockHeader with expected exceptions @@ -35,13 +37,11 @@ struct BlockchainTestFillerBlock : GCP_SPointerBase VALUE const& number() const { return m_blockNumber.getCContent(); } // BlockHeader overwrite section to replace some fields in the header for testing purposes - // Also BlockHeader contain expected exceptions for this block - bool hasBlockHeader() const { return !m_blockHeaderIncomplete.isEmpty(); } - BlockHeaderIncomplete const& blockHeader() const { return m_blockHeaderIncomplete.getCContent(); } - - // Blockheader oerwrite can define timestamp shift from previous block - bool hasRelTimeStamp() const { return m_hasRelTimeStamp; } - long long int relTimeStamp() const { return m_relTimeStamp; } + bool hasBlockHeaderOverwrite(FORK const& _fork) const { return m_overwriteHeaderByForkMap.count(_fork); } + BlockHeaderOverwrite const& getHeaderOverwrite(FORK const& _fork) const + { + return m_overwriteHeaderByForkMap.at(_fork).getCContent(); + } // Transaction in block filler. Can be marked invalid (expected to fail) std::vector const& transactions() const { return m_transactions; } @@ -82,13 +82,12 @@ struct BlockchainTestFillerBlock : GCP_SPointerBase spVALUE m_blockNumber; spFORK m_network; bool m_doNotImportOnClient = false; - bool m_hasRelTimeStamp = false; - long long int m_relTimeStamp; std::vector m_uncles; std::vector m_transactions; std::map m_expectExceptions; - spBlockHeaderIncomplete m_blockHeaderIncomplete; + + std::map m_overwriteHeaderByForkMap; }; } // namespace teststruct diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.cpp b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.cpp new file mode 100644 index 000000000..ae99ddcd5 --- /dev/null +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.cpp @@ -0,0 +1,24 @@ +#include "BlockchainTestFillerBlockHeaderOverwrite.h" +#include +using namespace dataobject; + +namespace test +{ +namespace teststruct +{ +BlockHeaderOverwrite::BlockHeaderOverwrite(DataObject const& _data) +{ + DataObject tmpD = convertDecBlockheaderIncompleteToHex(_data); + if (tmpD.getSubObjects().size() > 0) + m_blockHeaderIncomplete = spBlockHeaderIncomplete(new BlockHeaderIncomplete(tmpD)); + + m_relTimeStamp = 0; + if (_data.count("RelTimestamp")) + { + m_hasRelTimeStamp = true; + m_relTimeStamp = hexOrDecStringToInt(_data.atKey("RelTimestamp").asString()); + } +} + +} // namespace teststruct +} // namespace test diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.h new file mode 100644 index 000000000..25a0fbf8a --- /dev/null +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerBlockHeaderOverwrite.h @@ -0,0 +1,33 @@ +#pragma once +#include "../../../basetypes.h" +#include "../../../configs/FORK.h" +#include "../../Ethereum/BlockHeaderIncomplete.h" +#include +#include +using namespace dataobject; + +namespace test +{ +namespace teststruct +{ +// Information about blockheader overwrite +struct BlockHeaderOverwrite : GCP_SPointerBase +{ + BlockHeaderOverwrite(DataObject const&); + + // Blockheader oerwrite can define timestamp shift from previous block + bool hasRelTimeStamp() const { return m_hasRelTimeStamp; } + long long int relTimeStamp() const { return m_relTimeStamp; } + bool hasBlockHeader() const { return !m_blockHeaderIncomplete.isEmpty(); } + BlockHeaderIncomplete const& header() const { return m_blockHeaderIncomplete.getCContent(); } + +private: + bool m_hasRelTimeStamp = false; + long long int m_relTimeStamp; + spBlockHeaderIncomplete m_blockHeaderIncomplete; +}; + +typedef GCP_SPointer spBlockHeaderOverwrite; + +} // namespace teststruct +} // namespace test diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.cpp b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.cpp index 075adf1d8..8d17a0876 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.cpp +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.cpp @@ -3,19 +3,37 @@ #include #include +#include + namespace test { namespace teststruct { -BlockchainTestFillerTransaction::BlockchainTestFillerTransaction(DataObject const& _data) +BlockchainTestFillerTransaction::BlockchainTestFillerTransaction(DataObject const& _data, NonceMap& _nonceMap) { try { m_expectInvalid = _data.count("invalid"); DataObject tmpD = _data; + + if (tmpD.count("secretKey") && tmpD.atKey("nonce").asString() == "auto") + { + dev::Secret priv(tmpD.atKey("secretKey").asString()); + dev::Address key = dev::toAddress(priv); + if (_nonceMap.count("0x" + key.hex())) + { + tmpD.atKeyUnsafe("nonce").setString(_nonceMap.at("0x" + key.hex()).getCContent().asDecString()); + _nonceMap["0x" + key.hex()].getContent()++; + } + else + ETH_ERROR_MESSAGE("Parsing tx.nonce `auto` can't find tx.origin in nonce map!"); + } + tmpD.removeKey("data"); tmpD.removeKey("to"); + if (tmpD.count("accessList")) + tmpD.removeKey("accessList"); tmpD.performModifier(mod_valueToCompactEvenHexPrefixed); // fix 0x prefix on 'to' key @@ -28,7 +46,10 @@ BlockchainTestFillerTransaction::BlockchainTestFillerTransaction(DataObject cons // Compile LLL in transaction data into byte code if not already tmpD["data"] = test::compiler::replaceCode(_data.atKey("data").asString()); - m_transaction = spTransaction(new Transaction(tmpD)); + if (_data.count("accessList")) + tmpD["accessList"] = _data.atKey("accessList"); + + m_transaction = readTransaction(tmpD); } catch (std::exception const& _ex) { diff --git a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.h b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.h index 44ce9c60f..ca7acfcc7 100644 --- a/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.h +++ b/retesteth/testStructures/types/BlockchainTests/Filler/BlockchainTestFillerTransaction.h @@ -3,14 +3,16 @@ #include #include using namespace dataobject; - namespace test { namespace teststruct { +// NonceMap; +typedef std::map NonceMap; + struct BlockchainTestFillerTransaction : GCP_SPointerBase { - BlockchainTestFillerTransaction(DataObject const&); + BlockchainTestFillerTransaction(DataObject const&, NonceMap& _nonceMap); Transaction const& tr() const { return m_transaction.getCContent(); } bool isMarkedInvalid() const { return m_expectInvalid; } diff --git a/retesteth/testStructures/types/Ethereum/Account.cpp b/retesteth/testStructures/types/Ethereum/Account.cpp index 3cb5e1c1d..e370f4f2a 100644 --- a/retesteth/testStructures/types/Ethereum/Account.cpp +++ b/retesteth/testStructures/types/Ethereum/Account.cpp @@ -13,6 +13,8 @@ Account::Account(FH20 const& _addr, VALUE const& _balance, VALUE const& _nonce, m_nonce = spVALUE(new VALUE(_nonce)); m_code = spBYTES(new BYTES(_code)); m_storage = spStorage(new Storage(_storage)); + if (m_nonce.getCContent() > c_maxNonce) + ETH_ERROR_MESSAGE("Account `" + m_address.getCContent().asString() + "` requires nonce <= (2**64)-1"); } Account::Account(DataObject const& _data) @@ -22,6 +24,8 @@ Account::Account(DataObject const& _data) m_nonce = spVALUE(new VALUE(_data.atKey("nonce"))); m_code = spBYTES(new BYTES(_data.atKey("code"))); m_storage = spStorage(new Storage(_data.atKey("storage"))); + if (m_nonce.getCContent() > c_maxNonce) + ETH_ERROR_MESSAGE("Account `" + m_address.getCContent().asString() + "` requires nonce <= (2**64)-1"); requireJsonFields(_data, "Account " + _data.getKey(), {{"balance", {{DataType::String}, jsonField::Required}}, {"code", {{DataType::String}, jsonField::Required}}, {"nonce", {{DataType::String}, jsonField::Required}}, {"storage", {{DataType::Object}, jsonField::Required}}}); diff --git a/retesteth/testStructures/types/Ethereum/AccountIncomplete.cpp b/retesteth/testStructures/types/Ethereum/AccountIncomplete.cpp index 2391583f9..0510a0f13 100644 --- a/retesteth/testStructures/types/Ethereum/AccountIncomplete.cpp +++ b/retesteth/testStructures/types/Ethereum/AccountIncomplete.cpp @@ -17,7 +17,11 @@ AccountIncomplete::AccountIncomplete(DataObject const& _data) if (_data.count("balance")) m_balance = spVALUE(new VALUE(_data.atKey("balance"))); if (_data.count("nonce")) + { m_nonce = spVALUE(new VALUE(_data.atKey("nonce"))); + if (m_nonce.getCContent() > c_maxNonce) + ETH_ERROR_MESSAGE("AccountIncomplete `" + m_address.getCContent().asString() + "` requires nonce <= (2**64)-1"); + } if (_data.count("code")) m_code = spBYTES(new BYTES(_data.atKey("code"))); requireJsonFields(_data, "AccountIncomplete " + _data.getKey(), diff --git a/retesteth/testStructures/types/Ethereum/EthereumBlock.cpp b/retesteth/testStructures/types/Ethereum/EthereumBlock.cpp index 6fb52a5aa..49101fee7 100644 --- a/retesteth/testStructures/types/Ethereum/EthereumBlock.cpp +++ b/retesteth/testStructures/types/Ethereum/EthereumBlock.cpp @@ -45,7 +45,7 @@ BYTES const EthereumBlock::getRLP() const // Transaction list RLPStream transactionList(m_transactions.size()); for (auto const& tr : m_transactions) - transactionList.appendRaw(tr.asRLPStream().out()); + transactionList.appendRaw(tr.getCContent().asRLPStream().out()); stream.appendRaw(transactionList.out()); // Uncle list diff --git a/retesteth/testStructures/types/Ethereum/EthereumBlock.h b/retesteth/testStructures/types/Ethereum/EthereumBlock.h index a7da30acd..e8c7d80e8 100644 --- a/retesteth/testStructures/types/Ethereum/EthereumBlock.h +++ b/retesteth/testStructures/types/Ethereum/EthereumBlock.h @@ -21,7 +21,7 @@ namespace teststruct struct EthereumBlock : GCP_SPointerBase { EthereumBlock(BlockHeader const& _header) { m_header = spBlockHeader(new BlockHeader(_header.asDataObject())); } - void addTransaction(Transaction const& _tr) { m_transactions.push_back(Transaction(_tr.asDataObject())); } + void addTransaction(spTransaction const& _tr) { m_transactions.push_back(_tr); } void addUncle(BlockHeader const& _header) { m_uncles.push_back(BlockHeader(_header.asDataObject())); } void replaceHeader(BlockHeader const& _header) { m_header = spBlockHeader(new BlockHeader(_header.asDataObject())); } void recalculateUncleHash(); @@ -30,12 +30,12 @@ struct EthereumBlock : GCP_SPointerBase BlockHeader const& header() const { return m_header.getCContent(); } BlockHeader& headerUnsafe() { return m_header.getContent(); } std::vector const& uncles() const { return m_uncles; } - std::vector const& transactions() const { return m_transactions; } + std::vector const& transactions() const { return m_transactions; } protected: EthereumBlock() {} spBlockHeader m_header; - std::vector m_transactions; + std::vector m_transactions; std::vector m_uncles; }; diff --git a/retesteth/testStructures/types/Ethereum/Transaction.cpp b/retesteth/testStructures/types/Ethereum/Transaction.cpp index ec66f57fd..268a3a39a 100644 --- a/retesteth/testStructures/types/Ethereum/Transaction.cpp +++ b/retesteth/testStructures/types/Ethereum/Transaction.cpp @@ -11,9 +11,11 @@ namespace test { namespace teststruct { -Transaction::Transaction(DataObject const& _data) +Transaction::Transaction(DataObject const& _data, string const& _dataRawPreview, string const& _dataLabel) { fromDataObject(_data); + m_dataRawPreview = _dataRawPreview; + m_dataLabel = _dataLabel; } void Transaction::fromDataObject(DataObject const& _data) @@ -47,25 +49,28 @@ void Transaction::fromDataObject(DataObject const& _data) throw test::UpwardsException("Incorrect transaction `v` value: " + m_v.getCContent().asString()); m_r = spVALUE(new VALUE(_data.atKey("r"))); m_s = spVALUE(new VALUE(_data.atKey("s"))); + rebuildRLP(); } requireJsonFields(_data, "Transaction " + _data.getKey(), - {{"data", {{DataType::String}, jsonField::Required}}, - {"gasLimit", {{DataType::String}, jsonField::Required}}, - {"gasPrice", {{DataType::String}, jsonField::Required}}, - {"nonce", {{DataType::String}, jsonField::Required}}, - {"value", {{DataType::String}, jsonField::Required}}, - {"to", {{DataType::String, DataType::Null}, jsonField::Required}}, - {"secretKey", {{DataType::String}, jsonField::Optional}}, - {"v", {{DataType::String}, jsonField::Optional}}, - {"r", {{DataType::String}, jsonField::Optional}}, - {"s", {{DataType::String}, jsonField::Optional}}, - {"blockHash", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction - {"blockNumber", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction - {"from", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction - {"hash", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction - {"transactionIndex", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction - {"invalid", {{DataType::String}, jsonField::Optional}}, // BlockchainTest filling - }); + { + {"data", {{DataType::String}, jsonField::Required}}, {"gasLimit", {{DataType::String}, jsonField::Required}}, + {"gasPrice", {{DataType::String}, jsonField::Required}}, {"nonce", {{DataType::String}, jsonField::Required}}, + {"value", {{DataType::String}, jsonField::Required}}, + {"to", {{DataType::String, DataType::Null}, jsonField::Required}}, + {"secretKey", {{DataType::String}, jsonField::Optional}}, {"v", {{DataType::String}, jsonField::Optional}}, + {"r", {{DataType::String}, jsonField::Optional}}, {"s", {{DataType::String}, jsonField::Optional}}, + + {"type", {{DataType::String}, jsonField::Optional}}, // Transaction Type 1 + {"chainId", {{DataType::String}, jsonField::Optional}}, // Transaction Type 1 + {"accessList", {{DataType::Array}, jsonField::Optional}}, // Transaction access list + + {"blockHash", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction + {"blockNumber", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction + {"from", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction + {"hash", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction + {"transactionIndex", {{DataType::String}, jsonField::Optional}}, // EthGetBlockBy transaction + {"invalid", {{DataType::String}, jsonField::Optional}}, // BlockchainTest filling + }); } catch (std::exception const& _ex) { @@ -105,7 +110,6 @@ Transaction::Transaction(BYTES const& _rlp) fromRLP(rlp); } - void Transaction::streamHeader(dev::RLPStream& _s) const { _s << nonce().asU256(); @@ -134,32 +138,24 @@ void Transaction::buildVRS(VALUE const& _secret) DataObject v = DataObject(dev::toCompactHexPrefixed(dev::u256(sigStruct.v + 27))); DataObject r = DataObject(dev::toCompactHexPrefixed(dev::u256(sigStruct.r))); DataObject s = DataObject(dev::toCompactHexPrefixed(dev::u256(sigStruct.s))); - m_v = spVALUE(new VALUE(v)); - m_r = spVALUE(new VALUE(r)); - m_s = spVALUE(new VALUE(s)); + assignV(spVALUE(new VALUE(v))); + assignR(spVALUE(new VALUE(r))); + assignS(spVALUE(new VALUE(s))); + rebuildRLP(); } +void Transaction::assignV(spVALUE const _v) { m_v = _v; } +void Transaction::assignR(spVALUE const _r) { m_r = _r; } +void Transaction::assignS(spVALUE const _s) { m_s = _s; } -BYTES const Transaction::getSignedRLP() const +BYTES const& Transaction::getSignedRLP() const { - dev::RLPStream sWithSignature; - sWithSignature.appendList(9); - streamHeader(sWithSignature); - sWithSignature << v().asU256().convert_to(); - sWithSignature << r().asU256(); - sWithSignature << s().asU256(); - return BYTES(dev::toHexPrefixed(sWithSignature.out())); + return m_signedRLPdata.getCContent(); } -dev::RLPStream const Transaction::asRLPStream() const +dev::RLPStream const& Transaction::asRLPStream() const { - dev::RLPStream out; - out.appendList(9); - streamHeader(out); - out << v().asU256().convert_to(); - out << r().asU256(); - out << s().asU256(); - return out; + return m_outRlpStream; } const DataObject Transaction::asDataObject(ExportOrder _order) const @@ -195,24 +191,22 @@ const DataObject Transaction::asDataObject(ExportOrder _order) const return out; } -FH32 Transaction::hash() const +FH32 const& Transaction::hash() const { - return FH32("0x" + dev::toString(dev::sha3(asRLPStream().out()))); + return m_hash.getCContent(); } -bool Transaction::operator==(Transaction const& _rhs) const +void Transaction::rebuildRLP() { - bool creationCondition = false; - if (m_creation && _rhs.isCreation()) - creationCondition = true; - else if (m_creation && !_rhs.isCreation()) - creationCondition = false; - else if (!m_creation && _rhs.isCreation()) - creationCondition = false; - else if (!m_creation && !_rhs.isCreation()) - creationCondition = to() == _rhs.to(); - return creationCondition && data() == _rhs.data() && gasLimit() == _rhs.gasLimit() && gasPrice() == _rhs.gasPrice() && - nonce() == _rhs.nonce() && value() == _rhs.value() && v() == _rhs.v() && r() == _rhs.r() && s() == _rhs.s(); + dev::RLPStream out; + out.appendList(9); + streamHeader(out); + out << v().asU256().convert_to(); + out << r().asU256(); + out << s().asU256(); + m_outRlpStream = out; + m_signedRLPdata = spBYTES(new BYTES(dev::toHexPrefixed(out.out()))); + m_hash = spFH32(new FH32("0x" + dev::toString(dev::sha3(out.out())))); } } // namespace teststruct diff --git a/retesteth/testStructures/types/Ethereum/Transaction.h b/retesteth/testStructures/types/Ethereum/Transaction.h index aa02be56f..5981c6efe 100644 --- a/retesteth/testStructures/types/Ethereum/Transaction.h +++ b/retesteth/testStructures/types/Ethereum/Transaction.h @@ -2,6 +2,7 @@ #include "../../basetypes.h" #include #include +#include using namespace dataobject; using namespace test::teststruct; @@ -9,9 +10,15 @@ namespace test { namespace teststruct { +enum class TransactionType +{ + LEGACY, + ACCESSLIST +}; + struct Transaction : GCP_SPointerBase { - Transaction(DataObject const&); + Transaction(DataObject const&, string const& _dataRawPreview = string(), string const& _dataLabel = string()); Transaction(BYTES const&); Transaction(dev::RLP const&); BYTES const& data() const { return m_data.getCContent(); } @@ -29,18 +36,22 @@ struct Transaction : GCP_SPointerBase VALUE const& v() const { return m_v.getCContent(); } VALUE const& r() const { return m_r.getCContent(); } VALUE const& s() const { return m_s.getCContent(); } - FH32 hash() const; + FH32 const& hash() const; + virtual TransactionType type() const { return TransactionType::LEGACY; } - BYTES const getSignedRLP() const; - dev::RLPStream const asRLPStream() const; - DataObject const asDataObject(ExportOrder _order = ExportOrder::Default) const; + BYTES const& getSignedRLP() const; + dev::RLPStream const& asRLPStream() const; + virtual DataObject const asDataObject(ExportOrder _order = ExportOrder::Default) const; - bool operator==(Transaction const& _rhs) const; + virtual ~Transaction(){}; + + /// Debug + string const& dataLabel() const { return m_dataLabel; } + string const& dataRawPreview() const { return m_dataRawPreview; } private: - Transaction() {} - void fromDataObject(DataObject const&); - void fromRLP(dev::RLP const&); + virtual void fromRLP(dev::RLP const&); + spBYTES m_data; spVALUE m_gasLimit; spVALUE m_gasPrice; @@ -49,11 +60,28 @@ struct Transaction : GCP_SPointerBase spFH20 m_to; bool m_creation; - void buildVRS(VALUE const& _secret); - void streamHeader(dev::RLPStream& _stream) const; + virtual void buildVRS(VALUE const& _secret); + virtual void streamHeader(dev::RLPStream& _stream) const; spVALUE m_v; spVALUE m_r; spVALUE m_s; + + // Debug + string m_dataRawPreview; // Attached data raw preview before code compilation + string m_dataLabel; // Attached data Label from filler + +protected: + Transaction() {} + virtual void fromDataObject(DataObject const&); + void assignV(spVALUE const); + void assignR(spVALUE const); + void assignS(spVALUE const); + + // Optimization + spFH32 m_hash; + dev::RLPStream m_outRlpStream; + spBYTES m_signedRLPdata; + virtual void rebuildRLP(); }; typedef GCP_SPointer spTransaction; diff --git a/retesteth/testStructures/types/Ethereum/TransactionAccessList.cpp b/retesteth/testStructures/types/Ethereum/TransactionAccessList.cpp new file mode 100644 index 000000000..5ac2381a6 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/TransactionAccessList.cpp @@ -0,0 +1,151 @@ +#include "TransactionAccessList.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace test +{ +namespace teststruct +{ +TransactionAccessList::TransactionAccessList(DataObject const& _data, string const& _dataRawPreview, string const& _dataLabel) + : Transaction(_data, _dataRawPreview, _dataLabel) +{ + m_accessList = spAccessList(new AccessList(_data.atKey("accessList"))); + if (_data.count("secretKey")) + buildVRS(VALUE(_data.atKey("secretKey"))); // Build without v + 27 + else + rebuildRLP(); +} + +TransactionAccessList::TransactionAccessList(dev::RLP const& _rlp) +{ + fromRLP(_rlp); +} + +TransactionAccessList::TransactionAccessList(BYTES const& _rlp) +{ + dev::bytes decodeRLP = sfromHex(_rlp.asString()); + dev::RLP rlp(decodeRLP, dev::RLP::VeryStrict); + fromRLP(rlp); +} + +void TransactionAccessList::fromRLP(dev::RLP const& _rlp) +{ + // 0 - chainID + // 1 - nonce 4 - to 7 - v + // 2 - gasPrice 5 - value 8 - r + // 3 - gasLimit 6 - data 9 - s + DataObject trData; + size_t i = 0; + rlpToString(_rlp[i++]); // chainID + trData["nonce"] = rlpToString(_rlp[i++]); + trData["gasPrice"] = rlpToString(_rlp[i++]); + trData["gasLimit"] = rlpToString(_rlp[i++]); + string const to = rlpToString(_rlp[i++], 0); + trData["to"] = to == "0x" ? "" : to; + trData["value"] = rlpToString(_rlp[i++]); + trData["data"] = rlpToString(_rlp[i++], 0); + + // read access list + spAccessList list = spAccessList(new AccessList(_rlp[i++])); + trData["accessList"] = list.getContent().asDataObject(); + m_accessList = list; + + trData["v"] = rlpToString(_rlp[i++]); + trData["r"] = rlpToString(_rlp[i++]); + trData["s"] = rlpToString(_rlp[i++]); + fromDataObject(trData); +} + +void TransactionAccessList::buildVRS(VALUE const& _secret) +{ + dev::RLPStream stream; + stream.appendList(8); + TransactionAccessList::streamHeader(stream); + + // Alter output with prefixed 01 byte + tr.rlp + dev::bytes outa = stream.out(); + outa.insert(outa.begin(), dev::byte(1)); // txType + + dev::h256 hash(dev::sha3(outa)); + dev::Signature sig = dev::sign(dev::Secret(_secret.asString()), hash); + dev::SignatureStruct sigStruct = *(dev::SignatureStruct const*)&sig; + ETH_FAIL_REQUIRE_MESSAGE( + sigStruct.isValid(), TestOutputHelper::get().testName() + " Could not construct transaction signature!"); + + DataObject v = DataObject(dev::toCompactHexPrefixed(dev::u256(sigStruct.v), 1)); + DataObject r = DataObject(dev::toCompactHexPrefixed(dev::u256(sigStruct.r))); + DataObject s = DataObject(dev::toCompactHexPrefixed(dev::u256(sigStruct.s))); + assignV(spVALUE(new VALUE(v))); + assignR(spVALUE(new VALUE(r))); + assignS(spVALUE(new VALUE(s))); + rebuildRLP(); +} + +void TransactionAccessList::streamHeader(dev::RLPStream& _s) const +{ + // rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, access_list, yParity, senderR, senderS]) + _s << VALUE(1).asU256(); + _s << nonce().asU256(); + _s << gasPrice().asU256(); + _s << gasLimit().asU256(); + if (Transaction::isCreation()) + _s << ""; + else + _s << dev::Address(to().asString()); + _s << value().asU256(); + _s << test::sfromHex(data().asString()); + + // Access Listist + dev::RLPStream accessList(m_accessList.getCContent().list().size()); + for (auto const& el : m_accessList.getCContent().list()) + accessList.appendRaw(el.getCContent().asRLPStream().out()); + + _s.appendRaw(accessList.out()); +} + +DataObject const TransactionAccessList::asDataObject(ExportOrder _order) const +{ + DataObject out = Transaction::asDataObject(_order); + + out["chainId"] = "0x01"; + out["accessList"] = m_accessList.getCContent().asDataObject(); + out["type"] = "0x01"; + if (_order == ExportOrder::ToolStyle) + { + out["chainId"] = "0x1"; + out["type"] = "0x1"; + } + return out; +} + +void TransactionAccessList::rebuildRLP() +{ + // RLP(01 + tr.rlp) + dev::RLPStream wrapper; + dev::RLPStream out; + out.appendList(11); + streamHeader(out); + out << v().asU256().convert_to(); + out << r().asU256(); + out << s().asU256(); + + // Alter output with prefixed 01 byte + tr.rlp + dev::bytes outa = out.out(); + outa.insert(outa.begin(), dev::byte(1)); + + // Encode bytearray into rlp + wrapper << outa; + m_outRlpStream = wrapper; + m_signedRLPdata = spBYTES(new BYTES(dev::toHexPrefixed(m_outRlpStream.out()))); + m_hash = spFH32(new FH32("0x" + dev::toString(dev::sha3(outa)))); +} + + +} // namespace teststruct +} // namespace test diff --git a/retesteth/testStructures/types/Ethereum/TransactionAccessList.h b/retesteth/testStructures/types/Ethereum/TransactionAccessList.h new file mode 100644 index 000000000..82320a1bc --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/TransactionAccessList.h @@ -0,0 +1,32 @@ +#pragma once +#include "Transaction.h" +using namespace dataobject; +using namespace test::teststruct; + +namespace test +{ +namespace teststruct +{ +struct TransactionAccessList : Transaction +{ + TransactionAccessList(DataObject const&, string const& _dataRawPreview = string(), string const& _dataLabel = string()); + TransactionAccessList(BYTES const&); + TransactionAccessList(dev::RLP const&); + + DataObject const asDataObject(ExportOrder _order = ExportOrder::Default) const override; + TransactionType type() const override { return TransactionType::ACCESSLIST; } + +private: + void fromRLP(dev::RLP const&) override; + + void buildVRS(VALUE const& _secret) override; + void streamHeader(dev::RLPStream& _stream) const override; + + void rebuildRLP() override; + spAccessList m_accessList; +}; + +typedef GCP_SPointer spTransactionAccessList; + +} // namespace teststruct +} // namespace test diff --git a/retesteth/testStructures/types/Ethereum/TransactionReader.cpp b/retesteth/testStructures/types/Ethereum/TransactionReader.cpp new file mode 100644 index 000000000..c423af53f --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/TransactionReader.cpp @@ -0,0 +1,58 @@ +#include "TransactionReader.h" +#include "TransactionAccessList.h" +#include + +using namespace dataobject; +using namespace test::teststruct; + +namespace +{ + +spTransaction _readTransaction(TransactionType _t, dev::RLP const& _rlp) +{ + spTransaction spTr; + switch (_t) + { + case TransactionType::LEGACY: + spTr = spTransaction(new Transaction(_rlp)); + break; + case TransactionType::ACCESSLIST: + spTr = spTransaction(new TransactionAccessList(_rlp)); + break; + } + return spTr; +} + +} // namespace +namespace test +{ +namespace teststruct +{ +spTransaction readTransaction(BYTES const& _rlp) +{ + dev::bytes decodeRLP = test::sfromHex(_rlp.asString()); + dev::RLP rlp(decodeRLP, dev::RLP::VeryStrict); + return readTransaction(rlp); +} + +spTransaction readTransaction(dev::RLP const& _rlp) +{ + if (_rlp.isData()) + { + dev::bytesConstRef const& p = _rlp.payload(); + dev::RLP realRLP(p.cropped(1, p.size() - 1), dev::RLP::VeryStrict); + return _readTransaction(TransactionType::ACCESSLIST, realRLP); + } + else + return _readTransaction(TransactionType::LEGACY, _rlp); +} + +spTransaction readTransaction(DataObject const& _filledData) +{ + if (_filledData.count("accessList")) + return spTransaction(new TransactionAccessList(_filledData)); + return spTransaction(new Transaction(_filledData)); +} + +} // namespace teststruct +} // namespace test diff --git a/retesteth/testStructures/types/Ethereum/TransactionReader.h b/retesteth/testStructures/types/Ethereum/TransactionReader.h new file mode 100644 index 000000000..a96513446 --- /dev/null +++ b/retesteth/testStructures/types/Ethereum/TransactionReader.h @@ -0,0 +1,16 @@ +#include "Transaction.h" +#include "TransactionAccessList.h" + +using namespace dataobject; +using namespace test::teststruct; + +namespace test +{ +namespace teststruct +{ +spTransaction readTransaction(DataObject const& _filledData); +spTransaction readTransaction(BYTES const& _rlp); +spTransaction readTransaction(dev::RLP const& _rlp); + +} // namespace teststruct +} // namespace test diff --git a/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.cpp b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.cpp index be1bc6029..75e3b9378 100644 --- a/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.cpp +++ b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.cpp @@ -22,7 +22,9 @@ EthGetBlockByTransaction::EthGetBlockByTransaction(DataObject const& _data) _dataFieldRef = "0x"; } - m_transaction = spTransaction(new Transaction(_data)); + // Construct transaction from json rpc request + m_transaction = readTransaction(_data); + m_blockHash = spFH32(new FH32(_data.atKey("blockHash"))); m_blockNumber = spVALUE(new VALUE(_data.atKey("blockNumber"))); m_from = spFH20(new FH20(_data.atKey("from"))); diff --git a/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.h b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.h index 9f6a62a08..f00635ea4 100644 --- a/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.h +++ b/retesteth/testStructures/types/RPC/SubElements/EthGetBlockByTransaction.h @@ -14,10 +14,10 @@ struct EthGetBlockByTransaction { EthGetBlockByTransaction(DataObject const&); FH32 const& hash() const { return m_hash.getCContent(); } - Transaction const& transaction() const + spTransaction const& transaction() const { assert(isFullTransaction()); - return m_transaction.getCContent(); + return m_transaction; } bool isFullTransaction() const { return !m_transaction.isEmpty(); } FH32 const& blockHash() const diff --git a/retesteth/testStructures/types/RPC/SubElements/ToolResponseReceipt.cpp b/retesteth/testStructures/types/RPC/SubElements/ToolResponseReceipt.cpp index bb4ec9601..70f3f65b2 100644 --- a/retesteth/testStructures/types/RPC/SubElements/ToolResponseReceipt.cpp +++ b/retesteth/testStructures/types/RPC/SubElements/ToolResponseReceipt.cpp @@ -13,7 +13,8 @@ ToolResponseReceipt::ToolResponseReceipt(DataObject const& _data) m_trGasUsed = spVALUE(new VALUE(_data.atKey("gasUsed"))); requireJsonFields(_data, "ToolResponseReceipt " + _data.getKey(), - {{"root", {{DataType::String}, jsonField::Required}}, + {{"type", {{DataType::String}, jsonField::Optional}}, + {"root", {{DataType::String}, jsonField::Required}}, {"status", {{DataType::String}, jsonField::Required}}, {"cumulativeGasUsed", {{DataType::String}, jsonField::Required}}, {"logsBloom", {{DataType::String}, jsonField::Required}}, diff --git a/retesteth/testStructures/types/StateTests/Base/AccessList.cpp b/retesteth/testStructures/types/StateTests/Base/AccessList.cpp new file mode 100644 index 000000000..7181a2d30 --- /dev/null +++ b/retesteth/testStructures/types/StateTests/Base/AccessList.cpp @@ -0,0 +1,71 @@ +#include "AccessList.h" +#include +#include + +namespace test +{ +namespace teststruct +{ +AccessListElement::AccessListElement(DataObject const& _data) +{ + m_address = spFH20(new FH20(_data.atKey("address"))); + for (auto const& el : _data.atKey("storageKeys").getSubObjects()) + m_storageKeys.push_back(spFH32(new FH32(dev::toCompactHexPrefixed(dev::u256(el.asString()), 32)))); + + requireJsonFields(_data, "AccessListElement " + _data.getKey(), + {{"address", {{DataType::String}, jsonField::Required}}, {"storageKeys", {{DataType::Array}, jsonField::Required}}}); +} + +AccessList::AccessList(DataObject const& _data) +{ + for (auto const& el : _data.getSubObjects()) + m_list.push_back(spAccessListElement(new AccessListElement(el))); +} + +DataObject AccessList::asDataObject() const +{ + DataObject accessList(DataType::Array); + for (auto const& el : m_list) + { + DataObject accessListElement; + accessListElement["address"] = el.getCContent().address().asString(); + DataObject keys(DataType::Array); + for (auto const& el2 : el.getCContent().keys()) + keys.addArrayObject(el2.getCContent().asString()); + accessListElement["storageKeys"] = keys; + accessList.addArrayObject(accessListElement); + } + return accessList; +} + +const dev::RLPStream AccessListElement::asRLPStream() const +{ + dev::RLPStream stream(2); + stream << dev::Address(m_address.getCContent().asString()); + + dev::RLPStream storages(m_storageKeys.size()); + for (auto const& key : m_storageKeys) + storages << dev::h256(key.getCContent().asString()); + // storages << dev::u256(key.asString()); + + stream.appendRaw(storages.out()); + return stream; +} + +AccessListElement::AccessListElement(dev::RLP const& _rlp) +{ + size_t i = 0; + m_address = spFH20(new FH20(rlpToString(_rlp[i++]))); + auto const& rlplist = _rlp[i++].toList(); + for (auto const& key : rlplist) + m_storageKeys.push_back(spFH32(new FH32(rlpToString(key)))); +} + +AccessList::AccessList(dev::RLP const& _rlp) +{ + for (auto const& accList : _rlp.toList()) + m_list.push_back(spAccessListElement(new AccessListElement(accList))); +} + +} // namespace teststruct +} // namespace test diff --git a/retesteth/testStructures/types/StateTests/Base/AccessList.h b/retesteth/testStructures/types/StateTests/Base/AccessList.h new file mode 100644 index 000000000..2641d74b3 --- /dev/null +++ b/retesteth/testStructures/types/StateTests/Base/AccessList.h @@ -0,0 +1,41 @@ +#pragma once +#include +#include +#include +using namespace dataobject; + +namespace test +{ +namespace teststruct +{ +struct AccessListElement : GCP_SPointerBase +{ + AccessListElement(DataObject const&); + AccessListElement(dev::RLP const& _el); + FH20 const& address() const { return m_address.getCContent(); } + std::vector const& keys() const { return m_storageKeys; } + const dev::RLPStream asRLPStream() const; + +private: + spFH20 m_address; + std::vector m_storageKeys; +}; + +typedef GCP_SPointer spAccessListElement; + +struct AccessList : GCP_SPointerBase +{ + AccessList(){}; + AccessList(DataObject const&); + AccessList(dev::RLP const& _rlp); + DataObject asDataObject() const; + std::vector const& list() const { return m_list; } + +private: + std::vector m_list; +}; + +typedef GCP_SPointer spAccessList; + +} // namespace teststruct +} // namespace test diff --git a/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.cpp b/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.cpp index 82df8d0a5..434a7ef8b 100644 --- a/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.cpp +++ b/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.cpp @@ -8,8 +8,25 @@ const DataObject StateTestTransactionBase::asDataObject() const { // Serialize data back to JSON DataObject out; - for (BYTES const& el : m_data) - out["data"].addArrayObject(el.asString()); + size_t index = 0; + bool atLeastOneNonNullAccessList = false; + DataObject txAccessListData(DataType::Array); + for (Databox const& el : m_databox) + { + out["data"].addArrayObject(el.m_data.asString()); + if (el.m_accessList.isEmpty()) + txAccessListData.addArrayObject(DataObject(DataType::Null)); + else + { + txAccessListData.addArrayObject(el.m_accessList.getCContent().asDataObject()); + atLeastOneNonNullAccessList = true; + } + index++; + } + + if (atLeastOneNonNullAccessList) + out["accessLists"] = txAccessListData; + for (VALUE const& el : m_gasLimit) out["gasLimit"].addArrayObject(el.asString()); out["gasPrice"] = m_gasPrice.getCContent().asString(); @@ -30,16 +47,17 @@ std::vector StateTestTransactionBase::buildTransact { // Construct vector of all transactions that are described int data std::vector out; - for (size_t dIND = 0; dIND < m_data.size(); dIND++) + for (size_t dIND = 0; dIND < m_databox.size(); dIND++) { for (size_t gIND = 0; gIND < m_gasLimit.size(); gIND++) { for (size_t vIND = 0; vIND < m_value.size(); vIND++) { + Databox const& databox = m_databox.at(dIND); if (ExitHandler::receivedExitSignal()) return out; DataObject trData; - trData["data"] = m_data.at(dIND).asString(); + trData["data"] = databox.m_data.asString(); trData["gasLimit"] = m_gasLimit.at(gIND).asString(); trData["value"] = m_value.at(vIND).asString(); @@ -50,7 +68,13 @@ std::vector StateTestTransactionBase::buildTransact else trData["to"] = m_to.getCContent().asString(); trData["secretKey"] = m_secretKey.getCContent().asString(); - out.push_back(TransactionInGeneralSection(trData, dIND, gIND, vIND)); + + // Export Access List + if (!databox.m_accessList.isEmpty()) + trData["accessList"] = databox.m_accessList.getCContent().asDataObject(); + + out.push_back( + TransactionInGeneralSection(trData, dIND, gIND, vIND, databox.m_dataRawPreview, databox.m_dataLabel)); } } } diff --git a/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.h b/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.h index 4fa9c80b8..0f497fd02 100644 --- a/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.h +++ b/retesteth/testStructures/types/StateTests/Base/StateTestTransactionBase.h @@ -1,5 +1,6 @@ #pragma once #include "../../../basetypes.h" +#include "AccessList.h" #include "TransactionInGeneralSection.h" #include #include @@ -16,9 +17,23 @@ struct StateTestTransactionBase : GCP_SPointerBase DataObject const asDataObject() const; std::vector buildTransactions() const; + struct Databox + { + Databox(BYTES const& _data, string const& _label, string const& _rawPreview, + spAccessList const& _accessList = spAccessList(0)) + : m_data(_data), m_dataLabel(_label), m_dataRawPreview(_rawPreview), m_accessList(_accessList) + {} + BYTES m_data; + string m_dataLabel; + string m_dataRawPreview; // The source code preview before code compilation + spAccessList m_accessList; + }; + + std::vector const& databoxVector() const { return m_databox; }; + protected: StateTestTransactionBase(){}; - std::vector m_data; + std::vector m_databox; std::vector m_gasLimit; std::vector m_value; spVALUE m_gasPrice; diff --git a/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.cpp b/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.cpp index d0415a9d4..57434e52b 100644 --- a/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.cpp +++ b/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.cpp @@ -3,8 +3,12 @@ using namespace test::teststruct; -TransactionInGeneralSection::TransactionInGeneralSection(DataObject const& _tr, size_t _dInd, size_t _gInd, size_t _vInd) +TransactionInGeneralSection::TransactionInGeneralSection( + DataObject const& _tr, size_t _dInd, size_t _gInd, size_t _vInd, string const& _dataRawPreview, string const& _dataLabel) : m_dInd(_dInd), m_gInd(_gInd), m_vInd(_vInd), m_executed(false), m_skipped(false) { - m_tr = spTransaction(new Transaction(_tr)); + if (_tr.count("accessList")) + m_tr = spTransaction(new TransactionAccessList(_tr, _dataRawPreview, _dataLabel)); + else + m_tr = spTransaction(new Transaction(_tr, _dataRawPreview, _dataLabel)); } diff --git a/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.h b/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.h index e2e9b64bf..dbddd7534 100644 --- a/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.h +++ b/retesteth/testStructures/types/StateTests/Base/TransactionInGeneralSection.h @@ -1,5 +1,6 @@ #pragma once #include "../../Ethereum/Transaction.h" +#include "../../Ethereum/TransactionAccessList.h" #include #include @@ -14,7 +15,8 @@ namespace teststruct // This is a single transaction representation struct TransactionInGeneralSection { - TransactionInGeneralSection(DataObject const&, size_t _dInd, size_t _gInd, size_t _vInd); + TransactionInGeneralSection( + DataObject const&, size_t _dInd, size_t _gInd, size_t _vInd, string const& _dataRawPreview, string const& _dataLabel); size_t dataInd() const { return m_dInd; } size_t gasInd() const { return m_gInd; } size_t valueInd() const { return m_vInd; } diff --git a/retesteth/testStructures/types/StateTests/Filled/Info.cpp b/retesteth/testStructures/types/StateTests/Filled/Info.cpp index f12168072..21b4a3790 100644 --- a/retesteth/testStructures/types/StateTests/Filled/Info.cpp +++ b/retesteth/testStructures/types/StateTests/Filled/Info.cpp @@ -13,13 +13,19 @@ Info::Info(DataObject const& _data) m_lllcversion = _data.atKey("lllcversion").asString(); m_source = _data.atKey("source").asString(); m_sourceHash = _data.atKey("sourceHash").asString(); + + if (_data.count("labels")) + { + for (auto const& el : _data.atKey("labels").getSubObjects()) + m_labels.emplace(el.getKey(), el.asString()); + } + requireJsonFields(_data, "Info " + _data.getKey(), - { {"comment", {{DataType::String}, jsonField::Required}}, + {{"comment", {{DataType::String}, jsonField::Required}}, {"filling-rpc-server", {{DataType::String}, jsonField::Required}}, {"filling-tool-version", {{DataType::String}, jsonField::Required}}, - {"lllcversion", {{DataType::String}, jsonField::Required}}, - {"source", {{DataType::String}, jsonField::Required}}, - {"sourceHash", {{DataType::String}, jsonField::Required}}}); + {"lllcversion", {{DataType::String}, jsonField::Required}}, {"source", {{DataType::String}, jsonField::Required}}, + {"sourceHash", {{DataType::String}, jsonField::Required}}, {"labels", {{DataType::Object}, jsonField::Optional}}}); } } // namespace teststruct diff --git a/retesteth/testStructures/types/StateTests/Filled/Info.h b/retesteth/testStructures/types/StateTests/Filled/Info.h index 450844213..ef58d8d50 100644 --- a/retesteth/testStructures/types/StateTests/Filled/Info.h +++ b/retesteth/testStructures/types/StateTests/Filled/Info.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include using namespace dataobject; namespace test @@ -16,6 +17,7 @@ struct Info : GCP_SPointerBase string const& lllcversion() const { return m_lllcversion; } string const& source() const { return m_source; } string const& sourceHash() const { return m_sourceHash; } + std::map const& labels() const { return m_labels; } private: Info() {} @@ -25,6 +27,7 @@ struct Info : GCP_SPointerBase string m_lllcversion; string m_source; string m_sourceHash; + std::map m_labels; }; typedef GCP_SPointer spInfo; diff --git a/retesteth/testStructures/types/StateTests/Filled/StateTestPostResult.cpp b/retesteth/testStructures/types/StateTests/Filled/StateTestPostResult.cpp index 563c1c93d..e135b044f 100644 --- a/retesteth/testStructures/types/StateTests/Filled/StateTestPostResult.cpp +++ b/retesteth/testStructures/types/StateTests/Filled/StateTestPostResult.cpp @@ -12,9 +12,12 @@ StateTestPostResult::StateTestPostResult(DataObject const& _data) m_valInd = _data.atKey("indexes").atKey("value").asInt(); m_hash = spFH32(new FH32(_data.atKey("hash").asString())); m_log = spFH32(new FH32(_data.atKey("logs").asString())); + if (_data.count("txbytes")) + m_txbytes = spBYTES(new BYTES(_data.atKey("txbytes").asString())); requireJsonFields(_data, "StateTestPostResult " + _data.getKey(), {{"indexes", {{DataType::Object}, jsonField::Required}}, {"hash", {{DataType::String}, jsonField::Required}}, + {"txbytes", {{DataType::String}, jsonField::Optional}}, {"logs", {{DataType::String}, jsonField::Required}}}); } diff --git a/retesteth/testStructures/types/StateTests/Filled/StateTestPostResult.h b/retesteth/testStructures/types/StateTests/Filled/StateTestPostResult.h index 25af4ff2d..61495c04b 100644 --- a/retesteth/testStructures/types/StateTests/Filled/StateTestPostResult.h +++ b/retesteth/testStructures/types/StateTests/Filled/StateTestPostResult.h @@ -18,6 +18,7 @@ struct StateTestPostResult : GCP_SPointerBase } FH32 const& hash() const { return m_hash.getCContent(); } FH32 const& logs() const { return m_log.getCContent(); } + spBYTES const& bytesPtr() const { return m_txbytes; } DataObject const asDataObject() const; private: @@ -27,6 +28,7 @@ struct StateTestPostResult : GCP_SPointerBase int m_valInd; spFH32 m_hash; spFH32 m_log; + spBYTES m_txbytes; }; typedef std::vector StateTestPostResults; diff --git a/retesteth/testStructures/types/StateTests/Filled/StateTestTransaction.cpp b/retesteth/testStructures/types/StateTests/Filled/StateTestTransaction.cpp index 132923f47..cc9c143ba 100644 --- a/retesteth/testStructures/types/StateTests/Filled/StateTestTransaction.cpp +++ b/retesteth/testStructures/types/StateTests/Filled/StateTestTransaction.cpp @@ -21,21 +21,48 @@ StateTestTransaction::StateTestTransaction(DataObject const& _data) m_gasPrice = spVALUE(new VALUE(_data.atKey("gasPrice"))); m_nonce = spVALUE(new VALUE(_data.atKey("nonce"))); + std::vector accessLists; + if (_data.count("accessLists")) + { + for (auto const& el : _data.atKey("accessLists").getSubObjects()) + { + if (el.type() == DataType::Null) + accessLists.push_back(spAccessList(0)); + else + accessLists.push_back(spAccessList(new AccessList(el))); + } + } + + size_t index = 0; + if (_data.count("accessLists")) + if (accessLists.size() != _data.atKey("data").getSubObjects().size()) + ETH_ERROR_MESSAGE("`AccessLists` array length must match `data` array length!"); + for (auto const& el : _data.atKey("data").getSubObjects()) - m_data.push_back(el); + { + DataObject dataInKey = el; + if (accessLists.size()) + { + if (accessLists.at(index).isEmpty()) + m_databox.push_back(Databox(dataInKey, dataInKey.asString(), string())); + else + m_databox.push_back(Databox(dataInKey, dataInKey.asString(), string(), accessLists.at(index))); + } + else + m_databox.push_back(Databox(dataInKey, dataInKey.asString(), string())); + + index++; + } for (auto const& el : _data.atKey("gasLimit").getSubObjects()) m_gasLimit.push_back(el); for (auto const& el : _data.atKey("value").getSubObjects()) m_value.push_back(el); requireJsonFields(_data, "StateTestTransaction " + _data.getKey(), - {{"data", {{DataType::Array}, jsonField::Required}}, - {"gasLimit", {{DataType::Array}, jsonField::Required}}, - {"gasPrice", {{DataType::String}, jsonField::Required}}, - {"nonce", {{DataType::String}, jsonField::Required}}, - {"value", {{DataType::Array}, jsonField::Required}}, - {"to", {{DataType::String}, jsonField::Required}}, - {"secretKey", {{DataType::String}, jsonField::Required}}}); + {{"data", {{DataType::Array}, jsonField::Required}}, {"accessLists", {{DataType::Array}, jsonField::Optional}}, + {"gasLimit", {{DataType::Array}, jsonField::Required}}, {"gasPrice", {{DataType::String}, jsonField::Required}}, + {"nonce", {{DataType::String}, jsonField::Required}}, {"value", {{DataType::Array}, jsonField::Required}}, + {"to", {{DataType::String}, jsonField::Required}}, {"secretKey", {{DataType::String}, jsonField::Required}}}); } catch (std::exception const& _ex) { diff --git a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.cpp b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.cpp index 7681c786e..c6c45ce39 100644 --- a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.cpp +++ b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.cpp @@ -7,11 +7,82 @@ namespace test { namespace teststruct { -StateTestFillerExpectSection::StateTestFillerExpectSection(DataObject const& _data) +// Look at expect section data indexes filter and try to replace string values +// into indexes of transaction data array (searching by label) +DataObject ReplaceValueToIndexesInDataList(spStateTestFillerTransaction const& _gtr, DataObject const& _dataList) +{ + auto findIndexOfValueAndReplace = [&_gtr](DataObject& _data) { + if (_data.type() == DataType::String) + { + size_t i = 0; + std::vector indexes; + const vector& dVector = _gtr.getCContent().databoxVector(); + for (auto const& el : dVector) + { + if (el.m_dataLabel == _data.asString()) + indexes.push_back(i); + i++; + } + + if (indexes.size() == 1) + { + _data.clear(); + _data.setInt(indexes.at(0)); + } + if (indexes.size() > 1) + { + _data.clear(); + for (auto const& el : indexes) + _data.addArrayObject(el); + } + if (indexes.size() == 0 && _data.asString().find(":label") != string::npos) + ETH_ERROR_MESSAGE("Label not found in tx data: `" + _data.asString() + "`"); + } + }; + // Check if dataIndexes contain values of transaction data vector + // Find those values and vector and replace by indexes + DataObject dataIndexes = _dataList; + if (dataIndexes.type() == DataType::Array) + { + DataObject updatedDataIndexes; + for (auto& el : dataIndexes.getSubObjectsUnsafe()) + { + // try to replace `el` with data indexes from transaction + // in case `el` provided is a transaction value in dataInd array + if (el.type() == DataType::String) + { + DataObject elCopy = el; + findIndexOfValueAndReplace(elCopy); + if (elCopy.type() == DataType::Integer) + { + el = elCopy; + updatedDataIndexes.addArrayObject(el); + } + else if (elCopy.type() == DataType::Array) + { + for (auto const& el2 : elCopy.getSubObjects()) + updatedDataIndexes.addArrayObject(el2); + } + else + updatedDataIndexes.addArrayObject(el); + } + else + updatedDataIndexes.addArrayObject(el); + } + dataIndexes = updatedDataIndexes; + } + else if (dataIndexes.type() == DataType::String) + findIndexOfValueAndReplace(dataIndexes); + dataIndexes.setKey(_dataList.getKey()); + return dataIndexes; +} + +StateTestFillerExpectSection::StateTestFillerExpectSection(DataObject const& _data, spStateTestFillerTransaction const& _gtr) { try { - parseJsonIntValueIntoSet(_data.atKey("indexes").atKey("data"), m_dataInd); + DataObject dataIndexes = ReplaceValueToIndexesInDataList(_gtr, _data.atKey("indexes").atKey("data")); + parseJsonIntValueIntoSet(dataIndexes, m_dataInd); parseJsonIntValueIntoSet(_data.atKey("indexes").atKey("gas"), m_gasInd); parseJsonIntValueIntoSet(_data.atKey("indexes").atKey("value"), m_valInd); @@ -36,7 +107,7 @@ StateTestFillerExpectSection::StateTestFillerExpectSection(DataObject const& _da } catch (std::exception const& _ex) { - throw UpwardsException(string("StateTestFillerExpectSection parse error: ") + _ex.what() + _data.asJson()); + throw UpwardsException(string("StateTestFillerExpectSection parse error: ") + _ex.what() + "\n" + _data.asJson()); } } diff --git a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.h b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.h index 71307dfcf..6747ed6e1 100644 --- a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.h +++ b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerExpectSection.h @@ -3,6 +3,7 @@ #include "../../../types/Ethereum/StateIncomplete.h" #include #include +#include using namespace dataobject; using namespace test::teststruct; @@ -12,7 +13,7 @@ namespace teststruct { struct StateTestFillerExpectSection { - StateTestFillerExpectSection(DataObject const&); + StateTestFillerExpectSection(DataObject const&, spStateTestFillerTransaction const&); StateIncomplete const& result() const { return m_result.getCContent(); } std::vector const& forks() const { return m_forks; } bool hasFork(FORK const& _fork) const diff --git a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.cpp b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.cpp index 3131b0a58..7f89e7e7e 100644 --- a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.cpp +++ b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.cpp @@ -35,12 +35,43 @@ StateTestFillerTransaction::StateTestFillerTransaction(DataObject const& _data) for (auto const& el : _data.atKey("data").getSubObjects()) { + DataObject dataInKey; + spAccessList accessList; + if (el.type() == DataType::Object) + { + dataInKey = el.atKey("data"); + accessList = spAccessList(new AccessList(el.atKey("accessList"))); + requireJsonFields(el, "StateTestFillerTransaction::dataWithList " + _data.getKey(), + {{"data", {{DataType::String}, jsonField::Required}}, + {"accessList", {{DataType::Array}, jsonField::Required}}}); + } + else + dataInKey = el; + // -- Compile LLL in transaction data into byte code if not already - DataObject dataInKey = el; dataInKey.setKey("`data` array element in General Transaction Section"); // Hint - dataInKey.setString(test::compiler::replaceCode(dataInKey.asString())); + + string label; + string rawData = dataInKey.asString(); + std::string const c_labelPrefix = ":label"; + if (rawData.find(c_labelPrefix) != string::npos) + { + size_t const pos = rawData.find(c_labelPrefix); + size_t const posEnd = rawData.find(' ', pos + c_labelPrefix.size() + 1); + if (posEnd != string::npos) + { + label = rawData.substr(pos, posEnd - pos); + rawData = rawData.substr(posEnd + 1); // remove label before code parsing + } + else + { + label = rawData.substr(pos); + rawData = ""; + } + } + dataInKey.setString(test::compiler::replaceCode(rawData)); // --- - m_data.push_back(dataInKey); + m_databox.push_back(Databox(dataInKey, label, rawData.substr(0, 20), accessList)); } for (auto const& el : tmpD.atKey("gasLimit").getSubObjects()) m_gasLimit.push_back(el); diff --git a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.h b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.h index 3b155e882..83df50a22 100644 --- a/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.h +++ b/retesteth/testStructures/types/StateTests/Filler/StateTestFillerTransaction.h @@ -19,5 +19,7 @@ struct StateTestFillerTransaction : StateTestTransactionBase StateTestFillerTransaction(DataObject const&); }; +typedef GCP_SPointer spStateTestFillerTransaction; + } // namespace teststruct } // namespace test diff --git a/retesteth/testStructures/types/StateTests/GeneralStateTestFiller.cpp b/retesteth/testStructures/types/StateTests/GeneralStateTestFiller.cpp index dc6f3315b..1a4d009ab 100644 --- a/retesteth/testStructures/types/StateTests/GeneralStateTestFiller.cpp +++ b/retesteth/testStructures/types/StateTests/GeneralStateTestFiller.cpp @@ -39,9 +39,9 @@ StateTestInFiller::StateTestInFiller(DataObject const& _data) solidityCode = test::compiler::compileSolidity(_data.atKey("solidity").asString()); m_pre = spState(new State(convertDecStateToHex(_data.atKey("pre"), solidityCode))); - m_transaction = GCP_SPointer(new StateTestFillerTransaction(_data.atKey("transaction"))); + m_transaction = spStateTestFillerTransaction(new StateTestFillerTransaction(_data.atKey("transaction"))); for (auto const& el : _data.atKey("expect").getSubObjects()) - m_expectSections.push_back(StateTestFillerExpectSection(el)); + m_expectSections.push_back(StateTestFillerExpectSection(el, m_transaction)); ETH_ERROR_REQUIRE_MESSAGE(m_expectSections.size() > 0, "StateTestFiller require expect sections!"); m_name = _data.getKey(); diff --git a/retesteth/testSuites/CompareStates.cpp b/retesteth/testSuites/CompareStates.cpp index 6a950dd2e..cf89be53b 100644 --- a/retesteth/testSuites/CompareStates.cpp +++ b/retesteth/testSuites/CompareStates.cpp @@ -160,7 +160,16 @@ CompareResult compareStorage(Storage const& _expectStorage, Storage const& _remo if (_expectStorage.getKeys().size() < _remoteStorage.getKeys().size()) { - ETH_MARK_ERROR(message + " has more storage records than expected!"); + string storage = message + " has more storage records than expected!"; + std::vector keys; + for (auto const& el : _remoteStorage.getKeys()) + { + if (!_expectStorage.hasKey(VALUE(el.first))) + keys.push_back(el.first); + } + storage += "\n [" + keys.at(0) + "] = " + _remoteStorage.atKey(VALUE(keys.at(0))).asString(); + + ETH_MARK_ERROR(storage); result = CompareResult::IncorrectStorage; } @@ -240,12 +249,10 @@ void compareStates(StateBase const& _stateExpect, State const& _statePost) if (accountCompareResult != CompareResult::Success) result = accountCompareResult; } + if (Options::get().poststate) + ETH_STDOUT_MESSAGE("State Dump: \n" + _statePost.asDataObject().asJson()); if (result != CompareResult::Success) - { - if (Options::get().poststate) - ETH_STDOUT_MESSAGE("State Dump: \n" + _statePost.asDataObject().asJson()); ETH_ERROR_MESSAGE("CompareStates failed with errors: " + CompareResultToString(result)); - } } string CompareResultToString(CompareResult res) diff --git a/retesteth/testSuites/StateTests.cpp b/retesteth/testSuites/StateTests.cpp index 75e334b81..9f87f2c66 100644 --- a/retesteth/testSuites/StateTests.cpp +++ b/retesteth/testSuites/StateTests.cpp @@ -1,4 +1,4 @@ -/* +/* This file is part of cpp-ethereum. cpp-ethereum is free software: you can redistribute it and/or modify @@ -47,6 +47,7 @@ using namespace dev; using namespace test; using namespace test::teststruct; namespace fs = boost::filesystem; +string const c_trHashNotFound = "TR hash not found in mined block! (Check that tr is properly mined and not oog)"; namespace { @@ -56,7 +57,8 @@ bool OptionsAllowTransaction(test::teststruct::TransactionInGeneralSection const Options const& opt = Options::get(); if ((opt.trDataIndex == (int)_tr.dataInd() || opt.trDataIndex == -1) && (opt.trGasIndex == (int)_tr.gasInd() || opt.trGasIndex == -1) && - (opt.trValueIndex == (int)_tr.valueInd() || opt.trValueIndex == -1)) + (opt.trValueIndex == (int)_tr.valueInd() || opt.trValueIndex == -1) && + (opt.trDataLabel == _tr.transaction().dataLabel() || opt.trDataLabel.empty())) return true; return false; } @@ -73,7 +75,7 @@ void checkUnexecutedTransactions(std::vector const& atLeastOneExecuted = true; bool transactionExecutedOrSkipped = tr.getExecuted() || tr.getSkipped(); atLeastOneWithoutExpectSection = !transactionExecutedOrSkipped || atLeastOneWithoutExpectSection; - if (!transactionExecutedOrSkipped) + if (!transactionExecutedOrSkipped || atLeastOneWithoutExpectSection) { TestInfo errorInfo("all", (int)tr.dataInd(), (int)tr.gasInd(), (int)tr.valueInd()); TestOutputHelper::get().setCurrentTestInfo(errorInfo); @@ -130,8 +132,8 @@ DataObject FillTestAsBlockchain(StateTestInFiller const& _test) session.test_mineBlocks(1); VALUE latestBlockN(session.eth_blockNumber()); EthGetBlockBy remoteBlock(session.eth_getBlockByNumber(latestBlockN, Request::FULLOBJECTS)); - ETH_ERROR_REQUIRE_MESSAGE( - remoteBlock.hasTransaction(trHash), "StateTest::FillTest: TR hash not found in mined block!"); + if (!remoteBlock.hasTransaction(trHash)) + ETH_ERROR_MESSAGE("StateTest::FillTest: " + c_trHashNotFound); tr.markExecuted(); // Mining reward @@ -162,8 +164,6 @@ DataObject FillTestAsBlockchain(StateTestInFiller const& _test) aBlockchainTest["postStateHash"] = remoteBlock.header().stateRoot().asString(); } - - aBlockchainTest["network"] = fork.asString(); aBlockchainTest["sealEngine"] = sealEngineToStr(SealEngine::NoProof); aBlockchainTest["lastblockhash"] = remoteBlock.header().hash().asString(); @@ -211,6 +211,13 @@ DataObject FillTest(StateTestInFiller const& _test) // Gather Transactions from general transaction section std::vector txs = _test.GeneralTr().buildTransactions(); + for (auto const& tx : txs) + { + // Fill up the label map to tx.data + if (!tx.transaction().dataLabel().empty()) + filledTest["_info"]["labels"].addSubObject( + DataObject(test::fto_string(tx.dataInd()), tx.transaction().dataLabel())); + } // run transactions on all networks that we need for (auto const& fork : _test.getAllForksFromExpectSections()) // object constructed!!! @@ -236,6 +243,9 @@ DataObject FillTest(StateTestInFiller const& _test) for (auto& tr : txs) { TestInfo errorInfo(fork.asString(), tr.dataInd(), tr.gasInd(), tr.valueInd()); + if (!tr.transaction().dataLabel().empty() || !tr.transaction().dataRawPreview().empty()) + errorInfo.setTrDataDebug(tr.transaction().dataLabel() + " " + tr.transaction().dataRawPreview() + ".."); + TestOutputHelper::get().setCurrentTestInfo(errorInfo); if (!OptionsAllowTransaction(tr) || networkSkip) @@ -254,8 +264,8 @@ DataObject FillTest(StateTestInFiller const& _test) VALUE latestBlockN(session.eth_blockNumber()); EthGetBlockBy blockInfo(session.eth_getBlockByNumber(latestBlockN, Request::LESSOBJECTS)); - ETH_ERROR_REQUIRE_MESSAGE( - blockInfo.hasTransaction(trHash), "StateTest::FillTest: TR hash not found in mined block!"); + if (!blockInfo.hasTransaction(trHash)) + ETH_ERROR_MESSAGE("StateTest::FillTest: " + c_trHashNotFound); tr.markExecuted(); if (Options::get().poststate) @@ -281,6 +291,7 @@ DataObject FillTest(StateTestInFiller const& _test) transactionResults["indexes"] = indexes; transactionResults["hash"] = blockInfo.header().stateRoot().asString(); + transactionResults["txbytes"] = tr.transaction().getSignedRLP().asString(); // Fill up the loghash (optional) FH32 logHash(session.test_getLogHash(trHash)); @@ -345,6 +356,13 @@ void RunTest(StateTestInFilled const& _test) return; TestInfo errorInfo(network.asString(), tr.dataInd(), tr.gasInd(), tr.valueInd()); + + string label; + string const labelK = test::fto_string(tr.dataInd()); + if (_test.testInfo().labels().count(labelK)) + label = _test.testInfo().labels().at(labelK); + errorInfo.setTrDataDebug(label + " " + tr.transaction().dataLabel().substr(0, 8) + ".."); + TestOutputHelper::get().setCurrentTestInfo(errorInfo); bool checkIndexes = result.checkIndexes(tr.dataInd(), tr.gasInd(), tr.valueInd()); if (checkIndexes) @@ -364,8 +382,8 @@ void RunTest(StateTestInFilled const& _test) VALUE latestBlockN(session.eth_blockNumber()); EthGetBlockBy blockInfo(session.eth_getBlockByNumber(latestBlockN, Request::LESSOBJECTS)); - ETH_ERROR_REQUIRE_MESSAGE( - blockInfo.hasTransaction(trHash), "StateTest::RunTest: TR hash not found in mined block!"); + if (!blockInfo.hasTransaction(trHash)) + ETH_ERROR_MESSAGE("StateTest::RunTest: " + c_trHashNotFound); tr.markExecuted(); // Validate post state @@ -382,7 +400,15 @@ void RunTest(StateTestInFilled const& _test) ", expected: " + expectedPostHash.asString()); } if (Options::get().poststate) - ETH_LOG("\nState Dump:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + " \n" + getRemoteState(session).asDataObject().asJson(), 1); + ETH_LOG("\nRunning test State Dump:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + " \n" + getRemoteState(session).asDataObject().asJson(), 1); + + // Validate that txbytes field has the transaction data described in test `transaction` field. + spBYTES const& expectedBytesPtr = result.bytesPtr(); + if (!expectedBytesPtr.isEmpty()) + { + if (tr.transaction().getSignedRLP().asString() != expectedBytesPtr.getCContent().asString()) + ETH_ERROR_MESSAGE("TxBytes mismatch: test transaction section doest not match txbytes in post section!"); + } // Validate log hash FH32 const& expectedLogHash = result.logs(); @@ -394,8 +420,7 @@ void RunTest(StateTestInFilled const& _test) session.test_rewindToBlock(0); if (Options::get().logVerbosity >= 5) ETH_LOG("Executed: d: " + to_string(tr.dataInd()) + ", g: " + to_string(tr.gasInd()) + - ", v: " + to_string(tr.valueInd()) + ", fork: " + network.asString(), - 5); + ", v: " + to_string(tr.valueInd()) + ", fork: " + network.asString(), 5); } } //ForTransactions diff --git a/retesteth/testSuites/StateTests.h b/retesteth/testSuites/StateTests.h index b5685ef6a..696fce0d0 100644 --- a/retesteth/testSuites/StateTests.h +++ b/retesteth/testSuites/StateTests.h @@ -29,6 +29,8 @@ namespace test class StateTestSuite: public TestSuite { public: + StateTestSuite(); + StateTestSuite(int){}; DataObject doTests(DataObject const& _input, TestSuiteOptions& _opt) const override; TestSuite::TestPath suiteFolder() const override; TestSuite::FillerPath suiteFillerFolder() const override; @@ -43,6 +45,14 @@ class LegacyConstantinopleStateTestSuite : public StateTestSuite TestSuite::FillerPath suiteFillerFolder() const override; }; +class StateTestVMSuite: public StateTestSuite +{ +public: + StateTestVMSuite() : StateTestSuite(0){}; + TestSuite::TestPath suiteFolder() const override; + TestSuite::FillerPath suiteFillerFolder() const override; +}; + } diff --git a/retesteth/testSuites/StateTestsBoost.cpp b/retesteth/testSuites/StateTestsBoost.cpp index f80ef930a..f613047a0 100644 --- a/retesteth/testSuites/StateTestsBoost.cpp +++ b/retesteth/testSuites/StateTestsBoost.cpp @@ -23,6 +23,24 @@ TestSuite::FillerPath StateTestSuite::suiteFillerFolder() const return TestSuite::FillerPath(fs::path("src") / "GeneralStateTestsFiller"); } +StateTestSuite::StateTestSuite() +{ + // Register subtest as finished test case. because each folder is treated as test case folder + test::TestOutputHelper::get().markTestFolderAsFinished(getFullPathFiller("VMTests").parent_path(), "VMTests"); +} + +TestSuite::TestPath StateTestVMSuite::suiteFolder() const +{ + if (Options::get().fillchain) + return TestSuite::TestPath(fs::path("BlockchainTests") / "GeneralStateTests" / "VMTests"); + return TestSuite::TestPath(fs::path("GeneralStateTests") / "VMTests"); +} + +TestSuite::FillerPath StateTestVMSuite::suiteFillerFolder() const +{ + return TestSuite::FillerPath(fs::path("src") / "GeneralStateTestsFiller" / "VMTests"); +} + // Legacy Constantinople TestSuite::TestPath LegacyConstantinopleStateTestSuite::suiteFolder() const { @@ -110,7 +128,26 @@ BOOST_AUTO_TEST_CASE(stSelfBalance) {} BOOST_AUTO_TEST_CASE(stStaticFlagEnabled) {} BOOST_AUTO_TEST_CASE(stSubroutine) {} BOOST_AUTO_TEST_CASE(stEIP2537) {} +BOOST_AUTO_TEST_CASE(stEIP2930) {} // Heavy BOOST_AUTO_TEST_CASE(stTimeConsuming) {} + +// Converted VMTests +using GeneralStateTestsVMFixture = TestFixture; +BOOST_FIXTURE_TEST_SUITE(VMTests, GeneralStateTestsVMFixture) +BOOST_AUTO_TEST_CASE(vmArithmeticTest) {} +BOOST_AUTO_TEST_CASE(vmBitwiseLogicOperation) {} +BOOST_AUTO_TEST_CASE(vmBlockInfoTest) {} +BOOST_AUTO_TEST_CASE(vmEnvironmentalInfo) {} +BOOST_AUTO_TEST_CASE(vmIOandFlowOperations) {} +BOOST_AUTO_TEST_CASE(vmLogTest) {} +BOOST_AUTO_TEST_CASE(vmPerformance) {} +BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) {} +BOOST_AUTO_TEST_CASE(vmRandomTest) {} +BOOST_AUTO_TEST_CASE(vmSha3Test) {} +BOOST_AUTO_TEST_CASE(vmSystemOperations) {} +BOOST_AUTO_TEST_CASE(vmTests) {} +BOOST_AUTO_TEST_SUITE_END() + BOOST_AUTO_TEST_SUITE_END() diff --git a/retesteth/testSuites/VMTestsConverter.cpp b/retesteth/testSuites/VMTestsConverter.cpp index 43d028fb0..686793afc 100644 --- a/retesteth/testSuites/VMTestsConverter.cpp +++ b/retesteth/testSuites/VMTestsConverter.cpp @@ -122,6 +122,12 @@ DataObject VMTestConverterSuite::doTests(DataObject const& _input, TestSuiteOpti // Pre state bcTestFiller["pre"] = test.Pre().asDataObject(); + for (auto& acc : bcTestFiller["pre"].getSubObjectsUnsafe()) + { + const string val = acc.atKey("code").asString(); + if (val.size() > 2) + acc.atKeyUnsafe("code").setString(":raw " + val); + } // Insert sender account FH20 const sender(DataObject("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")); diff --git a/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp b/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp index 081ec2042..34476a17d 100644 --- a/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp +++ b/retesteth/testSuites/blockchain/BlockchainTestLogic.cpp @@ -54,6 +54,13 @@ void RunTest(BlockchainTestInFilled const& _test, TestSuite::TestSuiteOptions co // Check imported block against the fields in test // Check Blockheader EthGetBlockBy latestBlock(session.eth_getBlockByHash(blHash, Request::FULLOBJECTS)); + + for (auto const& tr : tblock.transactions()) + { + if (Options::get().vmtrace) + printVmTrace(session, tr.getCContent().hash(), latestBlock.header().stateRoot()); + } + bool condition = latestBlock.header() == tblock.header(); /*if (_opt.isLegacyTests) { @@ -104,7 +111,7 @@ void RunTest(BlockchainTestInFilled const& _test, TestSuite::TestSuiteOptions co // Verify transactions to one described in the fields ind = 0; - for (Transaction const& tr : tblock.transactions()) + for (spTransaction const& tr : tblock.transactions()) { if (ExitHandler::receivedExitSignal()) return; @@ -119,11 +126,12 @@ void RunTest(BlockchainTestInFilled const& _test, TestSuite::TestSuiteOptions co "(" + clientTr.blockNumber().asDecString() + " != " + tblock.header().number().asDecString() + ")"); - DataObject const testTr = tr.asDataObject(); - DataObject const remoteTr = clientTr.transaction().asDataObject(); - ETH_ERROR_REQUIRE_MESSAGE(clientTr.transaction() == tr, - "Error checking remote transaction, remote tr `" + remoteTr.asJson() + - "` is different to test tr `" + testTr.asJson() + "`)"); + BYTES const testTr = tr.getCContent().getSignedRLP(); + BYTES const remoteTr = clientTr.transaction().getCContent().getSignedRLP(); + + ETH_ERROR_REQUIRE_MESSAGE(remoteTr == testTr, "Error checking remote transaction, remote tr `" + + remoteTr.asString() + "` is different to test tr `" + + testTr.asString() + "`)"); } } diff --git a/retesteth/testSuites/blockchain/BlockchainTests.cpp b/retesteth/testSuites/blockchain/BlockchainTests.cpp index cc7cc3b66..232d26391 100644 --- a/retesteth/testSuites/blockchain/BlockchainTests.cpp +++ b/retesteth/testSuites/blockchain/BlockchainTests.cpp @@ -115,6 +115,21 @@ TestSuite::FillerPath BCGeneralStateTestsSuite::suiteFillerFolder() const return TestSuite::FillerPath(fs::path("src") / fs::path("GeneralStateTestsFiller")); } +BCGeneralStateTestsVMSuite::BCGeneralStateTestsVMSuite() +{ + test::TestOutputHelper::get().markTestFolderAsFinished(getFullPathFiller("VMTests").parent_path().parent_path(), "VMTests"); +} + +TestSuite::TestPath BCGeneralStateTestsVMSuite::suiteFolder() const +{ + return TestSuite::TestPath(fs::path("BlockchainTests") / "GeneralStateTests" / "VMTests"); +} + +TestSuite::FillerPath BCGeneralStateTestsVMSuite::suiteFillerFolder() const +{ + return TestSuite::FillerPath(fs::path("src") / fs::path("GeneralStateTestsFiller") / "VMTests"); +} + TestSuite::TestPath LegacyConstantinopleBCGeneralStateTestsSuite::suiteFolder() const { return TestSuite::TestPath( @@ -273,7 +288,26 @@ BOOST_AUTO_TEST_CASE(stSelfBalance) {} BOOST_AUTO_TEST_CASE(stStaticFlagEnabled) {} BOOST_AUTO_TEST_CASE(stSubroutine) {} BOOST_AUTO_TEST_CASE(stEIP2537) {} +BOOST_AUTO_TEST_CASE(stEIP2930) {} // Heavy BOOST_AUTO_TEST_CASE(stTimeConsuming) {} + +// Converted VMTests +using BCGeneralStateTestsVMFixture = TestFixture; +BOOST_FIXTURE_TEST_SUITE(VMTests, BCGeneralStateTestsVMFixture) +BOOST_AUTO_TEST_CASE(vmArithmeticTest) {} +BOOST_AUTO_TEST_CASE(vmBitwiseLogicOperation) {} +BOOST_AUTO_TEST_CASE(vmBlockInfoTest) {} +BOOST_AUTO_TEST_CASE(vmEnvironmentalInfo) {} +BOOST_AUTO_TEST_CASE(vmIOandFlowOperations) {} +BOOST_AUTO_TEST_CASE(vmLogTest) {} +BOOST_AUTO_TEST_CASE(vmPerformance) {} +BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) {} +BOOST_AUTO_TEST_CASE(vmRandomTest) {} +BOOST_AUTO_TEST_CASE(vmSha3Test) {} +BOOST_AUTO_TEST_CASE(vmSystemOperations) {} +BOOST_AUTO_TEST_CASE(vmTests) {} +BOOST_AUTO_TEST_SUITE_END() + BOOST_AUTO_TEST_SUITE_END() diff --git a/retesteth/testSuites/blockchain/BlockchainTests.h b/retesteth/testSuites/blockchain/BlockchainTests.h index ddc16a6be..5cf16c81b 100644 --- a/retesteth/testSuites/blockchain/BlockchainTests.h +++ b/retesteth/testSuites/blockchain/BlockchainTests.h @@ -47,6 +47,13 @@ class BCGeneralStateTestsSuite : public BlockchainTestValidSuite test::TestSuite::FillerPath suiteFillerFolder() const override; }; +class BCGeneralStateTestsVMSuite : public BCGeneralStateTestsSuite +{ +public: + BCGeneralStateTestsVMSuite(); + test::TestSuite::TestPath suiteFolder() const override; + test::TestSuite::FillerPath suiteFillerFolder() const override; +}; /// Suite run/check stateTests converted into blockchain by testeth class LegacyConstantinopleBCGeneralStateTestsSuite : public BlockchainTestValidSuite diff --git a/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp index c9a8623b0..be3c22af6 100644 --- a/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp +++ b/retesteth/testSuites/blockchain/fillers/BlockchainTestFillerLogic.cpp @@ -78,6 +78,9 @@ DataObject FillTest(BlockchainTestInFiller const& _test, TestSuite::TestSuiteOpt State remoteState(getRemoteState(session)); compareStates(expect.result(), remoteState); filledTest["postState"] = remoteState.asDataObject(ExportOrder::OldStyle); + if (Options::get().poststate) + ETH_STDOUT_MESSAGE("\nState Dump:" + TestOutputHelper::get().testInfo().errorDebug() + cDefault + + " \n" + filledTest.atKey("postState").asJson()); } catch (StateTooBig const&) { @@ -85,6 +88,11 @@ DataObject FillTest(BlockchainTestInFiller const& _test, TestSuite::TestSuiteOpt filledTest["postStateHash"] = finalBlock.header().stateRoot().asString(); } + if (Options::get().poststate) + ETH_STDOUT_MESSAGE("PostState " + TestOutputHelper::get().testInfo().errorDebug() + " : \n" + cDefault + + "Hash: " + finalBlock.header().stateRoot().asString()); + + filledTest["lastblockhash"] = finalBlock.header().hash().asString(); result.addSubObject(filledTest); } // expects count net diff --git a/retesteth/testSuites/blockchain/fillers/TestBlock.cpp b/retesteth/testSuites/blockchain/fillers/TestBlock.cpp index 5f3d992c7..6c74b03e5 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlock.cpp +++ b/retesteth/testSuites/blockchain/fillers/TestBlock.cpp @@ -27,7 +27,7 @@ DataObject TestBlock::asDataObject() const res["blockHeader"] = m_block.getCContent().header().asDataObject(); res["transactions"] = DataObject(DataType::Array); for (auto const& tr : m_block.getCContent().transactions()) - res["transactions"].addArrayObject(tr.asDataObject(ExportOrder::OldStyle)); + res["transactions"].addArrayObject(tr.getCContent().asDataObject(ExportOrder::OldStyle)); } res["rlp"] = m_rawRLP.getCContent().asString(); diff --git a/retesteth/testSuites/blockchain/fillers/TestBlock.h b/retesteth/testSuites/blockchain/fillers/TestBlock.h index f72c40356..ce2cd6c2a 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlock.h +++ b/retesteth/testSuites/blockchain/fillers/TestBlock.h @@ -14,7 +14,7 @@ class TestBlock BlockHeader const& getTestHeader() const { return m_block.getCContent().header(); } // Attach Transaction header to EthereumBlock (the one described in tests) - void registerTestTransaction(Transaction const& _tr) { m_block.getContent().addTransaction(_tr); } + void registerTestTransaction(spTransaction const& _tr) { m_block.getContent().addTransaction(_tr); } // Attach Uncle header to EthereumBlock (the one described in tests) void registerTestUncle(BlockHeader const& _uncle) { m_block.getContent().addUncle(_uncle); } diff --git a/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp b/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp index 55851331c..128a7ddb2 100644 --- a/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp +++ b/retesteth/testSuites/blockchain/fillers/TestBlockchain.cpp @@ -81,7 +81,7 @@ void TestBlockchain::generateBlock( typedef std::tuple testTrInfo; std::map testTransactionMap; for (auto const& tr : _block.transactions()) - testTransactionMap[tr.tr().hash()] = {spTransaction(new Transaction(tr.tr())), tr.isMarkedInvalid()}; + testTransactionMap[tr.tr().hash()] = {readTransaction(tr.tr().asDataObject()), tr.isMarkedInvalid()}; for (auto const& remoteTr : minedBlock.getCContent().transactions()) { @@ -93,8 +93,8 @@ void TestBlockchain::generateBlock( bool isMarkedInvalid = std::get<1>(testTransactionMap.at(remoteTr.hash())); if (!isMarkedInvalid) { - spTransaction const& tr = std::get<0>(testTransactionMap.at(remoteTr.hash())); - newBlock.registerTestTransaction(tr.getCContent()); + spTransaction const& spTr = std::get<0>(testTransactionMap.at(remoteTr.hash())); + newBlock.registerTestTransaction(spTr); } testTransactionMap.erase(remoteTr.hash()); } @@ -108,7 +108,7 @@ void TestBlockchain::generateBlock( { bool isMarkedInvalid = std::get<1>(leftoverTr.second); if (!isMarkedInvalid) - newBlock.registerTestTransaction(std::get<0>(leftoverTr.second).getCContent()); + newBlock.registerTestTransaction(std::get<0>(leftoverTr.second)); } // ------- @@ -131,14 +131,8 @@ GCP_SPointer TestBlockchain::mineBlock( m_session.test_mineBlocks(1); VALUE latestBlockNumber(m_session.eth_blockNumber()); - auto checkTransactions = [](size_t _trInBlocks, size_t _trInTest, size_t _trAllowedToFail) { - ETH_ERROR_REQUIRE_MESSAGE(_trInBlocks == _trInTest - _trAllowedToFail, - "BlockchainTest transaction execution failed! (remote " + fto_string(_trInBlocks) + " != test " + - fto_string(_trInTest) + ", allowedToFail = " + fto_string(_trAllowedToFail) + " )"); - }; - spFH32 minedBlockHash; - if (_blockInTest.hasBlockHeader() || _blockInTest.hasRelTimeStamp() || _blockInTest.uncles().size() > 0) + if (_blockInTest.hasBlockHeaderOverwrite(m_network) || _blockInTest.uncles().size() > 0) { // Need to overwrite the blockheader of a mined block with either blockHeader or uncles // Then import it again and see what client says, because mining with uncles not supported @@ -171,8 +165,34 @@ GCP_SPointer TestBlockchain::mineBlock( _rawRLP = remoteBlock.getCContent().getRLPHeaderTransactions(); } - checkTransactions(remoteBlock.getContent().transactions().size(), _blockInTest.transactions().size(), - _blockInTest.invalidTransactionCount()); + // check that transactions are good + for (auto const& trInTest : _blockInTest.transactions()) + { + auto const& container = remoteBlock.getCContent().transactions(); + auto result = std::find_if(container.begin(), container.end(), + [&trInTest](EthGetBlockByTransaction const& el) { return el.hash() == trInTest.tr().hash(); }); + if (result == container.end()) + { + if (!trInTest.isMarkedInvalid()) + ETH_WARNING( + "TestBlockchain::mineBlock transaction has unexpectedly failed to be mined (see logs --verbosity 6): \n" + + trInTest.tr().asDataObject().asJson()); + } + else + { + if (trInTest.isMarkedInvalid()) + ETH_WARNING("TestBlockchain::mineBlock transaction expected to failed but mined good: \n" + + trInTest.tr().asDataObject().asJson()); + } + } + + auto remoteTr = remoteBlock.getCContent().transactions().size(); + auto testblTr = _blockInTest.transactions().size(); + auto expectFails = _blockInTest.invalidTransactionCount(); + if (remoteTr != testblTr - expectFails) + ETH_ERROR_MESSAGE("BlockchainTest transaction execution failed! (remote " + fto_string(remoteTr) + " != test " + + fto_string(testblTr) + ", allowedToFail = " + fto_string(expectFails) + " )"); + return remoteBlock; } @@ -289,22 +309,27 @@ FH32 TestBlockchain::postmineBlockHeader(BlockchainTestFillerBlock const& _block for (auto const& un : _uncles) managedBlock.addUncle(un); - if (_blockInTest.hasBlockHeader()) - managedBlock.replaceHeader(_blockInTest.blockHeader().overwriteBlockHeader(managedBlock.header())); - - // Overwrite blockheader if defined in the test filler - if (_blockInTest.hasRelTimeStamp()) - { - EthGetBlockBy previousBlock(m_session.eth_getBlockByNumber(_latestBlockNumber - 1, Request::LESSOBJECTS)); - managedBlock.headerUnsafe().setTimestamp(previousBlock.header().timestamp().asU256() + _blockInTest.relTimeStamp()); - } - - // replace block with overwritten header bool weOverwriteHashFields = false; - if (_blockInTest.hasBlockHeader()) + if (_blockInTest.hasBlockHeaderOverwrite(m_network)) { - if (_blockInTest.blockHeader().hasUncleHash() || _blockInTest.blockHeader().hasTransactionHash()) - weOverwriteHashFields = true; + BlockHeaderOverwrite const& headerOverwrite = _blockInTest.getHeaderOverwrite(m_network); + if (headerOverwrite.hasBlockHeader()) + managedBlock.replaceHeader(headerOverwrite.header().overwriteBlockHeader(managedBlock.header())); + + // Overwrite blockheader if defined in the test filler + if (headerOverwrite.hasRelTimeStamp()) + { + EthGetBlockBy previousBlock(m_session.eth_getBlockByNumber(_latestBlockNumber - 1, Request::LESSOBJECTS)); + managedBlock.headerUnsafe().setTimestamp( + previousBlock.header().timestamp().asU256() + headerOverwrite.relTimeStamp()); + } + + // replace block with overwritten header + if (headerOverwrite.hasBlockHeader()) + { + if (headerOverwrite.header().hasUncleHash() || headerOverwrite.header().hasTransactionHash()) + weOverwriteHashFields = true; + } } if (!weOverwriteHashFields) diff --git a/retesteth/unitTests/dataObjectTests.cpp b/retesteth/unitTests/dataObjectTests.cpp index 41aeeb73c..6661852c0 100644 --- a/retesteth/unitTests/dataObjectTests.cpp +++ b/retesteth/unitTests/dataObjectTests.cpp @@ -503,7 +503,7 @@ BOOST_AUTO_TEST_CASE(dataobject_readJson15) } )"; DataObject dObj = ConvertJsoncppStringToData(data); - string res = R"({"array":[{}],"object":{}})"; + string res = R"({"array":[null],"object":null})"; BOOST_CHECK(dObj.asJson(0, false) == res); } @@ -809,4 +809,23 @@ BOOST_AUTO_TEST_CASE(dataobject_replace) BOOST_CHECK(data.asJson(0,false) == "{\"key2\":\"value2\"}"); } +BOOST_AUTO_TEST_CASE(dataobject_arrayhell) +{ + string const data = R"( + { + "array" : [ + [ + { + "address" : "0x0000000000000000000000000000000000001337", + "storageKeys" : [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000002" + ] + } + ] + ] + })"; + DataObject dObj = ConvertJsoncppStringToData(data, string(), true); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/retesteth/unitTests/expectSectionTests.cpp b/retesteth/unitTests/expectSectionTests.cpp new file mode 100644 index 000000000..31334dd20 --- /dev/null +++ b/retesteth/unitTests/expectSectionTests.cpp @@ -0,0 +1,376 @@ +#include +#include +#include +#include +#include +#include + +using namespace test; +using namespace dataobject; + +class Initializer : public TestOutputHelperFixture +{ +public: + Initializer() + { + for (auto const& config : Options::getDynamicOptions().getClientConfigs()) + { + Options::getDynamicOptions().setCurrentConfig(config); + break; + } + } +}; + +string const transactionCommon = R"( + "gasLimit" : ["400000"], + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : ["100000"] +)"; + +string const expectSectionCommon = R"( + "network" : ["Frontier"], + "result" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x00" : "0x00" } } + } +)"; + +StateTestFillerExpectSection makeExpectSection(string const& _tr, string const& _exp) +{ + spStateTestFillerTransaction spTransaction = + spStateTestFillerTransaction(new StateTestFillerTransaction(ConvertJsoncppStringToData(_tr))); + return StateTestFillerExpectSection(ConvertJsoncppStringToData(_exp), spTransaction); +} + +BOOST_FIXTURE_TEST_SUITE(ExpectSectionSuite, Initializer) + +BOOST_AUTO_TEST_CASE(expectIndexesM1) +{ + const string sTr = R"( + { + "data" : [ + ":label firstData :raw 0x11223344", + ":label secondData :raw 0x11223341" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : -1, + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); +} + +BOOST_AUTO_TEST_CASE(expectIndexesSingle) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223344", + ":raw 0x11223341" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : 1, + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == false); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); +} + +BOOST_AUTO_TEST_CASE(expectIndexesArray) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223344", + ":raw 0x11223341" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : [0,1], + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); +} + +BOOST_AUTO_TEST_CASE(expectIndexesSingleValue) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223344", + ":label secondData :raw 0x11223341" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : ":label secondData", + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == false); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); +} + +BOOST_AUTO_TEST_CASE(expectIndexesArrayValue) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223344", + ":label second :raw 0x11223341" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : [0, ":label second"], + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); +} + +BOOST_AUTO_TEST_CASE(expectIndexesArrayValueDouble) +{ + const string sTr = R"( + { + "data" : [ + ":label first :raw 0x11223344", + ":raw 0x11223341" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : [0, ":label first"], + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == false); +} + +BOOST_AUTO_TEST_CASE(expectIndexesSingleValueMultiple) +{ + const string sTr = R"( + { + "data" : [ + ":label second :raw 0x11223344", + ":label second :raw 0x11223344" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : ":label second", + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); +} + +BOOST_AUTO_TEST_CASE(expectIndexesArrayValueMultiple) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223341" + ":label second :raw 0x11223344", + ":label second :raw 0x11223344" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : [":label second"], + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == false); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(2, 0, 0) == true); +} + +BOOST_AUTO_TEST_CASE(expectIndexesRange) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223341" + ":raw 0x11223344", + ":raw 0x11223344" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : "1-2", + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == false); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(2, 0, 0) == true); +} + +BOOST_AUTO_TEST_CASE(expectIndexesRangeWrong) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223341" + ":raw 0x11223344", + ":raw 0x11223344" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : "1-2-3", + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + try + { + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(string("exception expected").size() == 0); + } + catch (std::exception const&) + { + TestOutputHelper::get().unmarkLastError(); + } +} + +BOOST_AUTO_TEST_CASE(expectIndexesRangeArray) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223341" + ":raw 0x11223344", + ":raw 0x11223344" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : ["1-3", 4, "5-5"], + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == false); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(2, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(3, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(4, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(5, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(6, 0, 0) == false); +} + +BOOST_AUTO_TEST_CASE(expectIndexesArrayNormal) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223341" + ":raw 0x11223344", + ":raw 0x11223344" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : [0, 2, 3], + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(expectSection.checkIndexes(0, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(1, 0, 0) == false); + BOOST_CHECK(expectSection.checkIndexes(2, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(3, 0, 0) == true); + BOOST_CHECK(expectSection.checkIndexes(4, 0, 0) == false); +} + +BOOST_AUTO_TEST_CASE(expectIndexesArrayValueNotFound) +{ + const string sTr = R"( + { + "data" : [ + ":raw 0x11223341" + ":label second :raw 0x11223344", + ":raw 0x11223344" + ], + )" + transactionCommon + " }"; + + const string sExp = R"( + { + "indexes" : { + "data" : [0, ":label 0x112233", 3], + "gas" : 0, + "value" : -1 + }, )" + expectSectionCommon + " }"; + + try + { + auto expectSection = makeExpectSection(sTr, sExp); + BOOST_CHECK(string("exception expected").size() == 0); + } + catch (std::exception const&) + { + TestOutputHelper::get().unmarkLastError(); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/retesteth/unitTests/trDataCompileTest.cpp b/retesteth/unitTests/trDataCompileTest.cpp new file mode 100644 index 000000000..6b70974d1 --- /dev/null +++ b/retesteth/unitTests/trDataCompileTest.cpp @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include + +using namespace test; +using namespace dataobject; + +string const transactionCommon = R"( + "gasLimit" : ["400000"], + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : ["100000"] +)"; + +StateTestFillerTransaction makeTransaction(std::vector const& _data) +{ + string str = "{ "; + str += "\"data\" : ["; + for (vector::const_iterator it = _data.begin(); it != _data.end(); it++) + { + str += "\"" + *it + "\""; + if (it + 1 != _data.end()) + str += ", "; + } + str += "]," + transactionCommon + "}"; + return StateTestFillerTransaction(ConvertJsoncppStringToData(str)); +} + +BOOST_FIXTURE_TEST_SUITE(trDataCompileSuite, TestOutputHelperFixture) + +BOOST_AUTO_TEST_CASE(compileRaw) +{ + StateTestFillerTransaction tr = makeTransaction({":raw 0x1234"}); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == "0x1234"); +} + +BOOST_AUTO_TEST_CASE(compileRawLabel) +{ + StateTestFillerTransaction tr = makeTransaction({":label sample :raw 0x1234"}); + BOOST_CHECK(tr.buildTransactions().at(0).transaction().dataLabel() == ":label sample"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == "0x1234"); +} + +BOOST_AUTO_TEST_CASE(compileRawArray) +{ + StateTestFillerTransaction tr = makeTransaction({":raw 0x1234", ":raw 0x2244"}); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == "0x1234"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(1).asString() == "0x2244"); +} + +BOOST_AUTO_TEST_CASE(compileRawArrayLabel) +{ + StateTestFillerTransaction tr = makeTransaction({":raw 0x1234", ":label sample :raw 0x2244"}); + BOOST_CHECK(tr.buildTransactions().at(0).transaction().dataLabel().empty()); + BOOST_CHECK(tr.buildTransactions().at(1).transaction().dataLabel() == ":label sample"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == "0x1234"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(1).asString() == "0x2244"); +} + +BOOST_AUTO_TEST_CASE(compileLLL) +{ + StateTestFillerTransaction tr = makeTransaction({"{ [[1]] 1 }"}); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == "0x600160015500"); +} + +BOOST_AUTO_TEST_CASE(compileLLLLabel) +{ + StateTestFillerTransaction tr = makeTransaction({":label sample { [[1]] 1 }"}); + BOOST_CHECK(tr.buildTransactions().at(0).transaction().dataLabel() == ":label sample"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == "0x600160015500"); +} + +BOOST_AUTO_TEST_CASE(compileLLLArray) +{ + StateTestFillerTransaction tr = makeTransaction({"{ [[1]] 1 }", "{ [[1]] 2 }"}); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == "0x600160015500"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(1).asString() == "0x600260015500"); +} + +BOOST_AUTO_TEST_CASE(compileLLLArrayLabel) +{ + StateTestFillerTransaction tr = makeTransaction({"{ [[1]] 1 }", ":label sample { [[1]] 2 }"}); + BOOST_CHECK(tr.buildTransactions().at(0).transaction().dataLabel().empty()); + BOOST_CHECK(tr.buildTransactions().at(1).transaction().dataLabel() == ":label sample"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == "0x600160015500"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(1).asString() == "0x600260015500"); +} + +BOOST_AUTO_TEST_CASE(compileABI) +{ + StateTestFillerTransaction tr = makeTransaction({":abi f(uint) 12"}); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == + "0x693c6139000000000000000000000000000000000000000000000000000000000000000c"); +} + +BOOST_AUTO_TEST_CASE(compileABILabel) +{ + StateTestFillerTransaction tr = makeTransaction({":label sample :abi f(uint) 12"}); + BOOST_CHECK(tr.buildTransactions().at(0).transaction().dataLabel() == ":label sample"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == + "0x693c6139000000000000000000000000000000000000000000000000000000000000000c"); +} + +BOOST_AUTO_TEST_CASE(compileABIArray) +{ + StateTestFillerTransaction tr = makeTransaction({":abi f(uint) 12", ":abi f(uint) 13"}); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == + "0x693c6139000000000000000000000000000000000000000000000000000000000000000c"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(1).asString() == + "0x693c6139000000000000000000000000000000000000000000000000000000000000000d"); +} + +BOOST_AUTO_TEST_CASE(compileABIArrayLabel) +{ + StateTestFillerTransaction tr = makeTransaction({":abi f(uint) 13", ":label sample :abi f(uint) 12"}); + BOOST_CHECK(tr.buildTransactions().at(0).transaction().dataLabel().empty()); + BOOST_CHECK(tr.buildTransactions().at(1).transaction().dataLabel() == ":label sample"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString() == + "0x693c6139000000000000000000000000000000000000000000000000000000000000000d"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(1).asString() == + "0x693c6139000000000000000000000000000000000000000000000000000000000000000c"); +} + +string const solContract = R"( + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.4.16 <0.8.0; + contract B { + function callback(address x) public { + (bool success, bytes memory data) = x.call(abi.encodeWithSignature('stor()')); + assembly { sstore(1,success) } + success; + data; + } + } +)"; + +string const solContractC = + "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c806373027f6d14610030575b600080fd5b6100726004803603602081" + "101561004657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610074565b005b60006060" + "8273ffffffffffffffffffffffffffffffffffffffff166040516024016040516020818303038152906040527fb28175c4000000000000000000000000" + "000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffff" + "ffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310610145578051825260" + "2082019150602081019050602083039250610122565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000" + "604051808303816000865af19150503d80600081146101a7576040519150601f19603f3d011682016040523d82523d6000602084013e6101ac565b6060" + "91505b50915091508160015550505056fea2646970667358221220a3bfc993384abb4d5ed57244caedd74028e6c86f863f7b27bb5353572b7890fa6473" + "6f6c63430007000033"; + +BOOST_AUTO_TEST_CASE(compileSOLC) +{ + StateTestFillerTransaction tr = makeTransaction({solContract}); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString().substr(0, 50) == solContractC.substr(0, 50)); +} + +BOOST_AUTO_TEST_CASE(compileSOLCLabel) +{ + StateTestFillerTransaction tr = makeTransaction({":label sample " + solContract}); + BOOST_CHECK(tr.buildTransactions().at(0).transaction().dataLabel() == ":label sample"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString().substr(0, 50) == solContractC.substr(0, 50)); +} + +BOOST_AUTO_TEST_CASE(compileSOLCArray) +{ + StateTestFillerTransaction tr = makeTransaction({solContract, solContract}); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString().substr(0, 50) == solContractC.substr(0, 50)); + BOOST_CHECK(tr.asDataObject().atKey("data").at(1).asString().substr(0, 50) == solContractC.substr(0, 50)); +} + +BOOST_AUTO_TEST_CASE(compileSOLCArrayLabel) +{ + StateTestFillerTransaction tr = makeTransaction({solContract, ":label sample " + solContract}); + BOOST_CHECK(tr.buildTransactions().at(0).transaction().dataLabel().empty()); + BOOST_CHECK(tr.buildTransactions().at(1).transaction().dataLabel() == ":label sample"); + BOOST_CHECK(tr.asDataObject().atKey("data").at(0).asString().substr(0, 50) == solContractC.substr(0, 50)); + BOOST_CHECK(tr.asDataObject().atKey("data").at(1).asString().substr(0, 50) == solContractC.substr(0, 50)); +} + +BOOST_AUTO_TEST_SUITE_END()