Check State

Incomplete State Support
This commit is contained in:
winsvega 2015-03-27 01:05:45 +03:00
parent b0c8babf0e
commit adba4fb9a1
2 changed files with 108 additions and 30 deletions

View File

@ -25,7 +25,6 @@
#include <chrono>
#include <boost/filesystem/path.hpp>
#include <boost/assign.hpp>
#include <libethereum/Client.h>
#include <liblll/Compiler.h>
@ -107,41 +106,72 @@ 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 iBalance = 0, iNonce = 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") );
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);
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(iBalance, Account::ContractConception);
_state.m_cache[address].setCode(code);
}
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())
_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<iNonce; ++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)
{
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)
{
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) \
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!");
if (_statePost.addressInUse(a.first))
{
CHECK(_stateExpect.balance(a.first) == _statePost.balance(a.first),
"Check State: " << a.first << ": incorrect balance " << _statePost.balance(a.first) << ", expected " << _stateExpect.balance(a.first));
CHECK(_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first),
"Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first));
map<u256, u256> stateStorage = _statePost.storage(a.first);
for (auto const& s: _stateExpect.storage(a.first))
ImportStateOptions addressOptions(true);
if(_expectedStateOptions.size())
{
CHECK(stateStorage[s.first] == s.second,
"Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(stateStorage[s.first]) << ", expected [" << s.first << "] = " << toHex(s.second));
try
{
addressOptions = _expectedStateOptions.at(a.first);
}
catch(std::out_of_range)
{
BOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!");
break;
}
}
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)) << "'");
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));
}
}
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
if (m_TestObject.count("expect") > 0)
{
State expectState(Address(), OverlayDB(), eth::BaseState::Empty);
importState(m_TestObject["expect"].get_obj(), expectState);
checkExpectedState(expectState, _statePost, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow);
stateOptionsMap stateMap;
State expectState(Address(), 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"));
}

View File

@ -97,6 +97,17 @@ namespace test
} \
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
{
@ -106,9 +117,12 @@ public:
// imports
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, stateOptionsMap& _stateOptionsMap);
void importTransaction(json_spirit::mObject& _o);
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, stateOptionsMap const& _expectedStateOptions, WhenError _throw = WhenError::Throw);
eth::State m_statePre;
eth::State m_statePost;