Browse Source

Check State

Incomplete State Support
cl-refactor
winsvega 10 years ago
parent
commit
97f3260b5a
  1. 122
      test/TestHelper.cpp
  2. 14
      test/TestHelper.h

122
test/TestHelper.cpp

@ -25,7 +25,6 @@
#include <chrono> #include <chrono>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/assign.hpp>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
@ -107,41 +106,72 @@ void ImportTest::importEnv(json_spirit::mObject& _o)
m_statePre.m_currentBlock = m_environment.currentBlock; 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) for (auto& i: _o)
{ {
json_spirit::mObject o = i.second.get_obj(); json_spirit::mObject o = i.second.get_obj();
assert(o.count("balance") > 0); ImportStateOptions stateOptions;
assert(o.count("nonce") > 0); u256 iBalance = 0, iNonce = 0;
assert(o.count("storage") > 0);
assert(o.count("code") > 0);
if (bigint(o["balance"].get_str()) >= c_max256plus1) if (o.count("balance") > 0)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); {
if (bigint(o["nonce"].get_str()) >= c_max256plus1) stateOptions.m_bHasBalance = true;
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); if (bigint(o["balance"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") );
iBalance = 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") );
iNonce = toInt(o["nonce"]);
}
Address address = Address(i.first); 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()) if (code.size())
{ {
_state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception); _state.m_cache[address] = Account(iBalance, Account::ContractConception);
_state.m_cache[address].setCode(code); _state.m_cache[address].setCode(code);
} }
else else
_state.m_cache[address] = Account(toInt(o["balance"]), Account::NormalCreation); _state.m_cache[address] = Account(iBalance, Account::NormalCreation);
for (auto const& j: o["storage"].get_obj()) if (o.count("storage") > 0)
_state.setStorage(address, toInt(j.first), toInt(j.second)); {
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<iNonce; ++i)
_state.noteSending(address); _state.noteSending(address);
_state.ensureCached(address, false, false); _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)
{
assert(stateOptionMap.second.isAllSet()); //check that every parameter was declared in state object
} }
} }
@ -178,6 +208,12 @@ void ImportTest::importTransaction(json_spirit::mObject& _o)
} }
void ImportTest::checkExpectedState(State const& _stateExpect, State const& _statePost, WhenError _throw) void ImportTest::checkExpectedState(State const& _stateExpect, State const& _statePost, WhenError _throw)
{
stateOptionsMap defaultMap;
checkExpectedState(_stateExpect, _statePost, defaultMap, _throw);
}
void ImportTest::checkExpectedState(State const& _stateExpect, State const& _statePost, stateOptionsMap const& _expectedStateOptions, WhenError _throw)
{ {
#define CHECK(a,b) \ #define CHECK(a,b) \
if (_throw == WhenError::Throw) \ if (_throw == WhenError::Throw) \
@ -190,20 +226,47 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta
CHECK(_statePost.addressInUse(a.first), "Filling Test: " << a.first << " missing expected address!"); CHECK(_statePost.addressInUse(a.first), "Filling Test: " << a.first << " missing expected address!");
if (_statePost.addressInUse(a.first)) if (_statePost.addressInUse(a.first))
{ {
CHECK(_stateExpect.balance(a.first) == _statePost.balance(a.first), ImportStateOptions addressOptions(true);
"Check State: " << a.first << ": incorrect balance " << _statePost.balance(a.first) << ", expected " << _stateExpect.balance(a.first)); if(_expectedStateOptions.size())
CHECK(_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first), {
"Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first)); 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));
}
map<u256, u256> stateStorage = _statePost.storage(a.first); if (addressOptions.m_bHasNonce)
for (auto const& s: _stateExpect.storage(a.first))
{ {
CHECK(stateStorage[s.first] == s.second, CHECK(_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first),
"Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(stateStorage[s.first]) << ", expected [" << s.first << "] = " << toHex(s.second)); "Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first));
} }
CHECK(_stateExpect.code(a.first) == _statePost.code(a.first), if (addressOptions.m_bHasStorage)
"Check State: " << a.first << ": incorrect code '" << toHex(_statePost.code(a.first)) << "', expected '" << toHex(_stateExpect.code(a.first)) << "'"); {
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));
}
}
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)) << "'");
}
} }
} }
} }
@ -219,9 +282,10 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost)
// compare expected state with post state // compare expected state with post state
if (m_TestObject.count("expect") > 0) if (m_TestObject.count("expect") > 0)
{ {
State expectState(Address(), OverlayDB(), eth::BaseState::Empty); stateOptionsMap stateMap;
importState(m_TestObject["expect"].get_obj(), expectState); State expectState(Address(), OverlayDB(), eth::BaseState::Empty);
checkExpectedState(expectState, _statePost, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); 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")); m_TestObject.erase(m_TestObject.find("expect"));
} }

14
test/TestHelper.h

@ -97,6 +97,17 @@ namespace test
} \ } \
while (0) while (0)
struct ImportStateOptions
{
ImportStateOptions():m_bHasBalance(false), m_bHasNonce(false), m_bHasCode(false), m_bHasStorage(false) {}
ImportStateOptions(bool _bSetAll):m_bHasBalance(_bSetAll), m_bHasNonce(_bSetAll), m_bHasCode(_bSetAll), m_bHasStorage(_bSetAll) {}
bool isAllSet() {return m_bHasBalance && m_bHasNonce && m_bHasCode && m_bHasStorage;}
bool m_bHasBalance;
bool m_bHasNonce;
bool m_bHasCode;
bool m_bHasStorage;
};
typedef std::map<Address, ImportStateOptions> stateOptionsMap;
class ImportTest class ImportTest
{ {
@ -106,9 +117,12 @@ public:
// imports // imports
void importEnv(json_spirit::mObject& _o); void importEnv(json_spirit::mObject& _o);
static void importState(json_spirit::mObject& _o, eth::State& _state); static void importState(json_spirit::mObject& _o, eth::State& _state);
static void importState(json_spirit::mObject& _o, eth::State& _state, stateOptionsMap& _stateOptionsMap);
void importTransaction(json_spirit::mObject& _o); void importTransaction(json_spirit::mObject& _o);
void exportTest(bytes const& _output, eth::State const& _statePost); void exportTest(bytes const& _output, eth::State const& _statePost);
static void checkExpectedState(eth::State const& _stateExpect, eth::State const& _statePost, WhenError _throw = WhenError::Throw); static void checkExpectedState(eth::State const& _stateExpect, eth::State const& _statePost, WhenError _throw = WhenError::Throw);
static void checkExpectedState(eth::State const& _stateExpect, eth::State const& _statePost, stateOptionsMap const& _expectedStateOptions, WhenError _throw = WhenError::Throw);
eth::State m_statePre; eth::State m_statePre;
eth::State m_statePost; eth::State m_statePost;

Loading…
Cancel
Save