|
@ -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) |
|
|
{ |
|
|
{ |
|
|
|
|
|
stateOptionsMap stateMap; |
|
|
State expectState(Address(), OverlayDB(), eth::BaseState::Empty); |
|
|
State expectState(Address(), OverlayDB(), eth::BaseState::Empty); |
|
|
importState(m_TestObject["expect"].get_obj(), expectState); |
|
|
importState(m_TestObject["expect"].get_obj(), expectState, stateMap); |
|
|
checkExpectedState(expectState, _statePost, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); |
|
|
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")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|