diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | TestHelper.cpp | 287 | ||||
-rw-r--r-- | TestHelper.h | 51 | ||||
-rw-r--r-- | genesis.cpp | 17 | ||||
-rw-r--r-- | hexPrefix.cpp | 15 | ||||
-rw-r--r-- | main.cpp | 6 | ||||
-rw-r--r-- | rlp.cpp | 15 | ||||
-rw-r--r-- | state.cpp | 173 | ||||
-rw-r--r-- | tmpFiller.json | 33 | ||||
-rw-r--r-- | trie.cpp | 18 | ||||
-rw-r--r-- | vm.cpp | 207 | ||||
-rw-r--r-- | vm.h | 3 |
12 files changed, 326 insertions, 501 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6aa99b61..e8769117 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ link_directories(../libethereum) file(GLOB HEADERS "*.h") add_executable(testeth ${SRC_LIST} ${HEADERS}) -add_executable(createRandomTest createRandomTest.cpp vm.cpp) +add_executable(createRandomTest createRandomTest.cpp vm.cpp TestHelper.cpp) target_link_libraries(testeth ethereum) target_link_libraries(testeth ethcore) diff --git a/TestHelper.cpp b/TestHelper.cpp index 460446ae..6f4b21e5 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -23,10 +23,14 @@ #include <thread> #include <chrono> +#include <boost/filesystem/path.hpp> #include <libethereum/Client.h> #include <liblll/Compiler.h> +//#define FILL_TESTS + using namespace std; +using namespace dev::eth; namespace dev { @@ -56,6 +60,7 @@ void connectClients(Client& c1, Client& c2) c2.connect("127.0.0.1", c1Port); #endif } +} namespace test { @@ -65,17 +70,12 @@ ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller):m_TestObject(_o) importEnv(_o["env"].get_obj()); importState(_o["pre"].get_obj(), m_statePre); - importExec(_o["exec"].get_obj()); + importTransaction(_o["transaction"].get_obj()); if (!isFiller) { importState(_o["post"].get_obj(), m_statePost); - //importCallCreates(_o["callcreates"].get_array()); - importGas(_o); - importOutput(_o); } -// else -// m_TestObject = &_o; // if Filler then change Test object to prepare for export } void ImportTest::importEnv(json_spirit::mObject& _o) @@ -110,130 +110,61 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) assert(o.count("code") > 0); Address address = Address(i.first); - _state.m_cache[address] = AddressState(toInt(o["nonce"]), toInt(o["balance"]), EmptyTrie, h256()); + for (auto const& j: o["storage"].get_obj()) _state.setStorage(address, toInt(j.first), toInt(j.second)); - bytes code; - if (o["code"].type() == json_spirit::str_type) - if (o["code"].get_str().find_first_of("0x") != 0) - code = compileLLL(o["code"].get_str(), false); - else - code = fromHex(o["code"].get_str().substr(2)); - else + bytes code = importCode(o); + + toInt(o["nonce"]); + if (toHex(code).size()) { - code.clear(); - for (auto const& j: o["code"].get_array()) - code.push_back(toByte(j)); + cout << "address: " << address << "has code: " << toHex(code) << endl; + _state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception); + i.second.get_obj()["code"] = "0x" + toHex(code); //preperation for export + _state.m_cache[address].setCode(bytesConstRef(&code)); } + else + _state.m_cache[address] = Account(toInt(o["balance"]), Account::NormalCreation); - i.second.get_obj()["code"] = "0x" + toHex(code); //preperation for export + for(int i=0; i<toInt(o["nonce"]); ++i) + _state.noteSending(address); - _state.m_cache[address].setCode(bytesConstRef(&code)); - _state.ensureCached(address, true, true); + _state.ensureCached(address, false, false); } } -void ImportTest::importExec(json_spirit::mObject& _o) +void ImportTest::importTransaction(json_spirit::mObject& _o) { - assert(_o.count("address")> 0); - assert(_o.count("caller") > 0); - assert(_o.count("origin") > 0); + assert(_o.count("nonce")> 0); + assert(_o.count("gasPrice") > 0); + assert(_o.count("gasLimit") > 0); + assert(_o.count("to") > 0); assert(_o.count("value") > 0); + assert(_o.count("secretKey") > 0); assert(_o.count("data") > 0); - assert(_o.count("gasPrice") > 0); - assert(_o.count("gas") > 0); - //assert(_o.count("code") > 0); - m_environment.myAddress = Address(_o["address"].get_str()); - m_environment.caller = Address(_o["caller"].get_str()); - m_environment.origin = Address(_o["origin"].get_str()); - m_environment.value = toInt(_o["value"]); - m_environment.gasPrice = toInt(_o["gasPrice"]); - gasExec = toInt(_o["gas"]); - - if (_o["code"].type() == json_spirit::str_type) - if (_o["code"].get_str().find_first_of("0x") == 0) - code = fromHex(_o["code"].get_str().substr(2)); - else - code = compileLLL(_o["code"].get_str()); - else if (_o["code"].type() == json_spirit::array_type) - for (auto const& j: _o["code"].get_array()) - code.push_back(toByte(j)); - else - m_environment.code.reset(); - m_environment.code = &code; - - if (_o["data"].type() == json_spirit::str_type) - if (_o["data"].get_str().find_first_of("0x") == 0) - data = fromHex(_o["data"].get_str().substr(2)); - else - data = fromHex(_o["data"].get_str()); - else - for (auto const& j: _o["data"].get_array()) - data.push_back(toByte(j)); - m_environment.data = &data; + m_transaction.nonce = toInt(_o["nonce"]); + m_transaction.gasPrice = toInt(_o["gasPrice"]); + m_transaction.gas = toInt(_o["gasLimit"]); + m_transaction.receiveAddress = Address(_o["to"].get_str()); + m_transaction.type = m_transaction.receiveAddress ? Transaction::MessageCall : Transaction::ContractCreation; + m_transaction.value = toInt(_o["value"]); + Secret secretKey = Secret(_o["secretKey"].get_str()); + m_transaction.sign(secretKey); + m_transaction.data = importData(_o); } -void ImportTest::importCallCreates(json_spirit::mArray& _callcreates) +void ImportTest::exportTest(bytes _output, State& _statePost) { - for (json_spirit::mValue& v: _callcreates) - { - auto tx = v.get_obj(); - assert(tx.count("data") > 0); - assert(tx.count("value") > 0); - assert(tx.count("destination") > 0); - assert(tx.count("gasLimit") > 0); - Transaction t; - t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall; - t.receiveAddress = Address(tx["destination"].get_str()); - t.value = toInt(tx["value"]); - t.gas = toInt(tx["gasLimit"]); - if (tx["data"].type() == json_spirit::str_type) - if (tx["data"].get_str().find_first_of("0x") == 0) - t.data = fromHex(tx["data"].get_str().substr(2)); - else - t.data = fromHex(tx["data"].get_str()); - else - for (auto const& j: tx["data"].get_array()) - t.data.push_back(toByte(j)); - callcreates.push_back(t); - } -} - -void ImportTest::importGas(json_spirit::mObject& _o) -{ - gas = toInt(_o["gas"]); -} - -void ImportTest::importOutput(json_spirit::mObject& _o) -{ - int i = 0; - if (_o["out"].type() == json_spirit::array_type) - for (auto const& d: _o["out"].get_array()) - { - output[i] = uint8_t(toInt(d)); - ++i; - } - else if (_o["out"].get_str().find("0x") == 0) - output = fromHex(_o["out"].get_str().substr(2)); - else - output = fromHex(_o["out"].get_str()); -} - -void ImportTest::exportTest(bytes _output, u256 _gas, State& _statePost) -{ - // export gas - m_TestObject["gas"] = toString(_gas); - // export output m_TestObject["out"] = "0x" + toHex(_output); // export post state json_spirit::mObject postState; - std::map<Address, AddressState> genesis = genesisState(); + std::map<Address, Account> genesis = genesisState(); for (auto const& a: _statePost.addresses()) { @@ -254,22 +185,6 @@ void ImportTest::exportTest(bytes _output, u256 _gas, State& _statePost) postState[toString(a.first)] = o; } m_TestObject["post"] = json_spirit::mValue(postState); - - m_TestObject["exec"].get_obj()["code"] = "0x" + toHex(code); - -// // export callcreates -// m_TestObject["callcreates"] = exportCallCreates(); - -// for (int i = 0; i < (m_manifest.internal.size(); ++i) -// { -// Transaction t; -// t.value = m_manifest.internal[i].value; -// t.gas = ; -// t.data = m_manifest.internal[i].input; ; -// t.receiveAddress = m_manifest.internal[i].to; -// t.type = - -// } } u256 toInt(json_spirit::mValue const& _v) @@ -298,5 +213,131 @@ byte toByte(json_spirit::mValue const& _v) return 0; } +bytes importData(json_spirit::mObject & _o) +{ + bytes data; + if (_o["data"].type() == json_spirit::str_type) + if (_o["data"].get_str().find_first_of("0x") == 0) + data = fromHex(_o["data"].get_str().substr(2)); + else + data = fromHex(_o["data"].get_str()); + else + for (auto const& j: _o["data"].get_array()) + data.push_back(toByte(j)); + + return data; +} + +bytes importCode(json_spirit::mObject & _o) +{ + bytes code; + if (_o["code"].type() == json_spirit::str_type) + if (_o["code"].get_str().find_first_of("0x") != 0) + code = compileLLL(_o["code"].get_str(), false); + else + code = fromHex(_o["code"].get_str().substr(2)); + else if (_o["code"].type() == json_spirit::array_type) + { + code.clear(); + for (auto const& j: _o["code"].get_array()) + code.push_back(toByte(j)); + } + return code; +} + +void checkOutput(bytes const& _output, json_spirit::mObject & _o) +{ + int j = 0; + if (_o["out"].type() == json_spirit::array_type) + for (auto const& d: _o["out"].get_array()) + { + BOOST_CHECK_MESSAGE(_output[j] == toInt(d), "Output byte [" << j << "] different!"); + ++j; + } + else if (_o["out"].get_str().find("0x") == 0) + BOOST_CHECK(_output == fromHex(_o["out"].get_str().substr(2))); + else + BOOST_CHECK(_output == fromHex(_o["out"].get_str())); +} + +void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore, Address _expectedAddr) +{ + for (auto&& expectedStorePair : _expectedStore) + { + auto& expectedStoreKey = expectedStorePair.first; + auto resultStoreIt = _resultStore.find(expectedStoreKey); + if (resultStoreIt == _resultStore.end()) + BOOST_ERROR(_expectedAddr << ": missing store key " << expectedStoreKey); + else + { + auto& expectedStoreValue = expectedStorePair.second; + auto& resultStoreValue = resultStoreIt->second; + BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); + } + } +} + +std::string getTestPath() +{ + string testPath; + const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); + + if (ptestPath == NULL) + { + cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; + testPath = "../../../tests"; + } + else + testPath = ptestPath; + + return testPath; +} + +void executeTests(const string& _name, const string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests) +{ + string testPath = getTestPath(); + testPath += _testPathAppendix; + +#ifdef FILL_TESTS + try + { + cnote << "Populating tests..."; + json_spirit::mValue v; + boost::filesystem::path p(__FILE__); + boost::filesystem::path dir = p.parent_path(); + string s = asString(dev::contents(dir.string() + "/" + _name + "Filler.json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + dir.string() + "/" + _name + "Filler.json is empty."); + json_spirit::read_string(s, v); + doTests(v, true); + writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); + } + catch (std::exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << _e.what()); + } +#endif + + try + { + cnote << "Testing ..." << _name; + json_spirit::mValue v; + string s = asString(dev::contents(testPath + "/" + _name + ".json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); + json_spirit::read_string(s, v); + doTests(v, false); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); + } + catch (std::exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << _e.what()); + } +} -} } } // namespaces +} } // namespaces diff --git a/TestHelper.h b/TestHelper.h index e1bba7d0..9187196d 100644 --- a/TestHelper.h +++ b/TestHelper.h @@ -21,6 +21,8 @@ #pragma once +#include <functional> +#include <boost/test/unit_test.hpp> #include "JsonSpiritHeaders.h" #include <libethereum/State.h> @@ -34,6 +36,8 @@ class Client; void mine(Client& c, int numBlocks); void connectClients(Client& c1, Client& c2); +} + namespace test { @@ -45,31 +49,26 @@ public: // imports void importEnv(json_spirit::mObject& _o); - void importState(json_spirit::mObject& _o, State& _state); - void importExec(json_spirit::mObject& _o); - void importCallCreates(json_spirit::mArray& _callcreates); - void importGas(json_spirit::mObject& _o); - void importOutput(json_spirit::mObject& _o); - - void exportTest(bytes _output, u256 _gas, State& _statePost); - Manifest* getManifest(){ return &m_manifest;} - - State m_statePre; - State m_statePost; - ExtVMFace m_environment; + void importState(json_spirit::mObject& _o, eth::State& _state); + void importTransaction(json_spirit::mObject& _o); + void exportTest(bytes _output, eth::State& _statePost); + eth::Manifest* getManifest(){ return &m_manifest;} + + eth::State m_statePre; + eth::State m_statePost; + eth::ExtVMFace m_environment; u256 gas; u256 gasExec; - Transactions callcreates; + eth::Transaction m_transaction; bytes output; - Manifest m_manifest; + eth::Manifest m_manifest; bytes code; private: json_spirit::mObject& m_TestObject; - // needed for const refs - + // needed for const ref bytes data; }; @@ -77,7 +76,25 @@ private: u256 toInt(json_spirit::mValue const& _v); byte toByte(json_spirit::mValue const& _v); - +bytes importCode(json_spirit::mObject &_o); +bytes importData(json_spirit::mObject &_o); +void checkOutput(bytes const& _output, json_spirit::mObject &_o); +void checkStorage(std::map<u256, u256> _expectedStore, std::map<u256, u256> _resultStore, Address _expectedAddr); +void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests); +std::string getTestPath(); + +template<typename mapType> +void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) +{ + for (auto& resultPair : _resultAddrs) + { + auto& resultAddr = resultPair.first; + auto expectedAddrIt = _expectedAddrs.find(resultAddr); + if (expectedAddrIt == _expectedAddrs.end()) + BOOST_ERROR("Missing result address " << resultAddr); + } + BOOST_CHECK(_expectedAddrs == _resultAddrs); } + } } diff --git a/genesis.cpp b/genesis.cpp index 16ffb185..6839d42e 100644 --- a/genesis.cpp +++ b/genesis.cpp @@ -26,6 +26,7 @@ #include <libdevcore/CommonIO.h> #include <libethereum/BlockChain.h> #include <boost/test/unit_test.hpp> +#include "TestHelper.h" using namespace std; using namespace dev; @@ -33,18 +34,12 @@ using namespace dev::eth; namespace js = json_spirit; +BOOST_AUTO_TEST_SUITE(BasicTests) + BOOST_AUTO_TEST_CASE(genesis_tests) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; + string testPath = test::getTestPath(); + testPath += "/BasicTests"; cnote << "Testing Genesis block..."; js::mValue v; @@ -59,3 +54,5 @@ BOOST_AUTO_TEST_CASE(genesis_tests) BOOST_CHECK_EQUAL(sha3(BlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } +BOOST_AUTO_TEST_SUITE_END() + diff --git a/hexPrefix.cpp b/hexPrefix.cpp index 99207ab9..1f02bac9 100644 --- a/hexPrefix.cpp +++ b/hexPrefix.cpp @@ -26,23 +26,19 @@ #include <libdevcore/CommonIO.h> #include <libdevcrypto/TrieCommon.h> #include <boost/test/unit_test.hpp> +#include "TestHelper.h" using namespace std; using namespace dev; namespace js = json_spirit; +BOOST_AUTO_TEST_SUITE(BasicTests) + BOOST_AUTO_TEST_CASE(hexPrefix_test) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; + string testPath = test::getTestPath(); + testPath += "/BasicTests"; cnote << "Testing Hex-Prefix-Encode..."; js::mValue v; @@ -62,3 +58,4 @@ BOOST_AUTO_TEST_CASE(hexPrefix_test) } } +BOOST_AUTO_TEST_SUITE_END() @@ -41,8 +41,8 @@ using namespace std; using namespace dev; using namespace dev::eth; -BOOST_AUTO_TEST_CASE(basic_tests) -{ +//BOOST_AUTO_TEST_CASE(basic_tests) +//{ /* RLPStream s; BlockInfo::genesis().streamRLP(s, false); std::cout << RLP(s.out()) << std::endl; @@ -54,5 +54,5 @@ BOOST_AUTO_TEST_CASE(basic_tests) // r += stateTest(); // r += peerTest(argc, argv); // BOOST_REQUIRE(!r); -} +//} @@ -29,6 +29,7 @@ #include <boost/test/unit_test.hpp> #include <algorithm> #include "JsonSpiritHeaders.h" +#include "TestHelper.h" using namespace std; using namespace dev; @@ -61,16 +62,8 @@ namespace dev static void getRLPTestCases(js::mValue& v) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; + string testPath = getTestPath(); + testPath += "/BasicTests"; string s = asString(contents(testPath + "/rlptest.json")); BOOST_REQUIRE_MESSAGE( s.length() > 0, @@ -144,6 +137,7 @@ namespace dev } } +BOOST_AUTO_TEST_SUITE(BasicTests) BOOST_AUTO_TEST_CASE(rlp_encoding_test) { @@ -202,4 +196,5 @@ BOOST_AUTO_TEST_CASE(rlp_decoding_test) } } +BOOST_AUTO_TEST_SUITE_END() @@ -37,20 +37,15 @@ using namespace std; using namespace json_spirit; using namespace dev; using namespace dev::eth; -using namespace dev::eth::test; - -class FakeState: public State -{ - -}; - +using namespace dev::eth; -namespace dev { namespace eth{ namespace test { +namespace dev { namespace test { void doStateTests(json_spirit::mValue& v, bool _fillin) { + cout << "start state test\n"; for (auto& i: v.get_obj()) { cnote << i.first; @@ -58,7 +53,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("env") > 0); BOOST_REQUIRE(o.count("pre") > 0); - BOOST_REQUIRE(o.count("exec") > 0); + BOOST_REQUIRE(o.count("transaction") > 0); ImportTest importer(o,_fillin); @@ -68,57 +63,47 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) importer.m_environment.code = &importer.code; } - ExtVM evm(importer.m_statePre, importer.m_environment.myAddress, - importer.m_environment.caller, importer.m_environment.origin, - importer.m_environment.value, importer.m_environment.gasPrice, - importer.m_environment.data, importer.m_environment.code, - importer.getManifest()); + State theState = importer.m_statePre; + + bytes tx = importer.m_transaction.rlp(); bytes output; - VM vm(importer.gasExec); + + // check + + for (auto const& a: theState.addresses()) + { + cout << "address: " << a.first << endl; + cout << "balance: " << theState.balance(a.first) << endl; + cout << "has code: " << theState.addressHasCode(a.first) << endl; + } + try { - output = vm.go(evm, Executive::simpleTrace()).toVector(); + theState.execute(tx, &output); } catch (Exception const& _e) { - cnote << "VM did throw an exception: " << diagnostic_information(_e); - //BOOST_ERROR("Failed VM Test with Exception: " << e.what()); + cnote << "state execution did throw an exception: " << diagnostic_information(_e); } catch (std::exception const& _e) { - cnote << "VM did throw an exception: " << _e.what(); - //BOOST_ERROR("Failed VM Test with Exception: " << e.what()); + cnote << "state execution did throw an exception: " << _e.what(); } if (_fillin) - importer.exportTest(output, vm.gas(), evm.state()); + importer.exportTest(output, theState); else { BOOST_REQUIRE(o.count("post") > 0); - //BOOST_REQUIRE(o.count("callcreates") > 0); BOOST_REQUIRE(o.count("out") > 0); - BOOST_REQUIRE(o.count("gas") > 0); - // check output + checkOutput(output, o); - int j = 0; - if (o["out"].type() == array_type) - for (auto const& d: o["out"].get_array()) - { - BOOST_CHECK_MESSAGE(output[j] == toInt(d), "Output byte [" << j << "] different!"); - ++j; - } - else if (o["out"].get_str().find("0x") == 0) - BOOST_CHECK(output == fromHex(o["out"].get_str().substr(2))); - else - BOOST_CHECK(output == fromHex(o["out"].get_str())); - - BOOST_CHECK_EQUAL(toInt(o["gas"]), vm.gas()); - + // check addresses auto expectedAddrs = importer.m_statePost.addresses(); - auto resultAddrs = evm.state().addresses(); + auto resultAddrs = theState.addresses(); for (auto& expectedPair : expectedAddrs) { auto& expectedAddr = expectedPair.first; @@ -127,115 +112,37 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) BOOST_ERROR("Missing expected address " << expectedAddr); else { - BOOST_CHECK_MESSAGE(importer.m_statePost.balance(expectedAddr) == evm.state().balance(expectedAddr), expectedAddr << ": incorrect balance " << evm.state().balance(expectedAddr) << ", expected " << importer.m_statePost.balance(expectedAddr)); - BOOST_CHECK_MESSAGE(importer.m_statePost.transactionsFrom(expectedAddr) == evm.state().transactionsFrom(expectedAddr), expectedAddr << ": incorrect txCount " << evm.state().transactionsFrom(expectedAddr) << ", expected " << importer.m_statePost.transactionsFrom(expectedAddr)); - BOOST_CHECK_MESSAGE(importer.m_statePost.code(expectedAddr) == evm.state().code(expectedAddr), expectedAddr << ": incorrect code"); - - auto&& expectedStore = importer.m_statePost.storage(expectedAddr); - auto&& resultStore = evm.state().storage(expectedAddr); - - for (auto&& expectedStorePair : expectedStore) - { - auto& expectedStoreKey = expectedStorePair.first; - auto resultStoreIt = resultStore.find(expectedStoreKey); - if (resultStoreIt == resultStore.end()) - BOOST_ERROR(expectedAddr << ": missing store key " << expectedStoreKey); - else - { - auto& expectedStoreValue = expectedStorePair.second; - auto& resultStoreValue = resultStoreIt->second; - BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); - } - } - } - } + BOOST_CHECK_MESSAGE(importer.m_statePost.balance(expectedAddr) == theState.balance(expectedAddr), expectedAddr << ": incorrect balance " << theState.balance(expectedAddr) << ", expected " << importer.m_statePost.balance(expectedAddr)); + BOOST_CHECK_MESSAGE(importer.m_statePost.transactionsFrom(expectedAddr) == theState.transactionsFrom(expectedAddr), expectedAddr << ": incorrect txCount " << theState.transactionsFrom(expectedAddr) << ", expected " << importer.m_statePost.transactionsFrom(expectedAddr)); + BOOST_CHECK_MESSAGE(importer.m_statePost.code(expectedAddr) == theState.code(expectedAddr), expectedAddr << ": incorrect code"); - for (auto& resultPair : resultAddrs) - { - auto& resultAddr = resultPair.first; - auto expectedAddrIt = expectedAddrs.find(resultAddr); - if (expectedAddrIt == expectedAddrs.end()) - BOOST_ERROR("Missing result address " << resultAddr); + checkStorage(importer.m_statePost.storage(expectedAddr), theState.storage(expectedAddr), expectedAddr); + } } - - BOOST_CHECK(evm.state().addresses() == importer.m_statePost.addresses()); // Just to make sure nothing missed - //BOOST_CHECK(evm.callcreates == importer.callcreates); + checkAddresses<map<Address, u256> >(expectedAddrs, resultAddrs); } - } } +} }// Namespace Close +BOOST_AUTO_TEST_SUITE(StateTests) -void executeStateTests(const string& _name) +BOOST_AUTO_TEST_CASE(stExample) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; - - testPath += "/statetests"; - -#ifdef FILL_TESTS - try - { - cnote << "Populating VM tests..."; - json_spirit::mValue v; - boost::filesystem::path p(__FILE__); - boost::filesystem::path dir = p.parent_path(); - string s = asString(dev::contents(dir.string() + "/" + _name + "Filler.json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + dir.string() + "/" + _name + "Filler.json is empty."); - json_spirit::read_string(s, v); - doStateTests(v, true); - writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); - } -#endif - - try - { - cnote << "Testing VM..." << _name; - json_spirit::mValue v; - string s = asString(dev::contents(testPath + "/" + _name + ".json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); - json_spirit::read_string(s, v); - doStateTests(v, false); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); - } - + dev::test::executeTests("stExample", "/StateTests", dev::test::doStateTests); } -} } }// Namespace Close -BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) -{ - dev::eth::test::executeStateTests("stSystemOperationsTest"); -} +//BOOST_AUTO_TEST_CASE(stSystemOperationsTest) +//{ +// dev::test::executeStateTests("stSystemOperationsTest"); +//} BOOST_AUTO_TEST_CASE(tmp) { - std::cout << "Doing systemoperationsTest in state\n"; int currentVerbosity = g_logVerbosity; g_logVerbosity = 12; - dev::eth::test::executeStateTests("tmp"); + dev::test::executeTests("tmp", "/StateTests", dev::test::doStateTests); g_logVerbosity = currentVerbosity; } +BOOST_AUTO_TEST_SUITE_END() diff --git a/tmpFiller.json b/tmpFiller.json index 2cd5d690..bd27b890 100644 --- a/tmpFiller.json +++ b/tmpFiller.json @@ -1,5 +1,5 @@ { - "ABAcallsSuicide0": { + "ABAcalls0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -9,29 +9,36 @@ "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) (SUICIDE 0x945304eb96065b2a98b57a48a06ae28d285a71b5) }", + "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }", "storage": {} }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "{ [[ (PC) ]] (ADD 1 (CALL 500 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 23 0 0 0 0)) } ", + "code" : " { [[ (PC) ]] (ADD 1 (CALL 500 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 23 0 0 0 0)) } ", "nonce" : "0", "storage" : { } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} } }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "100000", - "data" : "", - "gasPrice" : "100000000000000", - "gas" : "10000000000000" - } + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } } + } @@ -28,6 +28,7 @@ #include "TrieHash.h" #include "MemTrie.h" #include <boost/test/unit_test.hpp> +#include "TestHelper.h" using namespace std; using namespace dev; @@ -47,18 +48,14 @@ static unsigned fac(unsigned _i) } } +BOOST_AUTO_TEST_SUITE(TrieTests) + BOOST_AUTO_TEST_CASE(trie_tests) { - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; + string testPath = test::getTestPath(); - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; + + testPath += "/TrieTests"; cnote << "Testing Trie..."; js::mValue v; @@ -364,3 +361,6 @@ BOOST_AUTO_TEST_CASE(trieStess) } } +BOOST_AUTO_TEST_SUITE_END() + + @@ -20,11 +20,8 @@ * vm test functions. */ -#include <boost/filesystem/path.hpp> #include "vm.h" -//#define FILL_TESTS - using namespace std; using namespace json_spirit; using namespace dev; @@ -59,6 +56,8 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, t.receiveAddress = _receiveAddress; callcreates.push_back(t); (void)_out; + (void)_myAddressOverride; + (void)_codeAddressOverride; return true; } @@ -91,45 +90,13 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map<u256, u256> const& _st set(myAddress, _myBalance, _myNonce, _storage, get<3>(addresses[myAddress])); } -u256 FakeExtVM::toInt(mValue const& _v) -{ - switch (_v.type()) - { - case str_type: return u256(_v.get_str()); - case int_type: return (u256)_v.get_uint64(); - case bool_type: return (u256)(uint64_t)_v.get_bool(); - case real_type: return (u256)(uint64_t)_v.get_real(); - default: cwarn << "Bad type for scalar: " << _v.type(); - } - return 0; -} - -byte FakeExtVM::toByte(mValue const& _v) -{ - switch (_v.type()) - { - case str_type: return (byte)stoi(_v.get_str()); - case int_type: return (byte)_v.get_uint64(); - case bool_type: return (byte)_v.get_bool(); - case real_type: return (byte)_v.get_real(); - default: cwarn << "Bad type for scalar: " << _v.type(); - } - return 0; -} - void FakeExtVM::push(mObject& o, string const& _n, u256 _v) { - // if (_v < (u256)1 << 64) - // o[_n] = (uint64_t)_v; - // else o[_n] = toString(_v); } void FakeExtVM::push(mArray& a, u256 _v) { - // if (_v < (u256)1 << 64) - // a.push_back((uint64_t)_v); - // else a.push_back(toString(_v)); } @@ -202,17 +169,7 @@ void FakeExtVM::importState(mObject& _object) for (auto const& j: o["storage"].get_obj()) get<2>(a)[toInt(j.first)] = toInt(j.second); - if (o["code"].type() == str_type) - if (o["code"].get_str().find_first_of("0x") != 0) - get<3>(a) = compileLLL(o["code"].get_str(), false); - else - get<3>(a) = fromHex(o["code"].get_str().substr(2)); - else - { - get<3>(a).clear(); - for (auto const& j: o["code"].get_array()) - get<3>(a).push_back(toByte(j)); - } + get<3>(a) = importCode(o); } } @@ -250,26 +207,14 @@ void FakeExtVM::importExec(mObject& _o) thisTxCode.clear(); code = &thisTxCode; - if (_o["code"].type() == str_type) - if (_o["code"].get_str().find_first_of("0x") == 0) - thisTxCode = fromHex(_o["code"].get_str().substr(2)); - else - thisTxCode = compileLLL(_o["code"].get_str()); - else if (_o["code"].type() == array_type) - for (auto const& j: _o["code"].get_array()) - thisTxCode.push_back(toByte(j)); - else + + thisTxCode = importCode(_o); + if (_o["code"].type() != str_type && _o["code"].type() != array_type) code.reset(); thisTxData.clear(); - if (_o["data"].type() == str_type) - if (_o["data"].get_str().find_first_of("0x") == 0) - thisTxData = fromHex(_o["data"].get_str().substr(2)); - else - thisTxData = fromHex(_o["data"].get_str()); - else - for (auto const& j: _o["data"].get_array()) - thisTxData.push_back(toByte(j)); + thisTxData = importData(_o); + data = &thisTxData; } @@ -302,14 +247,7 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) t.receiveAddress = Address(tx["destination"].get_str()); t.value = toInt(tx["value"]); t.gas = toInt(tx["gasLimit"]); - if (tx["data"].type() == str_type) - if (tx["data"].get_str().find_first_of("0x") == 0) - t.data = fromHex(tx["data"].get_str().substr(2)); - else - t.data = fromHex(tx["data"].get_str()); - else - for (auto const& j: tx["data"].get_array()) - t.data.push_back(toByte(j)); + t.data = importData(tx); callcreates.push_back(t); } } @@ -346,7 +284,7 @@ eth::OnOpFunc FakeExtVM::simpleTrace() namespace dev { namespace test { -void doTests(json_spirit::mValue& v, bool _fillin) +void doVMTests(json_spirit::mValue& v, bool _fillin) { for (auto& i: v.get_obj()) { @@ -424,19 +362,10 @@ void doTests(json_spirit::mValue& v, bool _fillin) dev::test::FakeExtVM test; test.importState(o["post"].get_obj()); test.importCallCreates(o["callcreates"].get_array()); - int i = 0; - if (o["out"].type() == array_type) - for (auto const& d: o["out"].get_array()) - { - BOOST_CHECK_MESSAGE(output[i] == test.toInt(d), "Output byte [" << i << "] different!"); - ++i; - } - else if (o["out"].get_str().find("0x") == 0) - BOOST_CHECK(output == fromHex(o["out"].get_str().substr(2))); - else - BOOST_CHECK(output == fromHex(o["out"].get_str())); - BOOST_CHECK_EQUAL(test.toInt(o["gas"]), vm.gas()); + checkOutput(output, o); + + BOOST_CHECK_EQUAL(toInt(o["gas"]), vm.gas()); auto& expectedAddrs = test.addresses; auto& resultAddrs = fev.addresses; @@ -454,134 +383,68 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState)); BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code"); - auto&& expectedStore = std::get<2>(expectedState); - auto&& resultStore = std::get<2>(resultState); - - for (auto&& expectedStorePair : expectedStore) - { - auto& expectedStoreKey = expectedStorePair.first; - auto resultStoreIt = resultStore.find(expectedStoreKey); - if (resultStoreIt == resultStore.end()) - BOOST_ERROR(expectedAddr << ": missing store key " << expectedStoreKey); - else - { - auto& expectedStoreValue = expectedStorePair.second; - auto& resultStoreValue = resultStoreIt->second; - BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); - } - } + checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); } } - BOOST_CHECK(test.addresses == fev.addresses); // Just to make sure nothing missed + checkAddresses<std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes> > >(test.addresses, fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); } } } -void executeTests(const string& _name) -{ - const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); - string testPath; - - if (ptestPath == NULL) - { - cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests"; - } - else - testPath = ptestPath; - - testPath += "/vmtests"; - -#ifdef FILL_TESTS - try - { - cnote << "Populating VM tests..."; - json_spirit::mValue v; - boost::filesystem::path p(__FILE__); - boost::filesystem::path dir = p.parent_path(); - string s = asString(contents(dir.string() + "/" + _name + "Filler.json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + "Filler.json is empty."); - json_spirit::read_string(s, v); - dev::test::doTests(v, true); - writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); - } -#endif - - try - { - cnote << "Testing VM..." << _name; - json_spirit::mValue v; - string s = asString(contents(testPath + "/" + _name + ".json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); - json_spirit::read_string(s, v); - dev::test::doTests(v, false); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); - } - -} - } } // Namespace Close +BOOST_AUTO_TEST_SUITE(VMTests) + BOOST_AUTO_TEST_CASE(vm_tests) { - dev::test::executeTests("vmtests"); + dev::test::executeTests("vmtests", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmArithmeticTest) { - dev::test::executeTests("vmArithmeticTest"); + dev::test::executeTests("vmArithmeticTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmBitwiseLogicOperationTest) { - dev::test::executeTests("vmBitwiseLogicOperationTest"); + dev::test::executeTests("vmBitwiseLogicOperationTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmSha3Test) { - dev::test::executeTests("vmSha3Test"); + dev::test::executeTests("vmSha3Test", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmEnvironmentalInfoTest) { - dev::test::executeTests("vmEnvironmentalInfoTest"); + dev::test::executeTests("vmEnvironmentalInfoTest", "/VMTests", dev::test::doVMTests); } BOOST_AUTO_TEST_CASE(vmBlockInfoTest) { - dev::test::executeTests("vmBlockInfoTest"); + dev::test::executeTests("vmBlockInfoTest", "/VMTests", dev::test::doVMTests); } -BOOST_AUTO_TEST_CASE(vmIOandFlowOperationsTest) +//BOOST_AUTO_TEST_CASE(vmIOandFlowOperationsTest) +//{ +// dev::test::executeTests("vmIOandFlowOperationsTest", "/VMTests", dev::test::doVMTests); +//} + +BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) { - dev::test::executeTests("vmIOandFlowOperationsTest"); + dev::test::executeTests("vmPushDupSwapTest", "/VMTests", dev::test::doVMTests); } -BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) +BOOST_AUTO_TEST_CASE(vmNamecoin) { - dev::test::executeTests("vmPushDupSwapTest"); + dev::test::executeTests("vmNamecoin", "/VMTests", dev::test::doVMTests); } //BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) //{ -// dev::test::executeTests("vmSystemOperationsTest"); +// dev::test::executeTests("vmSystemOperationsTest", "/VMTests", dev::test::doVMTests); //} BOOST_AUTO_TEST_CASE(userDefinedFile) @@ -598,7 +461,7 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) string s = asString(contents(filename)); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); json_spirit::read_string(s, v); - dev::test::doTests(v, false); + dev::test::doVMTests(v, false); } catch (Exception const& _e) { @@ -611,3 +474,5 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) g_logVerbosity = currentVerbosity; } } + +BOOST_AUTO_TEST_SUITE_END() @@ -36,6 +36,7 @@ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. #include <libethereum/Transaction.h> #include <libethereum/ExtVM.h> #include <libethereum/State.h> +#include "TestHelper.h" namespace dev { namespace test { @@ -60,8 +61,6 @@ public: void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code); void set(Address _a, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code); void reset(u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage); - u256 toInt(json_spirit::mValue const& _v); - byte toByte(json_spirit::mValue const& _v); void push(json_spirit::mObject& o, std::string const& _n, u256 _v); void push(json_spirit::mArray& a, u256 _v); u256 doPosts(); |