uint64_t toUnsigned(js::mValue const& _v) { switch (_v.type()) { case js::int_type: return _v.get_uint64(); case js::str_type: return fromBigEndian<uint64_t>(fromHex(_v.get_str())); default: return 0; } }
static void buildRLP(js::mValue& _v, RLPStream& _rlp) { if (_v.type() == js::array_type) { RLPStream s; for (auto& i: _v.get_array()) buildRLP(i, s); _rlp.appendList(s.out()); } else if (_v.type() == js::int_type) _rlp.append(_v.get_uint64()); else if (_v.type() == js::str_type) { auto s = _v.get_str(); if (s.size() && s[0] == '#') _rlp.append(bigint(s.substr(1))); else _rlp.append(s); } }
void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { for (auto& i: _v.get_obj()) { cerr << i.first << endl; mObject& o = i.second.get_obj(); if (_fillin) { TBOOST_REQUIRE((o.count("transaction") > 0)); mObject tObj = o["transaction"].get_obj(); //Construct Rlp of the given transaction RLPStream rlpStream = createRLPStreamFromTransactionFields(tObj); o["rlp"] = toHex(rlpStream.out(), 2, HexPrefix::Add); try { Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); if (!txFromFields.signature().isValid()) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); o["sender"] = toString(txFromFields.sender()); o["transaction"] = ImportTest::makeAllFieldsHex(tObj); } catch(Exception const& _e) { //Transaction is InValid cnote << "Transaction Exception: " << diagnostic_information(_e); o.erase(o.find("transaction")); if (o.count("expect") > 0) { bool expectInValid = (o["expect"].get_str() == "invalid"); if (Options::get().checkState) {TBOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");} else {TBOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");} o.erase(o.find("expect")); } } //Transaction is Valid if (o.count("expect") > 0) { bool expectValid = (o["expect"].get_str() == "valid"); if (Options::get().checkState) {TBOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");} else {TBOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");} o.erase(o.find("expect")); } } else { TBOOST_REQUIRE((o.count("rlp") > 0)); Transaction txFromRlp; try { bytes stream = importByteArray(o["rlp"].get_str()); RLP rlp(stream); txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything); if (!txFromRlp.signature().isValid()) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); } catch(Exception const& _e) { cnote << i.first; cnote << "Transaction Exception: " << diagnostic_information(_e); TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!"); continue; } catch(...) { TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!"); continue; } TBOOST_REQUIRE((o.count("transaction") > 0)); mObject tObj = o["transaction"].get_obj(); Transaction txFromFields(createRLPStreamFromTransactionFields(tObj).out(), CheckTransaction::Everything); //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((txFromFields.data() == txFromRlp.data()), "Data in given RLP not matching the Transaction data!"); TBOOST_CHECK_MESSAGE((txFromFields.value() == txFromRlp.value()), "Value in given RLP not matching the Transaction value!"); TBOOST_CHECK_MESSAGE((txFromFields.gasPrice() == txFromRlp.gasPrice()), "GasPrice in given RLP not matching the Transaction gasPrice!"); TBOOST_CHECK_MESSAGE((txFromFields.gas() == txFromRlp.gas()),"Gas in given RLP not matching the Transaction gas!"); TBOOST_CHECK_MESSAGE((txFromFields.nonce() == txFromRlp.nonce()),"Nonce in given RLP not matching the Transaction nonce!"); TBOOST_CHECK_MESSAGE((txFromFields.receiveAddress() == txFromRlp.receiveAddress()), "Receive address in given RLP not matching the Transaction 'to' address!"); TBOOST_CHECK_MESSAGE((txFromFields.sender() == txFromRlp.sender()), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!"); TBOOST_CHECK_MESSAGE((txFromFields == txFromRlp), "However, txFromFields != txFromRlp!"); TBOOST_REQUIRE ((o.count("sender") > 0)); Address addressReaded = Address(o["sender"].get_str()); TBOOST_CHECK_MESSAGE((txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded), "Signature address of sender does not match given sender address!"); } }//for }//doTransactionTests
void doVMTests(json_spirit::mValue& v, bool _fillin) { processCommandLineOptions(); for (auto& i: v.get_obj()) { cnote << i.first; mObject& o = i.second.get_obj(); BOOST_REQUIRE(o.count("env") > 0); BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("exec") > 0); FakeExtVM fev; fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); if (_fillin) o["pre"] = mValue(fev.exportState()); fev.importExec(o["exec"].get_obj()); if (fev.code.empty()) { fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.code = fev.thisTxCode; } bytes output; u256 gas; bool vmExceptionOccured = false; auto startTime = std::chrono::high_resolution_clock::now(); try { auto vm = eth::VMFactory::create(fev.gas); output = vm->go(fev, fev.simpleTrace()).toBytes(); gas = vm->gas(); } catch (VMException const& _e) { cnote << "Safe VM Exception"; vmExceptionOccured = true; } catch (Exception const& _e) { cnote << "VM did throw an exception: " << diagnostic_information(_e); BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); } catch (std::exception const& _e) { cnote << "VM did throw an exception: " << _e.what(); BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); } auto endTime = std::chrono::high_resolution_clock::now(); 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) { if (std::string(argv[i]) == "--show-times") { auto testDuration = endTime - startTime; cnote << "Execution time: " << std::chrono::duration_cast<std::chrono::milliseconds>(testDuration).count() << " ms"; break; } } // delete null entries in storage for the sake of comparison for (auto &a: fev.addresses) { vector<u256> keystoDelete; for (auto &s: get<2>(a.second)) { if (s.second == 0) keystoDelete.push_back(s.first); } for (auto const key: keystoDelete ) { get<2>(a.second).erase(key); } } if (_fillin) { o["env"] = mValue(fev.exportEnv()); o["exec"] = mValue(fev.exportExec()); if (!vmExceptionOccured) { o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); fev.push(o, "gas", gas); o["logs"] = exportLog(fev.sub.logs); } } else { if (o.count("post") > 0) // No exceptions expected { BOOST_CHECK(!vmExceptionOccured); BOOST_REQUIRE(o.count("post") > 0); BOOST_REQUIRE(o.count("callcreates") > 0); BOOST_REQUIRE(o.count("out") > 0); BOOST_REQUIRE(o.count("gas") > 0); BOOST_REQUIRE(o.count("logs") > 0); dev::test::FakeExtVM test; test.importState(o["post"].get_obj()); test.importCallCreates(o["callcreates"].get_array()); test.sub.logs = importLog(o["logs"].get_array()); checkOutput(output, o); BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); auto& expectedAddrs = test.addresses; auto& resultAddrs = fev.addresses; for (auto&& expectedPair : expectedAddrs) { auto& expectedAddr = expectedPair.first; auto resultAddrIt = resultAddrs.find(expectedAddr); if (resultAddrIt == resultAddrs.end()) BOOST_ERROR("Missing expected address " << expectedAddr); else { auto& expectedState = expectedPair.second; auto& resultState = resultAddrIt->second; BOOST_CHECK_MESSAGE(std::get<0>(expectedState) == std::get<0>(resultState), expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState)); BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState)); BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code"); checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); } } checkAddresses<std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes> > >(test.addresses, fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); checkLog(fev.sub.logs, test.sub.logs); } else // Exception expected BOOST_CHECK(vmExceptionOccured); } } }