update test to new Block/State refactoring - credit to winsvega and chriseth

This commit is contained in:
CJentzsch 2015-08-06 00:14:45 +02:00
parent e0863fbd27
commit 4626890913
7 changed files with 87 additions and 92 deletions

View File

@ -25,6 +25,7 @@
#include <chrono> #include <chrono>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libevm/ExtVMFace.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include "Stats.h" #include "Stats.h"
@ -61,7 +62,7 @@ void connectClients(Client& c1, Client& c2)
#endif #endif
} }
void mine(State& s, BlockChain const& _bc) void mine(Block& s, BlockChain const& _bc)
{ {
std::unique_ptr<SealEngineFace> sealer(Ethash::createSealEngine()); std::unique_ptr<SealEngineFace> sealer(Ethash::createSealEngine());
s.commitToSeal(_bc); s.commitToSeal(_bc);
@ -94,23 +95,43 @@ struct MissingFields : virtual Exception {};
bigint const c_max256plus1 = bigint(1) << 256; bigint const c_max256plus1 = bigint(1) << 256;
ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller, testType testTemplate):
m_statePre(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())), m_statePre(OverlayDB(), eth::BaseState::Empty),
m_statePost(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())), m_statePost(OverlayDB(), eth::BaseState::Empty),
m_environment(m_envInfo),
m_testObject(_o) m_testObject(_o)
{ {
importEnv(_o["env"].get_obj()); if (testTemplate == testType::StateTests)
importState(_o["pre"].get_obj(), m_statePre);
importTransaction(_o["transaction"].get_obj());
if (!isFiller)
{ {
importState(_o["post"].get_obj(), m_statePost); importEnv(_o["env"].get_obj());
m_environment.sub.logs = importLog(_o["logs"].get_array()); importTransaction(_o["transaction"].get_obj());
importState(_o["pre"].get_obj(), m_statePre);
if (!isFiller)
{
if (_o.count("post"))
importState(_o["post"].get_obj(), m_statePost);
else
importState(_o["postState"].get_obj(), m_statePost);
m_logsExpected = importLog(_o["logs"].get_array());
}
} }
} }
//executes an imported transacton on preState
bytes ImportTest::executeTest()
{
ExecutionResult res;
eth::State tmpState = m_statePre;
std::pair<ExecutionResult, TransactionReceipt> execOut = m_statePre.execute(m_envInfo, m_transaction);
res = execOut.first;
m_logs = execOut.second.log();
m_statePre.commit();
m_statePost = m_statePre;
m_statePre = tmpState;
return res.output;
}
json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o) json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o)
{ {
static const set<string> hashes {"bloom" , "coinbase", "hash", "mixHash", "parentHash", "receiptTrie", static const set<string> hashes {"bloom" , "coinbase", "hash", "mixHash", "parentHash", "receiptTrie",
@ -139,24 +160,25 @@ json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o)
void ImportTest::importEnv(json_spirit::mObject& _o) void ImportTest::importEnv(json_spirit::mObject& _o)
{ {
assert(_o.count("previousHash") > 0);
assert(_o.count("currentGasLimit") > 0); assert(_o.count("currentGasLimit") > 0);
assert(_o.count("currentDifficulty") > 0); assert(_o.count("currentDifficulty") > 0);
assert(_o.count("currentNumber") > 0);
assert(_o.count("currentTimestamp") > 0); assert(_o.count("currentTimestamp") > 0);
assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentCoinbase") > 0);
assert(_o.count("currentNumber") > 0); m_envInfo.setGasLimit(toInt(_o["currentGasLimit"]));
m_envInfo.setBeneficiary(Address(_o["currentCoinbase"].get_str()));
m_envInfo.setDifficulty(toInt(_o["currentDifficulty"])); m_envInfo.setDifficulty(toInt(_o["currentDifficulty"]));
m_envInfo.setNumber(toInt(_o["currentNumber"])); m_envInfo.setNumber(toInt(_o["currentNumber"]));
m_envInfo.setGasLimit(toInt(_o["currentGasLimit"]));
m_envInfo.setTimestamp(toInt(_o["currentTimestamp"])); m_envInfo.setTimestamp(toInt(_o["currentTimestamp"]));
m_envInfo.setBeneficiary(Address(_o["currentCoinbase"].get_str()));
m_envInfo.setLastHashes( lastHashes( m_envInfo.number() ) );
} }
// import state from not fully declared json_spirit::mObject, writing to _stateOptionsMap which fields were defined in json // 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, AccountMaskMap& o_mask) void ImportTest::importState(json_spirit::mObject& _o, State& _state, AccountMaskMap& o_mask)
{ {
_state.populateFrom(jsonToAccountMap(json_spirit::write_string(_o, false), &o_mask)); std::string jsondata = json_spirit::write_string((json_spirit::mValue)_o, false);
_state.populateFrom(jsonToAccountMap(jsondata, &o_mask));
} }
void ImportTest::importState(json_spirit::mObject& _o, State& _state) void ImportTest::importState(json_spirit::mObject& _o, State& _state)
@ -215,7 +237,7 @@ void ImportTest::importTransaction(json_spirit::mObject& _o)
} }
} }
void ImportTest::checkExpectedState(State const& _stateExpect, State const& _statePost, stateOptionsMap const _expectedStateOptions, WhenError _throw) void ImportTest::compareStates(State const& _stateExpect, State const& _statePost, AccountMaskMap const _expectedStateOptions, WhenError _throw)
{ {
#define CHECK(a,b) \ #define CHECK(a,b) \
{ \ { \
@ -230,7 +252,7 @@ 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))
{ {
ImportStateOptions addressOptions(true); AccountMask addressOptions(true);
if(_expectedStateOptions.size()) if(_expectedStateOptions.size())
{ {
try try
@ -244,15 +266,15 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta
} }
} }
if (addressOptions.m_bHasBalance) if (addressOptions.hasBalance())
CHECK((_stateExpect.balance(a.first) == _statePost.balance(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 State: " << a.first << ": incorrect balance " << _statePost.balance(a.first) << ", expected " << _stateExpect.balance(a.first));
if (addressOptions.m_bHasNonce) if (addressOptions.hasNonce())
CHECK((_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(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)); "Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first));
if (addressOptions.m_bHasStorage) if (addressOptions.hasStorage())
{ {
unordered_map<u256, u256> stateStorage = _statePost.storage(a.first); unordered_map<u256, u256> stateStorage = _statePost.storage(a.first);
for (auto const& s: _stateExpect.storage(a.first)) for (auto const& s: _stateExpect.storage(a.first))
@ -266,14 +288,14 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta
"Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(s.second) << ", expected [" << s.first << "] = " << toHex(stateStorage[s.first])); "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(s.second) << ", expected [" << s.first << "] = " << toHex(stateStorage[s.first]));
} }
if (addressOptions.m_bHasCode) if (addressOptions.hasCode())
CHECK((_stateExpect.code(a.first) == _statePost.code(a.first)), 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)) << "'"); "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) void ImportTest::exportTest(bytes const& _output)
{ {
// export output // export output
@ -291,22 +313,22 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost)
m_testObject.erase(m_testObject.find("expectOut")); m_testObject.erase(m_testObject.find("expectOut"));
} }
// export logs // export logs
m_testObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); m_testObject["logs"] = exportLog(m_logs);
// 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; eth::AccountMaskMap stateMap;
State expectState(OverlayDB(), eth::BaseState::Empty); State expectState(OverlayDB(), eth::BaseState::Empty);
importState(m_testObject["expect"].get_obj(), expectState, stateMap); importState(m_testObject["expect"].get_obj(), expectState, stateMap);
checkExpectedState(expectState, _statePost, stateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); compareStates(expectState, m_statePost, stateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow);
m_testObject.erase(m_testObject.find("expect")); m_testObject.erase(m_testObject.find("expect"));
} }
// export post state // export post state
m_testObject["post"] = fillJsonWithState(_statePost); m_testObject["post"] = fillJsonWithState(m_statePost);
m_testObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes()); m_testObject["postStateRoot"] = toHex(m_statePost.rootHash().asBytes());
// export pre state // export pre state
m_testObject["pre"] = fillJsonWithState(m_statePre); m_testObject["pre"] = fillJsonWithState(m_statePre);

