diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d3c167a..3330977aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ option(GUI "Build GUI components (AlethZero, Mix)" ON) option(TESTS "Build the tests." ON) option(NOBOOST "No use of boost macros in test functions" OFF) option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF) -option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF) +option(ETHASHCL "Build in support for GPU mining via OpenCL" ON) option(JSCONSOLE "Build in javascript console" ON) # propagates CMake configuration options to the compiler diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index c310b3dd9..cf3a9820e 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -75,7 +75,7 @@ DEV_SIMPLE_EXCEPTION(NoHashRecorded); * The default constructor creates an empty object, which can be tested against with the boolean * conversion operator. */ -struct BlockInfo +class BlockInfo { friend class BlockChain; public: @@ -209,7 +209,7 @@ public: void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); - BlockInfo::parentHash = _parent.hash(); + BlockInfo::m_parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); BlockInfoSub::populateFromParent(_parent); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index ee483aa8b..09c6cbe19 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -196,7 +196,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); static void listDevices() {} - static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, boost::optional) { return false; } + static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: @@ -234,7 +234,7 @@ public: unsigned _deviceId, bool _allowCPU, unsigned _extraGPUMemory, - boost::optional _currentBlock + uint64_t _currentBlock ); static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } @@ -246,7 +246,7 @@ private: void workLoop() override; bool report(uint64_t _nonce); - using Miner::accumulateHashes; + using GenericMiner::accumulateHashes; EthashCLHook* m_hook = nullptr; ethash_cl_miner* m_miner = nullptr; @@ -448,7 +448,7 @@ std::string EthashCPUMiner::platformInfo() class EthashCLHook: public ethash_cl_miner::search_hook { public: - EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {} EthashCLHook(EthashCLHook const&) = delete; void abort() @@ -511,7 +511,7 @@ unsigned EthashGPUMiner::s_deviceId = 0; unsigned EthashGPUMiner::s_numInstances = 0; EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): - Miner(_ci), + GenericMiner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { @@ -527,7 +527,7 @@ EthashGPUMiner::~EthashGPUMiner() bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = EthashAux::eval(work().seedHash, work().headerHash, n); + EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n); if (r.value < work().boundary) return submitProof(Solution{n, r.mixHash}); return false; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 8a654fa51..2b6cb25c2 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -849,7 +849,7 @@ void BlockChain::rescue(OverlayDB& _db) u = m; } cout << " lowest is " << l << endl; - for (;; --l) + for (; l > 0; --l) { h256 h = numberHash(l); cout << "Checking validity of " << l << " (" << h << ")..." << flush; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 2269407b6..d60be548a 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -395,7 +395,12 @@ public: BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); if ((_ir & ImportRequirements::Parent) != 0) - h.verifyParent(header(h.parentHash())); + { + bytes parentHeader(headerData(h.parentHash())); + if (parentHeader.empty()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + h.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, h.parentHash(), HeaderData)); + } res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/Client.h b/libethereum/Client.h index 33d7558cd..896444176 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -346,7 +346,7 @@ public: { m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); m_sealEngine->onSealGenerated([=](bytes const& header){ - return this->submitSealed(header); + this->submitSealed(header); }); init(_host, _dbPath, _forceAction, _networkId); } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index d57741e61..46e0efe95 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -399,43 +399,42 @@ void Host::runAcceptor() auto socket = make_shared(new bi::tcp::socket(m_ioService)); m_tcp4Acceptor.async_accept(socket->ref(), [=](boost::system::error_code ec) { - if (peerCount() > 9 * m_idealPeerCount) + m_accepting = false; + if (ec || !m_run) + { + socket->close(); + return; + } + if (peerCount() > Ingress * m_idealPeerCount) { - clog(NetConnect) << "Dropping incoming connect due to maximum peer count (9 * ideal peer count): " << socket->remoteEndpoint(); + clog(NetConnect) << "Dropping incoming connect due to maximum peer count (" << Ingress << " * ideal peer count): " << socket->remoteEndpoint(); socket->close(); if (ec.value() < 1) runAcceptor(); return; } - // if no error code bool success = false; - if (!ec) + try { - try - { - // incoming connection; we don't yet know nodeid - auto handshake = make_shared(this, socket); - m_connecting.push_back(handshake); - handshake->start(); - success = true; - } - catch (Exception const& _e) - { - clog(NetWarn) << "ERROR: " << diagnostic_information(_e); - } - catch (std::exception const& _e) - { - clog(NetWarn) << "ERROR: " << _e.what(); - } + // incoming connection; we don't yet know nodeid + auto handshake = make_shared(this, socket); + m_connecting.push_back(handshake); + handshake->start(); + success = true; + } + catch (Exception const& _e) + { + clog(NetWarn) << "ERROR: " << diagnostic_information(_e); + } + catch (std::exception const& _e) + { + clog(NetWarn) << "ERROR: " << _e.what(); } if (!success) socket->ref().close(); - - m_accepting = false; - if (ec.value() < 1) - runAcceptor(); + runAcceptor(); }); } } @@ -627,7 +626,7 @@ void Host::run(boost::system::error_code const&) m_nodeTable->processEvents(); // cleanup zombies - DEV_GUARDED(x_connecting); + DEV_GUARDED(x_connecting) m_connecting.remove_if([](std::weak_ptr h){ return h.expired(); }); DEV_GUARDED(x_timers) m_timers.remove_if([](std::shared_ptr t) diff --git a/libp2p/Host.h b/libp2p/Host.h index 17e98f8f6..0fe6da5f9 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -212,7 +212,7 @@ protected: void restoreNetwork(bytesConstRef _b); private: - enum PeerSlotRatio { Egress = 2, Ingress = 9 }; + enum PeerSlotRatio { Egress = 1, Ingress = 4 }; bool havePeerSession(NodeId const& _id) { return !!peerSession(_id); } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index c29788b9f..aec72285c 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,38 +63,23 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { + std::unique_ptr sealer(Ethash::createSealEngine()); s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - Ethash::BlockHeader header(s.info); - f.onSolutionFound([&](EthashProofOfWork::Solution sol) - { - header.m_mixHash = sol.mixHash; - header.m_nonce = sol.nonce; - RLPStream ret; - header.streamRLP(ret); - s.sealBlock(ret); - return true; - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); -} - -void mine(BlockInfo& _bi) -{ - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](EthashProofOfWork::Solution sol) - { - _bi.proof = sol; - return completed = true; - }); - f.setWork(_bi); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + sealer->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + sealer->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); +} + +void mine(Ethash::BlockHeader& _bi) +{ + std::unique_ptr sealer(Ethash::createSealEngine()); + Notified sealed; + sealer->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + sealer->generateSeal(_bi); + sealed.waitNot({}); + _bi = Ethash::BlockHeader(sealed); } } @@ -158,13 +143,24 @@ void ImportTest::importEnv(json_spirit::mObject& _o) 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()); - + RLPStream rlpStream; + rlpStream.appendList(BlockInfo::BasicFields); + + rlpStream << h256(_o["previousHash"].get_str()); + rlpStream << EmptyListSHA3; + rlpStream << Address(_o["currentCoinbase"].get_str()); + rlpStream << h256(); // stateRoot + rlpStream << EmptyTrie; // transactionTrie + rlpStream << EmptyTrie; // receiptTrie + rlpStream << LogBloom(); // bloom + rlpStream << toInt(_o["currentDifficulty"]); + rlpStream << toInt(_o["currentNumber"]); + rlpStream << toInt(_o["currentGasLimit"]); + rlpStream << 0; //gasUsed + rlpStream << toInt(_o["currentTimestamp"]); + rlpStream << std::string(); //extra data + + m_environment.currentBlock = BlockInfo(rlpStream.out(), CheckEverything, h256{}, HeaderData); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; } @@ -824,6 +820,43 @@ LastHashes lastHashes(u256 _currentBlockNumber) return ret; } +dev::eth::Ethash::BlockHeader constructHeader( + h256 const& _parentHash, + h256 const& _sha3Uncles, + Address const& _coinbaseAddress, + h256 const& _stateRoot, + h256 const& _transactionsRoot, + h256 const& _receiptsRoot, + dev::eth::LogBloom const& _logBloom, + u256 const& _difficulty, + u256 const& _number, + u256 const& _gasLimit, + u256 const& _gasUsed, + u256 const& _timestamp, + bytes const& _extraData) +{ + RLPStream rlpStream; + rlpStream.appendList(Ethash::BlockHeader::Fields); + + rlpStream << _parentHash << _sha3Uncles << _coinbaseAddress << _stateRoot << _transactionsRoot << _receiptsRoot << _logBloom + << _difficulty << _number << _gasLimit << _gasUsed << _timestamp << _extraData << h256{} << Nonce{}; + + return Ethash::BlockHeader(rlpStream.out()); +} + +void updateEthashSeal(dev::eth::Ethash::BlockHeader& _header, h256 const& _mixHash, dev::eth::Nonce const& _nonce) +{ + RLPStream source; + _header.streamRLP(source); + RLP sourceRlp(source.out()); + RLPStream header; + header.appendList(Ethash::BlockHeader::Fields); + for (size_t i = 0; i < BlockInfo::BasicFields; i++) + header << sourceRlp[i]; + + header << _mixHash << _nonce; + _header = Ethash::BlockHeader(header.out()); +} namespace { diff --git a/test/TestHelper.h b/test/TestHelper.h index 420278838..735535492 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -27,6 +27,7 @@ #include #include "JsonSpiritHeaders.h" +#include #include #include #include @@ -62,7 +63,7 @@ class State; void mine(Client& c, int numBlocks); void connectClients(Client& c1, Client& c2); void mine(State& _s, BlockChain const& _bc); -void mine(BlockInfo& _bi); +void mine(Ethash::BlockHeader& _bi); } @@ -175,7 +176,21 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o); void checkStorage(std::map _expectedStore, std::map _resultStore, Address _expectedAddr); void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs); void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates); - +dev::eth::Ethash::BlockHeader constructHeader( + h256 const& _parentHash, + h256 const& _sha3Uncles, + Address const& _coinbaseAddress, + h256 const& _stateRoot, + h256 const& _transactionsRoot, + h256 const& _receiptsRoot, + dev::eth::LogBloom const& _logBloom, + u256 const& _difficulty, + u256 const& _number, + u256 const& _gasLimit, + u256 const& _gasUsed, + u256 const& _timestamp, + bytes const& _extraData); +void updateEthashSeal(dev::eth::Ethash::BlockHeader& _header, h256 const& _mixHash, dev::eth::Nonce const& _nonce); void executeTests(const std::string& _name, const std::string& _testPathAppendix, const boost::filesystem::path _pathToFiller, std::function doTests); void userDefinedTest(std::function doTests); RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj); @@ -224,7 +239,7 @@ public: bool inputLimits = false; bool bigData = false; bool wallet = false; - bool nonetwork = true; + bool nonetwork = false; bool nodag = true; /// @} diff --git a/test/fuzzTesting/checkRandomStateTest.cpp b/test/fuzzTesting/checkRandomStateTest.cpp index 01366cd4d..adbb953f3 100644 --- a/test/fuzzTesting/checkRandomStateTest.cpp +++ b/test/fuzzTesting/checkRandomStateTest.cpp @@ -87,7 +87,7 @@ bool doStateTest(mValue& _v) try { - output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index d533ac2da..be751f2b7 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -233,7 +233,7 @@ void doStateTests(json_spirit::mValue& _v) eth::State theState = importer.m_statePre; try { - output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index c3cd75b0d..0e69793e2 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing, h256{}, HeaderData); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index f9d83e9c6..7c9b7197f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -21,6 +21,7 @@ #include #include +#include #include "../TestUtils.h" using namespace std; @@ -139,7 +140,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); + Ethash::BlockHeader blockInfo((static_cast(_client)).bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index cf44dfd9f..764585520 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -37,16 +37,17 @@ namespace dev { namespace test { typedef std::vector uncleList; typedef std::pair blockSet; -BlockInfo constructBlock(mObject& _o); -bytes createBlockRLPFromFields(mObject& _tObj); -RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList); +using BlockHeader = Ethash::BlockHeader; + +BlockHeader constructBlock(mObject& _o, h256 const& _stateRoot = h256{}); +bytes createBlockRLPFromFields(mObject& _tObj, h256 const& _stateRoot = h256{}); +RLPStream createFullBlockFromHeader(BlockHeader const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList); mArray writeTransactionsToJson(Transactions const& txs); -mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi); -void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj); -BlockInfo constructBlock(mObject& _o); -void updatePoW(BlockInfo& _bi); -mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); +mObject writeBlockHeaderToJson(mObject& _o, BlockHeader const& _bi); +void overwriteBlockHeader(BlockHeader& _current_BlockHeader, mObject& _blObj); +void updatePoW(BlockHeader& _bi); +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { @@ -61,12 +62,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) cerr << i.first << endl; TBOOST_REQUIRE(o.count("genesisBlockHeader")); - BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj()); TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); + BlockHeader biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj(), h256{}); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path(), h256{}, WithExisting::Kill)), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,7 +77,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot() = trueState.rootHash(); + biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj(), trueState.rootHash()); else TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); @@ -96,7 +97,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // construct true blockchain TransientDirectory td; - BlockChain trueBc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill); + FullBlockChain trueBc(rlpGenesisBlock.out(), StateDefinition(), td.path(), WithExisting::Kill); if (_fillin) { @@ -107,7 +108,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) genesis.first = rlpGenesisBlock.out(); genesis.second = uncleList(); blockSets.push_back(genesis); - vector vBiBlocks; + vector vBiBlocks; vBiBlocks.push_back(biGenesisBlock); size_t importBlockNumber = 0; @@ -124,8 +125,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) vBiBlocks.push_back(biGenesisBlock); TransientDirectory td_stateDB, td_bc; - BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); + FullBlockChain bc(rlpGenesisBlock.out(), StateDefinition(), td_bc.path(), WithExisting::Kill); + State state(OverlayDB(State::openDB(td_stateDB.path(), h256{}, WithExisting::Kill)), BaseState::Empty); + trueState.setAddress(biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -134,12 +136,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) BlockQueue uncleQueue; uncleList uncles = blockSets.at(i).second; for (size_t j = 0; j < uncles.size(); j++) - uncleQueue.import(&uncles.at(j), bc); + uncleQueue.import(&uncles.at(j), false); const bytes block = blockSets.at(i).first; bc.sync(uncleQueue, state.db(), 4); bc.attemptImport(block, state.db()); - vBiBlocks.push_back(BlockInfo(block)); + vBiBlocks.push_back(BlockHeader(block)); state.sync(bc); } @@ -156,7 +158,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } //get uncles - vector vBiUncles; + vector vBiUncles; blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks, blockSets); BlockQueue uncleBlockQueue; @@ -167,7 +169,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) RLPStream uncle = createFullBlockFromHeader(vBiUncles.at(i)); try { - uncleBlockQueue.import(&uncle.out(), bc); + uncleBlockQueue.import(&uncle.out(), false); uncleBlockQueueList.push_back(uncle.out()); // wait until block is verified this_thread::sleep_for(chrono::seconds(1)); @@ -205,14 +207,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) txList.push_back(txi); blObj["transactions"] = writeTransactionsToJson(txList); - BlockInfo current_BlockHeader = state.info(); + BlockHeader current_BlockHeader = state.info(); RLPStream uncleStream; uncleStream.appendList(vBiUncles.size()); for (unsigned i = 0; i < vBiUncles.size(); ++i) { RLPStream uncleRlp; - vBiUncles[i].streamRLP(uncleRlp, WithNonce); + vBiUncles[i].streamRLP(uncleRlp); uncleStream.appendRaw(uncleRlp.out()); } @@ -225,7 +227,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); + current_BlockHeader.setSha3Uncles(sha3(uncleStream.out())); updatePoW(current_BlockHeader); } @@ -330,7 +332,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blockRLP = importByteArray(blObj["rlp"].get_str()); trueState.sync(trueBc); trueBc.import(blockRLP, trueState.db()); - if (trueBc.info() != BlockInfo(blockRLP)) + if (trueBc.info() != BlockHeader(blockRLP)) importedAndBest = false; trueState.sync(trueBc); } @@ -363,17 +365,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(blObj.count("blockHeader")); mObject tObj = blObj["blockHeader"].get_obj(); - BlockInfo blockHeaderFromFields; + BlockHeader blockHeaderFromFields; const bytes c_rlpBytesBlockHeader = createBlockRLPFromFields(tObj); const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader); - blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce); + blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreSeal); - BlockInfo blockFromRlp = trueBc.info(); + BlockHeader blockFromRlp(trueBc.header()); if (importedAndBest) { //Check the fields restored from RLP to original fields - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithProof) == blockFromRlp.headerHash(WithProof)), "hash in given RLP not matching the block hash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); @@ -381,14 +383,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty() == blockFromRlp.difficulty()), "difficulty in given RLP not matching the block difficulty!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number() == blockFromRlp.number()), "number in given RLP not matching the block number!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit() == blockFromRlp.gasLimit()),"gasLimit in given RLP not matching the block gasLimit!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed() == blockFromRlp.gasUsed()), "gasUsed in given RLP not matching the block gasUsed!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash() == blockFromRlp.mixHash()), "mixHash in given RLP not matching the block mixHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce() == blockFromRlp.nonce()), "nonce in given RLP not matching the block nonce!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields == blockFromRlp), "However, blockHeaderFromFields != blockFromRlp!"); @@ -454,7 +456,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // check uncle list // uncles from uncle list field - vector uBlHsFromField; + vector uBlHsFromField; if (blObj["uncleHeaders"].type() != json_spirit::null_type) for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array()) { @@ -462,7 +464,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE((uBlH.size() == 16)); bytes uncleRLP = createBlockRLPFromFields(uBlH); const RLP c_uRLP(uncleRLP); - BlockInfo uncleBlockHeader; + BlockHeader uncleBlockHeader; try { uncleBlockHeader.populateFromHeader(c_uRLP); @@ -475,10 +477,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } // uncles from block RLP - vector uBlHsFromRlp; + vector uBlHsFromRlp; for (auto const& uRLP: root[2]) { - BlockInfo uBl; + BlockHeader uBl; uBl.populateFromHeader(uRLP); uBlHsFromRlp.push_back(uBl); } @@ -499,7 +501,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // helping functions -mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet) +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet) { // write uncle list mArray aUncleList; @@ -521,7 +523,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector { size_t number = (size_t)toInt(uncleHeaderObj["sameAsBlock"]); uncleHeaderObj.erase("sameAsBlock"); - BlockInfo currentUncle = _vBiBlocks[number]; + BlockHeader currentUncle = _vBiBlocks[number]; writeBlockHeaderToJson(uncleHeaderObj, currentUncle); aUncleList.push_back(uncleHeaderObj); _vBiUncles.push_back(currentUncle); @@ -532,7 +534,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector if (uncleHeaderObj.count("sameAsPreviousBlockUncle")) { bytes uncleRLP = _blockSet[(size_t)toInt(uncleHeaderObj["sameAsPreviousBlockUncle"])].second[0]; - BlockInfo uncleHeader(uncleRLP); + BlockHeader uncleHeader(uncleRLP); writeBlockHeaderToJson(uncleHeaderObj, uncleHeader); aUncleList.push_back(uncleHeaderObj); @@ -548,15 +550,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleHeaderObj.erase("overwriteAndRedoPoW"); } - BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); + BlockHeader uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp() = (u256)time(0); - cnote << "uncle block n = " << toString(uncleBlockFromFields.number); + uncleBlockFromFields.setTimestamp((u256)time(0)); + cnote << "uncle block n = " << toString(uncleBlockFromFields.number()); if (_vBiBlocks.size() > 2) { - if (uncleBlockFromFields.number - 1 < _vBiBlocks.size()) - uncleBlockFromFields.populateFromParent(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); + if (uncleBlockFromFields.number() - 1 < _vBiBlocks.size()) + uncleBlockFromFields.populateFromParent(_vBiBlocks[(size_t)uncleBlockFromFields.number() - 1]); else uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 2]); } @@ -565,29 +567,32 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector if (overwrite != "false") { - uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; - uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; - uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); - uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); + uncleBlockFromFields = constructHeader( + overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(), + uncleBlockFromFields.sha3Uncles(), + uncleBlockFromFields.coinbaseAddress(), + overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(), + uncleBlockFromFields.transactionsRoot(), + uncleBlockFromFields.receiptsRoot(), + uncleBlockFromFields.logBloom(), + overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : overwrite == "timestamp" ? uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number() - 1]) : uncleBlockFromFields.difficulty(), + uncleBlockFromFields.number(), + overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit(), + overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed(), + overwrite == "timestamp" ? toInt(uncleHeaderObj["timestamp"]) : uncleBlockFromFields.timestamp(), + uncleBlockFromFields.extraData()); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); - - if (overwrite == "timestamp") - { - uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); - uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); - } } updatePoW(uncleBlockFromFields); if (overwrite == "nonce") - uncleBlockFromFields.nonce = Nonce(uncleHeaderObj["nonce"].get_str()); + updateEthashSeal(uncleBlockFromFields, uncleBlockFromFields.mixHash(), Nonce(uncleHeaderObj["nonce"].get_str())); if (overwrite == "mixHash") - uncleBlockFromFields.mixHash = h256(uncleHeaderObj["mixHash"].get_str()); + updateEthashSeal(uncleBlockFromFields, h256(uncleHeaderObj["mixHash"].get_str()), uncleBlockFromFields.nonce()); writeBlockHeaderToJson(uncleHeaderObj, uncleBlockFromFields); @@ -600,7 +605,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector return aUncleList; } -bytes createBlockRLPFromFields(mObject& _tObj) +bytes createBlockRLPFromFields(mObject& _tObj, h256 const& _stateRoot) { RLPStream rlpStream; rlpStream.appendList(_tObj.count("hash") > 0 ? (_tObj.size() - 1) : _tObj.size()); @@ -614,7 +619,9 @@ bytes createBlockRLPFromFields(mObject& _tObj) if (_tObj.count("coinbase")) rlpStream << importByteArray(_tObj["coinbase"].get_str()); - if (_tObj.count("stateRoot")) + if (_stateRoot) + rlpStream << _stateRoot; + else if (_tObj.count("stateRoot")) rlpStream << importByteArray(_tObj["stateRoot"].get_str()); if (_tObj.count("transactionsTrie")) @@ -653,47 +660,35 @@ bytes createBlockRLPFromFields(mObject& _tObj) return rlpStream.out(); } -void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) +void overwriteBlockHeader(BlockHeader& _header, mObject& _blObj) { auto ho = _blObj["blockHeader"].get_obj(); if (ho.size() != 14) { - BlockInfo tmp = _header; - if (ho.count("parentHash")) - tmp.parentHash() = h256(ho["parentHash"].get_str()); - if (ho.count("uncleHash")) - tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); - if (ho.count("coinbase")) - tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); - if (ho.count("stateRoot")) - tmp.stateRoot() = h256(ho["stateRoot"].get_str()); - if (ho.count("transactionsTrie")) - tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); - if (ho.count("receiptTrie")) - tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); - if (ho.count("bloom")) - tmp.logBloom() = LogBloom(ho["bloom"].get_str()); - if (ho.count("difficulty")) - tmp.difficulty = toInt(ho["difficulty"]); - if (ho.count("number")) - tmp.number = toInt(ho["number"]); - if (ho.count("gasLimit")) - tmp.gasLimit = toInt(ho["gasLimit"]); - if (ho.count("gasUsed")) - tmp.gasUsed = toInt(ho["gasUsed"]); - if (ho.count("timestamp")) - tmp.timestamp() = toInt(ho["timestamp"]); - if (ho.count("extraData")) - tmp.extraData() = importByteArray(ho["extraData"].get_str()); + BlockHeader tmp = constructHeader( + ho.count("parentHash") ? h256(ho["parentHash"].get_str()) : h256{}, + ho.count("uncleHash") ? h256(ho["uncleHash"].get_str()) : EmptyListSHA3, + ho.count("coinbase") ? Address(ho["coinbase"].get_str()) : Address{}, + ho.count("stateRoot") ? h256(ho["stateRoot"].get_str()): h256{}, + ho.count("transactionsTrie") ? h256(ho["transactionsTrie"].get_str()) : EmptyTrie, + ho.count("receiptTrie") ? h256(ho["receiptTrie"].get_str()) : EmptyTrie, + ho.count("bloom") ? LogBloom(ho["bloom"].get_str()) : LogBloom{}, + ho.count("difficulty") ? toInt(ho["difficulty"]) : u256(0), + ho.count("number") ? toInt(ho["number"]) : u256(0), + ho.count("gasLimit") ? toInt(ho["gasLimit"]) : u256(0), + ho.count("gasUsed") ? toInt(ho["gasUsed"]) : u256(0), + ho.count("timestamp") ? toInt(ho["timestamp"]) : u256(0), + ho.count("extraData") ? importByteArray(ho["extraData"].get_str()) : bytes{}); // find new valid nonce - if (tmp != _header && tmp.difficulty) + if (static_cast(tmp) != static_cast(_header) && tmp.difficulty()) mine(tmp); + if (ho.count("mixHash")) - tmp.mixHash = h256(ho["mixHash"].get_str()); + updateEthashSeal(tmp, h256(ho["mixHash"].get_str()), tmp.nonce()); if (ho.count("nonce")) - tmp.nonce = Nonce(ho["nonce"].get_str()); + updateEthashSeal(tmp, tmp.mixHash(), Nonce(ho["nonce"].get_str())); tmp.noteDirty(); _header = tmp; @@ -703,19 +698,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) // take the blockheader as is const bytes c_blockRLP = createBlockRLPFromFields(ho); const RLP c_bRLP(c_blockRLP); - _header.populateFromHeader(c_bRLP, IgnoreNonce); + _header.populateFromHeader(c_bRLP, IgnoreSeal); } } -BlockInfo constructBlock(mObject& _o) +BlockHeader constructBlock(mObject& _o, h256 const& _stateRoot) { - BlockInfo ret; + BlockHeader ret; try { // construct genesis block - const bytes c_blockRLP = createBlockRLPFromFields(_o); + const bytes c_blockRLP = createBlockRLPFromFields(_o, _stateRoot); const RLP c_bRLP(c_blockRLP); - ret.populateFromHeader(c_bRLP, IgnoreNonce); + ret.populateFromHeader(c_bRLP, IgnoreSeal); } catch (Exception const& _e) { @@ -732,7 +727,7 @@ BlockInfo constructBlock(mObject& _o) return ret; } -void updatePoW(BlockInfo& _bi) +void updatePoW(BlockHeader& _bi) { mine(_bi); _bi.noteDirty(); @@ -749,7 +744,7 @@ mArray writeTransactionsToJson(Transactions const& txs) return txArray; } -mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) +mObject writeBlockHeaderToJson(mObject& _o, BlockHeader const& _bi) { _o["parentHash"] = toString(_bi.parentHash()); _o["uncleHash"] = toString(_bi.sha3Uncles()); @@ -758,22 +753,22 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) _o["transactionsTrie"] = toString(_bi.transactionsRoot()); _o["receiptTrie"] = toString(_bi.receiptsRoot()); _o["bloom"] = toString(_bi.logBloom()); - _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); + _o["difficulty"] = toCompactHex(_bi.difficulty(), HexPrefix::Add, 1); _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); - _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); - _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); + _o["gasLimit"] = toCompactHex(_bi.gasLimit(), HexPrefix::Add, 1); + _o["gasUsed"] = toCompactHex(_bi.gasUsed(), HexPrefix::Add, 1); _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); - _o["mixHash"] = toString(_bi.mixHash); - _o["nonce"] = toString(_bi.nonce); + _o["mixHash"] = toString(_bi.mixHash()); + _o["nonce"] = toString(_bi.nonce()); _o["hash"] = toString(_bi.hash()); return _o; } -RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs, bytes const& _uncles) +RLPStream createFullBlockFromHeader(BlockHeader const& _bi, bytes const& _txs, bytes const& _uncles) { RLPStream rlpStream; - _bi.streamRLP(rlpStream, WithNonce); + _bi.streamRLP(rlpStream, WithProof); RLPStream ret(3); ret.appendRaw(rlpStream.out()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 39997572f..a8bc852f0 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hash(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index 45c2fa13e..825ed8b4b 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -63,7 +63,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) try { Listener::ExecTimeGuard guard{i.first}; - output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + output = theState.execute(lastHashes(importer.m_environment.currentBlock.number()), importer.m_transaction).output; } catch (Exception const& _e) { diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index badabd70c..36f22734f 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -102,13 +102,26 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash() = h256(_o["previousHash"].get_str()); - currentBlock.number = toInt(_o["currentNumber"]); - lastHashes = test::lastHashes(currentBlock.number); - currentBlock.gasLimit = toInt(_o["currentGasLimit"]); - currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); + + RLPStream rlpStream; + rlpStream.appendList(BlockInfo::BasicFields); + + rlpStream << h256(_o["previousHash"].get_str()); + rlpStream << EmptyListSHA3; + rlpStream << Address(_o["currentCoinbase"].get_str()); + rlpStream << h256(); // stateRoot + rlpStream << EmptyTrie; // transactionTrie + rlpStream << EmptyTrie; // receiptTrie + rlpStream << LogBloom(); // bloom + rlpStream << toInt(_o["currentDifficulty"]); + rlpStream << toInt(_o["currentNumber"]); + rlpStream << toInt(_o["currentGasLimit"]); + rlpStream << 0; //gasUsed + rlpStream << toInt(_o["currentTimestamp"]); + rlpStream << std::string(); //extra data + currentBlock = BlockInfo(rlpStream.out(), CheckEverything, h256{}, HeaderData); + + lastHashes = test::lastHashes(currentBlock.number()); } mObject FakeExtVM::exportState()