aboutsummaryrefslogtreecommitdiffstats
path: root/TestHelper.cpp
diff options
context:
space:
mode:
authorGav Wood <g@ethdev.com>2015-04-09 04:42:36 +0800
committerGav Wood <g@ethdev.com>2015-04-09 04:42:36 +0800
commit07940a644dc561a5388b42a528f96095de1c510b (patch)
tree64ea178c34965df6357b362fa46a046ed3e78b44 /TestHelper.cpp
parent377e5435580e2e7e948e4a7690f0249f6af032d9 (diff)
parentff5ce7bda3346e3893d933196371564b4e45baec (diff)
downloaddexon-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.cpp138
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;
}
}
}