View File

@ -32,6 +32,7 @@
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include <libtestutils/Common.h> #include <libtestutils/Common.h>
#ifdef NOBOOST #ifdef NOBOOST
#define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception(); #define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception();
#define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); #define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception();
@ -62,7 +63,7 @@ class State;
void mine(Client& c, int numBlocks); void mine(Client& c, int numBlocks);
void connectClients(Client& c1, Client& c2); void connectClients(Client& c1, Client& c2);
void mine(State& _s, BlockChain const& _bc); void mine(Block& _s, BlockChain const& _bc);
void mine(Ethash::BlockHeader& _bi); void mine(Ethash::BlockHeader& _bi);
} }
@ -122,11 +123,17 @@ namespace test
} \ } \
while (0) while (0)
enum class testType
{
StateTests,
BlockChainTests,
Other
};
class ImportTest class ImportTest
{ {
public: public:
ImportTest(json_spirit::mObject& _o): m_environment(m_envInfo), m_testObject(_o) {} ImportTest(json_spirit::mObject& _o, bool isFiller, testType testTemplate = testType::StateTests);
ImportTest(json_spirit::mObject& _o, bool isFiller);
// imports // imports
void importEnv(json_spirit::mObject& _o); void importEnv(json_spirit::mObject& _o);
@ -135,14 +142,16 @@ public:
void importTransaction(json_spirit::mObject& _o); void importTransaction(json_spirit::mObject& _o);
static json_spirit::mObject& makeAllFieldsHex(json_spirit::mObject& _o); static json_spirit::mObject& makeAllFieldsHex(json_spirit::mObject& _o);
void exportTest(bytes const& _output, eth::State const& _statePost); bytes executeTest();
static void checkExpectedState(eth::State const& _stateExpect, eth::State const& _statePost, stateOptionsMap const _expectedStateOptions = stateOptionsMap(), WhenError _throw = WhenError::Throw); void exportTest(bytes const& _output);
static void compareStates(eth::State const& _stateExpect, eth::State const& _statePost, eth::AccountMaskMap const _expectedStateOptions = eth::AccountMaskMap(), WhenError _throw = WhenError::Throw);
eth::State m_statePre; eth::State m_statePre;
eth::State m_statePost; eth::State m_statePost;
eth::EnvInfo m_envInfo; eth::EnvInfo m_envInfo;
eth::ExtVMFace m_environment; eth::Transaction m_transaction;
eth::Transaction m_transaction; eth::LogEntries m_logs;
eth::LogEntries m_logsExpected;
private: private:
json_spirit::mObject& m_testObject; json_spirit::mObject& m_testObject;
@ -196,7 +205,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin);
void doBlockchainTests(json_spirit::mValue& _v, bool _fillin); void doBlockchainTests(json_spirit::mValue& _v, bool _fillin);
void doRlpTests(json_spirit::mValue& v, bool _fillin); void doRlpTests(json_spirit::mValue& v, bool _fillin);
template<typename mapType> /*template<typename mapType>
void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)
{ {
for (auto& resultPair : _resultAddrs) for (auto& resultPair : _resultAddrs)
@ -207,7 +216,7 @@ void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)
TBOOST_ERROR("Missing result address " << resultAddr); TBOOST_ERROR("Missing result address " << resultAddr);
} }
TBOOST_CHECK((_expectedAddrs == _resultAddrs)); TBOOST_CHECK((_expectedAddrs == _resultAddrs));
} }*/
class Options class Options
{ {

View File

@ -101,7 +101,9 @@ void ClientBaseFixture::enumerateClients(std::function<void(Json::Value const&,
{ {
enumerateBlockchains([&callback](Json::Value const& _json, BlockChain const& _bc, State _state) -> void enumerateBlockchains([&callback](Json::Value const& _json, BlockChain const& _bc, State _state) -> void
{ {
FixedClient client(_bc, _state); cerr << "void ClientBaseFixture::enumerateClients. FixedClient now accepts block not sate!" << endl;
_state.commit(); //unused variable. remove this line
FixedClient client(_bc, eth::Block {});
callback(_json, client); callback(_json, client);
}); });
} }

View File

@ -545,7 +545,7 @@ BOOST_AUTO_TEST_CASE(multisig_value_transfer)
// 4 owners, set required to 3 // 4 owners, set required to 3
BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
// check that balance is and stays zero at destination address // check that balance is and stays zero at destination address
h256 opHash("8f27f478ebcfaf28b0c354f4809ace8087000d668b89c8bc3b1b608bfdbe6654"); h256 opHash("6244b4fa93f73e09db0ae52750095ca0364a76b72bc01723c97011fcb876cc9e");
BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
m_sender = Address(0x12); m_sender = Address(0x12);
BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash)); BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
@ -596,7 +596,7 @@ BOOST_AUTO_TEST_CASE(revoke_transaction)
BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
// create a transaction // create a transaction
Address deployer = m_sender; Address deployer = m_sender;
h256 opHash("8f27f478ebcfaf28b0c354f4809ace8087000d668b89c8bc3b1b608bfdbe6654"); h256 opHash("6244b4fa93f73e09db0ae52750095ca0364a76b72bc01723c97011fcb876cc9e");
BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
m_sender = Address(0x12); m_sender = Address(0x12);
BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash)); BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));

