diff options
author | Gav Wood <g@ethdev.com> | 2015-04-09 04:42:36 +0800 |
---|---|---|
committer | Gav Wood <g@ethdev.com> | 2015-04-09 04:42:36 +0800 |
commit | 07940a644dc561a5388b42a528f96095de1c510b (patch) | |
tree | 64ea178c34965df6357b362fa46a046ed3e78b44 /TestHelper.cpp | |
parent | 377e5435580e2e7e948e4a7690f0249f6af032d9 (diff) | |
parent | ff5ce7bda3346e3893d933196371564b4e45baec (diff) | |
download | dexon-solidity-07940a644dc561a5388b42a528f96095de1c510b.tar.gz dexon-solidity-07940a644dc561a5388b42a528f96095de1c510b.tar.zst dexon-solidity-07940a644dc561a5388b42a528f96095de1c510b.zip |
Merge pull request #1401 from winsvega/expectedState
Expected state
Diffstat (limited to 'TestHelper.cpp')
-rw-r--r-- | TestHelper.cpp | 138 |
1 files changed, 122 insertions, 16 deletions
diff --git a/TestHelper.cpp b/TestHelper.cpp index 757a6e7a..e86b84aa 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -68,6 +68,8 @@ namespace test { struct ValueTooLarge: virtual Exception {}; +struct MissingFields : virtual Exception {}; + bigint const c_max256plus1 = bigint(1) << 256; ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): @@ -106,41 +108,75 @@ void ImportTest::importEnv(json_spirit::mObject& _o) m_statePre.m_currentBlock = m_environment.currentBlock; } -void ImportTest::importState(json_spirit::mObject& _o, State& _state) +// import state from not fully declared json_spirit::mObject, writing to _stateOptionsMap which fields were defined in json + +void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptionsMap& _stateOptionsMap) { for (auto& i: _o) { json_spirit::mObject o = i.second.get_obj(); - assert(o.count("balance") > 0); - assert(o.count("nonce") > 0); - assert(o.count("storage") > 0); - assert(o.count("code") > 0); + ImportStateOptions stateOptions; + u256 balance = 0; + u256 nonce = 0; - if (bigint(o["balance"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); - if (bigint(o["nonce"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); + if (o.count("balance") > 0) + { + stateOptions.m_bHasBalance = true; + if (bigint(o["balance"].get_str()) >= c_max256plus1) + BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); + balance = toInt(o["balance"]); + } + + if (o.count("nonce") > 0) + { + stateOptions.m_bHasNonce = true; + if (bigint(o["nonce"].get_str()) >= c_max256plus1) + BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); + nonce = toInt(o["nonce"]); + } Address address = Address(i.first); - bytes code = importCode(o); + bytes code; + if (o.count("code") > 0) + { + code = importCode(o); + stateOptions.m_bHasCode = true; + } if (code.size()) { - _state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception); + _state.m_cache[address] = Account(balance, Account::ContractConception); _state.m_cache[address].setCode(code); } else - _state.m_cache[address] = Account(toInt(o["balance"]), Account::NormalCreation); + _state.m_cache[address] = Account(balance, Account::NormalCreation); - for (auto const& j: o["storage"].get_obj()) - _state.setStorage(address, toInt(j.first), toInt(j.second)); + if (o.count("storage") > 0) + { + stateOptions.m_bHasStorage = true; + for (auto const& j: o["storage"].get_obj()) + _state.setStorage(address, toInt(j.first), toInt(j.second)); + } - for(int i=0; i<toInt(o["nonce"]); ++i) + for (int i = 0; i < nonce; ++i) _state.noteSending(address); _state.ensureCached(address, false, false); + _stateOptionsMap[address] = stateOptions; + } +} + +void ImportTest::importState(json_spirit::mObject& _o, State& _state) +{ + stateOptionsMap importedMap; + importState(_o, _state, importedMap); + for (auto& stateOptionMap : importedMap) + { + //check that every parameter was declared in state object + if (!stateOptionMap.second.isAllSet()) + BOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); } } @@ -176,6 +212,64 @@ void ImportTest::importTransaction(json_spirit::mObject& _o) } } +void ImportTest::checkExpectedState(State const& _stateExpect, State const& _statePost, stateOptionsMap const _expectedStateOptions, WhenError _throw) +{ + #define CHECK(a,b) \ + { \ + if (_throw == WhenError::Throw) \ + BOOST_CHECK_MESSAGE(a,b); \ + else \ + BOOST_WARN_MESSAGE(a,b); \ + } + + for (auto const& a: _stateExpect.addresses()) + { + CHECK(_statePost.addressInUse(a.first), "Filling Test: " << a.first << " missing expected address!"); + if (_statePost.addressInUse(a.first)) + { + ImportStateOptions addressOptions(true); + if(_expectedStateOptions.size()) + { + try + { + addressOptions = _expectedStateOptions.at(a.first); + } + catch(std::out_of_range) + { + BOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!"); + break; + } + } + + if (addressOptions.m_bHasBalance) + CHECK(_stateExpect.balance(a.first) == _statePost.balance(a.first), + "Check State: " << a.first << ": incorrect balance " << _statePost.balance(a.first) << ", expected " << _stateExpect.balance(a.first)); + + if (addressOptions.m_bHasNonce) + CHECK(_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first), + "Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first)); + + if (addressOptions.m_bHasStorage) + { + map<u256, u256> stateStorage = _statePost.storage(a.first); + for (auto const& s: _stateExpect.storage(a.first)) + CHECK(stateStorage[s.first] == s.second, + "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(stateStorage[s.first]) << ", expected [" << s.first << "] = " << toHex(s.second)); + + //Check for unexpected storage values + stateStorage = _stateExpect.storage(a.first); + for (auto const& s: _statePost.storage(a.first)) + CHECK(stateStorage[s.first] == s.second, + "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(s.second) << ", expected [" << s.first << "] = " << toHex(stateStorage[s.first])); + } + + if (addressOptions.m_bHasCode) + CHECK(_stateExpect.code(a.first) == _statePost.code(a.first), + "Check State: " << a.first << ": incorrect code '" << toHex(_statePost.code(a.first)) << "', expected '" << toHex(_stateExpect.code(a.first)) << "'"); + } + } +} + void ImportTest::exportTest(bytes const& _output, State const& _statePost) { // export output @@ -184,8 +278,17 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost) // export logs m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); - // export post state + // compare expected state with post state + if (m_TestObject.count("expect") > 0) + { + stateOptionsMap stateMap; + State expectState(OverlayDB(), eth::BaseState::Empty); + importState(m_TestObject["expect"].get_obj(), expectState, stateMap); + checkExpectedState(expectState, _statePost, stateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); + m_TestObject.erase(m_TestObject.find("expect")); + } + // export post state m_TestObject["post"] = fillJsonWithState(_statePost); m_TestObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes()); @@ -559,6 +662,8 @@ Options::Options() inputLimits = true; else if (arg == "--bigdata") bigData = true; + else if (arg == "--checkstate") + checkState = true; else if (arg == "--all") { performance = true; @@ -566,6 +671,7 @@ Options::Options() memory = true; inputLimits = true; bigData = true; + checkState = true; } } } |