aboutsummaryrefslogtreecommitdiffstats
path: root/TestHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TestHelper.cpp')
-rw-r--r--TestHelper.cpp723
1 files changed, 723 insertions, 0 deletions
diff --git a/TestHelper.cpp b/TestHelper.cpp
new file mode 100644
index 00000000..e86b84aa
--- /dev/null
+++ b/TestHelper.cpp
@@ -0,0 +1,723 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file TestHelper.cpp
+ * @author Marko Simovic <markobarko@gmail.com>
+ * @date 2014
+ */
+
+#include "TestHelper.h"
+
+#include <thread>
+#include <chrono>
+
+#include <boost/filesystem/path.hpp>
+
+#include <libethereum/Client.h>
+#include <liblll/Compiler.h>
+#include <libevm/VMFactory.h>
+#include "Stats.h"
+
+using namespace std;
+using namespace dev::eth;
+
+namespace dev
+{
+namespace eth
+{
+
+void mine(Client& c, int numBlocks)
+{
+ auto startBlock = c.blockChain().details().number;
+
+ c.startMining();
+ while(c.blockChain().details().number < startBlock + numBlocks)
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ c.stopMining();
+}
+
+void connectClients(Client& c1, Client& c2)
+{
+ (void)c1;
+ (void)c2;
+ // TODO: Move to WebThree. eth::Client no longer handles networking.
+#if 0
+ short c1Port = 20000;
+ short c2Port = 21000;
+ c1.startNetwork(c1Port);
+ c2.startNetwork(c2Port);
+ c2.connect("127.0.0.1", c1Port);
+#endif
+}
+}
+
+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):
+ m_statePre(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())),
+ m_statePost(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())),
+ m_TestObject(_o)
+{
+ importEnv(_o["env"].get_obj());
+ importState(_o["pre"].get_obj(), m_statePre);
+ importTransaction(_o["transaction"].get_obj());
+
+ if (!isFiller)
+ {
+ importState(_o["post"].get_obj(), m_statePost);
+ m_environment.sub.logs = importLog(_o["logs"].get_array());
+ }
+}
+
+void ImportTest::importEnv(json_spirit::mObject& _o)
+{
+ assert(_o.count("previousHash") > 0);
+ assert(_o.count("currentGasLimit") > 0);
+ assert(_o.count("currentDifficulty") > 0);
+ assert(_o.count("currentTimestamp") > 0);
+ assert(_o.count("currentCoinbase") > 0);
+ assert(_o.count("currentNumber") > 0);
+
+ m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str());
+ m_environment.currentBlock.number = toInt(_o["currentNumber"]);
+ m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]);
+ m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]);
+ m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]);
+ m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str());
+
+ m_statePre.m_previousBlock = m_environment.previousBlock;
+ m_statePre.m_currentBlock = m_environment.currentBlock;
+}
+
+// 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();
+
+ ImportStateOptions stateOptions;
+ u256 balance = 0;
+ u256 nonce = 0;
+
+ 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;
+ if (o.count("code") > 0)
+ {
+ code = importCode(o);
+ stateOptions.m_bHasCode = true;
+ }
+
+ if (code.size())
+ {
+ _state.m_cache[address] = Account(balance, Account::ContractConception);
+ _state.m_cache[address].setCode(code);
+ }
+ else
+ _state.m_cache[address] = Account(balance, Account::NormalCreation);
+
+ 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 < 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!"));
+ }
+}
+
+void ImportTest::importTransaction(json_spirit::mObject& _o)
+{
+ if (_o.count("secretKey") > 0)
+ {
+ assert(_o.count("nonce") > 0);
+ assert(_o.count("gasPrice") > 0);
+ assert(_o.count("gasLimit") > 0);
+ assert(_o.count("to") > 0);
+ assert(_o.count("value") > 0);
+ assert(_o.count("data") > 0);
+
+ if (bigint(_o["nonce"].get_str()) >= c_max256plus1)
+ BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") );
+ if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1)
+ BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") );
+ if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1)
+ BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") );
+ if (bigint(_o["value"].get_str()) >= c_max256plus1)
+ BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") );
+
+ m_transaction = _o["to"].get_str().empty() ?
+ Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) :
+ Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), Address(_o["to"].get_str()), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str()));
+ }
+ else
+ {
+ RLPStream transactionRLPStream = createRLPStreamFromTransactionFields(_o);
+ RLP transactionRLP(transactionRLPStream.out());
+ m_transaction = Transaction(transactionRLP.data(), CheckTransaction::Everything);
+ }
+}
+
+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
+ m_TestObject["out"] = "0x" + toHex(_output);
+
+ // export logs
+ m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries());
+
+ // 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());
+
+ // export pre state
+ m_TestObject["pre"] = fillJsonWithState(m_statePre);
+}
+
+json_spirit::mObject fillJsonWithState(State _state)
+{
+ // export pre state
+ json_spirit::mObject oState;
+
+ for (auto const& a: _state.addresses())
+ {
+ json_spirit::mObject o;
+ o["balance"] = toString(_state.balance(a.first));
+ o["nonce"] = toString(_state.transactionsFrom(a.first));
+ {
+ json_spirit::mObject store;
+ for (auto const& s: _state.storage(a.first))
+ store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second));
+ o["storage"] = store;
+ }
+ o["code"] = "0x" + toHex(_state.code(a.first));
+
+ oState[toString(a.first)] = o;
+ }
+ return oState;
+}
+
+u256 toInt(json_spirit::mValue const& _v)
+{
+ switch (_v.type())
+ {
+ case json_spirit::str_type: return u256(_v.get_str());
+ case json_spirit::int_type: return (u256)_v.get_uint64();
+ case json_spirit::bool_type: return (u256)(uint64_t)_v.get_bool();
+ case json_spirit::real_type: return (u256)(uint64_t)_v.get_real();
+ default: cwarn << "Bad type for scalar: " << _v.type();
+ }
+ return 0;
+}
+
+byte toByte(json_spirit::mValue const& _v)
+{
+ switch (_v.type())
+ {
+ case json_spirit::str_type: return (byte)stoi(_v.get_str());
+ case json_spirit::int_type: return (byte)_v.get_uint64();
+ case json_spirit::bool_type: return (byte)_v.get_bool();
+ case json_spirit::real_type: return (byte)_v.get_real();
+ default: cwarn << "Bad type for scalar: " << _v.type();
+ }
+ return 0;
+}
+
+bytes importByteArray(std::string const& _str)
+{
+ return fromHex(_str.substr(0, 2) == "0x" ? _str.substr(2) : _str, WhenError::Throw);
+}
+
+bytes importData(json_spirit::mObject& _o)
+{
+ bytes data;
+ if (_o["data"].type() == json_spirit::str_type)
+ data = importByteArray(_o["data"].get_str());
+ else
+ for (auto const& j: _o["data"].get_array())
+ data.push_back(toByte(j));
+ return data;
+}
+
+bytes importCode(json_spirit::mObject& _o)
+{
+ bytes code;
+ if (_o["code"].type() == json_spirit::str_type)
+ if (_o["code"].get_str().find_first_of("0x") != 0)
+ code = compileLLL(_o["code"].get_str(), false);
+ else
+ code = fromHex(_o["code"].get_str().substr(2));
+ else if (_o["code"].type() == json_spirit::array_type)
+ {
+ code.clear();
+ for (auto const& j: _o["code"].get_array())
+ code.push_back(toByte(j));
+ }
+ return code;
+}
+
+LogEntries importLog(json_spirit::mArray& _a)
+{
+ LogEntries logEntries;
+ for (auto const& l: _a)
+ {
+ json_spirit::mObject o = l.get_obj();
+ // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest)
+ assert(o.count("address") > 0);
+ assert(o.count("topics") > 0);
+ assert(o.count("data") > 0);
+ assert(o.count("bloom") > 0);
+ LogEntry log;
+ log.address = Address(o["address"].get_str());
+ for (auto const& t: o["topics"].get_array())
+ log.topics.push_back(h256(t.get_str()));
+ log.data = importData(o);
+ logEntries.push_back(log);
+ }
+ return logEntries;
+}
+
+json_spirit::mArray exportLog(eth::LogEntries _logs)
+{
+ json_spirit::mArray ret;
+ if (_logs.size() == 0) return ret;
+ for (LogEntry const& l: _logs)
+ {
+ json_spirit::mObject o;
+ o["address"] = toString(l.address);
+ json_spirit::mArray topics;
+ for (auto const& t: l.topics)
+ topics.push_back(toString(t));
+ o["topics"] = topics;
+ o["data"] = "0x" + toHex(l.data);
+ o["bloom"] = toString(l.bloom());
+ ret.push_back(o);
+ }
+ return ret;
+}
+
+void checkOutput(bytes const& _output, json_spirit::mObject& _o)
+{
+ int j = 0;
+ if (_o["out"].type() == json_spirit::array_type)
+ for (auto const& d: _o["out"].get_array())
+ {
+ BOOST_CHECK_MESSAGE(_output[j] == toInt(d), "Output byte [" << j << "] different!");
+ ++j;
+ }
+ else if (_o["out"].get_str().find("0x") == 0)
+ BOOST_CHECK(_output == fromHex(_o["out"].get_str().substr(2)));
+ else
+ BOOST_CHECK(_output == fromHex(_o["out"].get_str()));
+}
+
+void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore, Address _expectedAddr)
+{
+ for (auto&& expectedStorePair : _expectedStore)
+ {
+ auto& expectedStoreKey = expectedStorePair.first;
+ auto resultStoreIt = _resultStore.find(expectedStoreKey);
+ if (resultStoreIt == _resultStore.end())
+ BOOST_ERROR(_expectedAddr << ": missing store key " << expectedStoreKey);
+ else
+ {
+ auto& expectedStoreValue = expectedStorePair.second;
+ auto& resultStoreValue = resultStoreIt->second;
+ BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue);
+ }
+ }
+ BOOST_CHECK_EQUAL(_resultStore.size(), _expectedStore.size());
+ for (auto&& resultStorePair: _resultStore)
+ {
+ if (!_expectedStore.count(resultStorePair.first))
+ BOOST_ERROR(_expectedAddr << ": unexpected store key " << resultStorePair.first);
+ }
+}
+
+void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs)
+{
+ BOOST_REQUIRE_EQUAL(_resultLogs.size(), _expectedLogs.size());
+
+ for (size_t i = 0; i < _resultLogs.size(); ++i)
+ {
+ BOOST_CHECK_EQUAL(_resultLogs[i].address, _expectedLogs[i].address);
+ BOOST_CHECK_EQUAL(_resultLogs[i].topics, _expectedLogs[i].topics);
+ BOOST_CHECK(_resultLogs[i].data == _expectedLogs[i].data);
+ }
+}
+
+void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates)
+{
+ BOOST_REQUIRE_EQUAL(_resultCallCreates.size(), _expectedCallCreates.size());
+
+ for (size_t i = 0; i < _resultCallCreates.size(); ++i)
+ {
+ BOOST_CHECK(_resultCallCreates[i].data() == _expectedCallCreates[i].data());
+ BOOST_CHECK(_resultCallCreates[i].receiveAddress() == _expectedCallCreates[i].receiveAddress());
+ BOOST_CHECK(_resultCallCreates[i].gas() == _expectedCallCreates[i].gas());
+ BOOST_CHECK(_resultCallCreates[i].value() == _expectedCallCreates[i].value());
+ }
+}
+
+void userDefinedTest(string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests)
+{
+ for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
+ {
+ string arg = boost::unit_test::framework::master_test_suite().argv[i];
+ if (arg == testTypeFlag)
+ {
+ if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
+ {
+ cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " <filename> <testname>\n";
+ return;
+ }
+ string filename = boost::unit_test::framework::master_test_suite().argv[i + 1];
+ string testname = boost::unit_test::framework::master_test_suite().argv[i + 2];
+ int currentVerbosity = g_logVerbosity;
+ g_logVerbosity = 12;
+ try
+ {
+ cnote << "Testing user defined test: " << filename;
+ json_spirit::mValue v;
+ string s = asString(contents(filename));
+ BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. ");
+ json_spirit::read_string(s, v);
+ json_spirit::mObject oSingleTest;
+
+ json_spirit::mObject::const_iterator pos = v.get_obj().find(testname);
+ if (pos == v.get_obj().end())
+ {
+ cnote << "Could not find test: " << testname << " in " << filename << "\n";
+ return;
+ }
+ else
+ oSingleTest[pos->first] = pos->second;
+
+ json_spirit::mValue v_singleTest(oSingleTest);
+ doTests(v_singleTest, false);
+ }
+ catch (Exception const& _e)
+ {
+ BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e));
+ g_logVerbosity = currentVerbosity;
+ }
+ catch (std::exception const& _e)
+ {
+ BOOST_ERROR("Failed Test with Exception: " << _e.what());
+ g_logVerbosity = currentVerbosity;
+ }
+ g_logVerbosity = currentVerbosity;
+ }
+ }
+}
+
+void executeTests(const string& _name, const string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests)
+{
+ string testPath = getTestPath();
+ testPath += _testPathAppendix;
+
+ if (Options::get().stats)
+ Listener::registerListener(Stats::get());
+
+ if (Options::get().fillTests)
+ {
+ try
+ {
+ cnote << "Populating tests...";
+ json_spirit::mValue v;
+ boost::filesystem::path p(__FILE__);
+ boost::filesystem::path dir = p.parent_path();
+ string s = asString(dev::contents(dir.string() + "/" + _name + "Filler.json"));
+ BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + dir.string() + "/" + _name + "Filler.json is empty.");
+ json_spirit::read_string(s, v);
+ doTests(v, true);
+ writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true)));
+ }
+ catch (Exception const& _e)
+ {
+ BOOST_ERROR("Failed filling test with Exception: " << diagnostic_information(_e));
+ }
+ catch (std::exception const& _e)
+ {
+ BOOST_ERROR("Failed filling test with Exception: " << _e.what());
+ }
+ }
+
+ try
+ {
+ std::cout << "TEST " << _name << ":\n";
+ json_spirit::mValue v;
+ string s = asString(dev::contents(testPath + "/" + _name + ".json"));
+ BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
+ json_spirit::read_string(s, v);
+ Listener::notifySuiteStarted(_name);
+ doTests(v, false);
+ }
+ catch (Exception const& _e)
+ {
+ BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e));
+ }
+ catch (std::exception const& _e)
+ {
+ BOOST_ERROR("Failed test with Exception: " << _e.what());
+ }
+}
+
+RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj)
+{
+ //Construct Rlp of the given transaction
+ RLPStream rlpStream;
+ rlpStream.appendList(_tObj.size());
+
+ if (_tObj.count("nonce"))
+ rlpStream << bigint(_tObj["nonce"].get_str());
+
+ if (_tObj.count("gasPrice"))
+ rlpStream << bigint(_tObj["gasPrice"].get_str());
+
+ if (_tObj.count("gasLimit"))
+ rlpStream << bigint(_tObj["gasLimit"].get_str());
+
+ if (_tObj.count("to"))
+ {
+ if (_tObj["to"].get_str().empty())
+ rlpStream << "";
+ else
+ rlpStream << importByteArray(_tObj["to"].get_str());
+ }
+
+ if (_tObj.count("value"))
+ rlpStream << bigint(_tObj["value"].get_str());
+
+ if (_tObj.count("data"))
+ rlpStream << importData(_tObj);
+
+ if (_tObj.count("v"))
+ rlpStream << bigint(_tObj["v"].get_str());
+
+ if (_tObj.count("r"))
+ rlpStream << bigint(_tObj["r"].get_str());
+
+ if (_tObj.count("s"))
+ rlpStream << bigint(_tObj["s"].get_str());
+
+ if (_tObj.count("extrafield"))
+ rlpStream << bigint(_tObj["extrafield"].get_str());
+
+ return rlpStream;
+}
+
+Options::Options()
+{
+ auto argc = boost::unit_test::framework::master_test_suite().argc;
+ auto argv = boost::unit_test::framework::master_test_suite().argv;
+
+ for (auto i = 0; i < argc; ++i)
+ {
+ auto arg = std::string{argv[i]};
+ if (arg == "--jit")
+ {
+ jit = true;
+ eth::VMFactory::setKind(eth::VMKind::JIT);
+ }
+ else if (arg == "--vmtrace")
+ vmtrace = true;
+ else if (arg == "--filltests")
+ fillTests = true;
+ else if (arg.compare(0, 7, "--stats") == 0)
+ {
+ stats = true;
+ if (arg.size() > 7)
+ statsOutFile = arg.substr(8); // skip '=' char
+ }
+ else if (arg == "--performance")
+ performance = true;
+ else if (arg == "--quadratic")
+ quadratic = true;
+ else if (arg == "--memory")
+ memory = true;
+ else if (arg == "--inputlimits")
+ inputLimits = true;
+ else if (arg == "--bigdata")
+ bigData = true;
+ else if (arg == "--checkstate")
+ checkState = true;
+ else if (arg == "--all")
+ {
+ performance = true;
+ quadratic = true;
+ memory = true;
+ inputLimits = true;
+ bigData = true;
+ checkState = true;
+ }
+ }
+}
+
+Options const& Options::get()
+{
+ static Options instance;
+ return instance;
+}
+
+
+LastHashes lastHashes(u256 _currentBlockNumber)
+{
+ LastHashes ret;
+ for (u256 i = 1; i <= 256 && i <= _currentBlockNumber; ++i)
+ ret.push_back(sha3(toString(_currentBlockNumber - i)));
+ return ret;
+}
+
+
+namespace
+{
+ Listener* g_listener;
+}
+
+void Listener::registerListener(Listener& _listener)
+{
+ g_listener = &_listener;
+}
+
+void Listener::notifySuiteStarted(std::string const& _name)
+{
+ if (g_listener)
+ g_listener->suiteStarted(_name);
+}
+
+void Listener::notifyTestStarted(std::string const& _name)
+{
+ if (g_listener)
+ g_listener->testStarted(_name);
+}
+
+void Listener::notifyTestFinished()
+{
+ if (g_listener)
+ g_listener->testFinished();
+}
+
+} } // namespaces