View File

@ -1151,8 +1151,10 @@ BOOST_AUTO_TEST_CASE(blockchain)
" blockNumber = block.number;\n" " blockNumber = block.number;\n"
" }\n" " }\n"
"}\n"; "}\n";
m_envInfo.setBeneficiary(Address(0x123));
m_envInfo.setNumber(7);
compileAndRun(sourceCode, 27); compileAndRun(sourceCode, 27);
BOOST_CHECK(callContractFunctionWithValue("someInfo()", 28) == encodeArgs(28, 0, 1)); BOOST_CHECK(callContractFunctionWithValue("someInfo()", 28) == encodeArgs(28, 0x123, 7));
} }
BOOST_AUTO_TEST_CASE(msg_sig) BOOST_AUTO_TEST_CASE(msg_sig)
@ -1187,12 +1189,14 @@ BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same)
BOOST_AUTO_TEST_CASE(now) BOOST_AUTO_TEST_CASE(now)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function someInfo() returns (bool success) {\n" " function someInfo() returns (bool equal, uint val) {\n"
" return block.timestamp == now && now > 0;\n" " equal = block.timestamp == now;\n"
" val = now;\n"
" }\n" " }\n"
"}\n"; "}\n";
m_envInfo.setTimestamp(9);
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("someInfo()") == encodeArgs(true)); BOOST_CHECK(callContractFunction("someInfo()") == encodeArgs(true, 9));
} }
BOOST_AUTO_TEST_CASE(type_conversions_cleanup) BOOST_AUTO_TEST_CASE(type_conversions_cleanup)
@ -5099,31 +5103,6 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0))); BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0)));
} }
BOOST_AUTO_TEST_CASE(string_bytes_conversion)
{
char const* sourceCode = R"(
contract Test {
string s;
bytes b;
function f(string _s, uint n) returns (byte) {
b = bytes(_s);
s = string(b);
return bytes(s)[n];
}
function l() returns (uint) { return bytes(s).length; }
}
)";
compileAndRun(sourceCode, 0, "Test");
BOOST_CHECK(callContractFunction(
"f(string,uint256)",
u256(0x40),
u256(2),
u256(6),
string("abcdef")
) == encodeArgs("c"));
BOOST_CHECK(callContractFunction("l()") == encodeArgs(u256(6)));
}
BOOST_AUTO_TEST_CASE(string_as_mapping_key) BOOST_AUTO_TEST_CASE(string_as_mapping_key)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

View File

@ -2149,23 +2149,6 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
} }
BOOST_AUTO_TEST_CASE(string_bytes_conversion)
{
char const* text = R"(
contract Test {
string s;
bytes b;
function h(string _s) external { bytes(_s).length; }
function i(string _s) internal { bytes(_s).length; }
function j() internal { bytes(s).length; }
function k(bytes _b) external { string(_b); }
function l(bytes _b) internal { string(_b); }
function m() internal { string(b); }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -44,7 +44,6 @@ public:
ExecutionFramework() ExecutionFramework()
{ {
g_logVerbosity = 0; g_logVerbosity = 0;
m_state.resetCurrent();
} }
bytes const& compileAndRunWithoutCheck( bytes const& compileAndRunWithoutCheck(
@ -185,7 +184,7 @@ protected:
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0)
{ {
m_state.addBalance(m_sender, _value); // just in case m_state.addBalance(m_sender, _value); // just in case
eth::Executive executive(m_state, eth::EnvInfo(), 0); eth::Executive executive(m_state, m_envInfo, 0);
eth::ExecutionResult res; eth::ExecutionResult res;
executive.setResultRecipient(res); executive.setResultRecipient(res);
eth::Transaction t = eth::Transaction t =
@ -226,6 +225,7 @@ protected:
dev::solidity::CompilerStack m_compiler; dev::solidity::CompilerStack m_compiler;
Address m_sender; Address m_sender;
Address m_contractAddress; Address m_contractAddress;
eth::EnvInfo m_envInfo;
eth::State m_state; eth::State m_state;
u256 const m_gasPrice = 100 * eth::szabo; u256 const m_gasPrice = 100 * eth::szabo;
u256 const m_gas = 100000000; u256 const m_gas = 100000000;