diff --git a/CMakeLists.txt b/CMakeLists.txt index b49a94559..36d9b7695 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,7 +139,6 @@ elseif (BUNDLE STREQUAL "release") # release builds set(D_EVMJIT ON) set(D_JSCONSOLE ON) set(D_JSONRPC ON) - set(D_FRONTIER ON) set(D_CMAKE_BUILD_TYPE "Release") endif () diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 0872aabe4..b1a93aaab 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -223,6 +223,7 @@ + @@ -1819,6 +1820,11 @@ font-size: 14pt &Hermit Mode + + + Dump &Block State as JSON... + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 214dbab1e..6a9db4a22 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1851,6 +1851,46 @@ void Main::on_debugCurrent_triggered() } } +std::string minHex(h256 const& _h) +{ + unsigned i = 0; + for (; i < 31 && !_h[i]; ++i) {} + return toHex(_h.ref().cropped(i)); +} + +void Main::on_dumpBlockState_triggered() +{ +#if ETH_FATDB || !ETH_TRUE + if (auto item = ui->blocks->currentItem()) + { + auto hba = item->data(Qt::UserRole).toByteArray(); + assert(hba.size() == 32); + auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer); + QString fn = QFileDialog::getSaveFileName(this, "Select file to output state dump"); + ofstream f(fn.toStdString()); + if (f.is_open()) + { + js::mObject s; + State state = ethereum()->state(h); + for (pair const& i: state.addresses()) + { + js::mObject a; + a["balance"] = toString(i.second); + a["nonce"] = toString(state.transactionsFrom(i.first)); + a["codeHash"] = state.codeHash(i.first).hex(); + js::mObject st; + for (pair const& j: state.storage(i.first)) + st[minHex(j.first)] = st[minHex(j.second)]; + a["storage"] = st; + s[i.first.hex()] = a; + } + js::mValue v(s); + js::write_stream(v, f, true); + } + } +#endif +} + void Main::debugDumpState(int _add) { if (auto item = ui->blocks->currentItem()) diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index f06048c02..307cc1533 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -193,6 +193,7 @@ private slots: void on_debugCurrent_triggered(); void on_debugDumpState_triggered() { debugDumpState(1); } void on_debugDumpStatePre_triggered() { debugDumpState(0); } + void on_dumpBlockState_triggered(); // Whisper void on_newIdentity_triggered(); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index c6812a112..389d0a8ef 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -41,6 +41,7 @@ enum IncludeProof enum Strictness { CheckEverything, + JustSeal, QuickNonce, IgnoreSeal, CheckNothing diff --git a/libethcore/Common.h b/libethcore/Common.h index c59b28f15..072d78cc3 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -127,15 +127,17 @@ struct ImportRequirements enum { ValidSeal = 1, ///< Validate seal - DontHave = 2, ///< Avoid old blocks UncleBasic = 4, ///< Check the basic structure of the uncles. TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. - Parent = 64, ///< Check parent block header - CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals - CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, + Parent = 64, ///< Check parent block header. + UncleParent = 128, ///< Check uncle parent block header. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals. + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures. + OutOfOrderChecks = ValidSeal | CheckUncles | CheckTransactions, ///< Do all checks that can be done independently of prior blocks having been imported. + InOrderChecks = Parent | UncleParent, ///< Do all checks that cannot be done independently of prior blocks having been imported. + Everything = ValidSeal | CheckUncles | CheckTransactions | Parent | UncleParent, None = 0 }; }; diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 8715507ba..68992286c 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -70,6 +70,7 @@ DEV_SIMPLE_EXCEPTION(InvalidNonce); DEV_SIMPLE_EXCEPTION(InvalidBlockHeaderItemCount); DEV_SIMPLE_EXCEPTION(InvalidBlockNonce); DEV_SIMPLE_EXCEPTION(InvalidParentHash); +DEV_SIMPLE_EXCEPTION(InvalidUncleParentHash); DEV_SIMPLE_EXCEPTION(InvalidNumber); DEV_SIMPLE_EXCEPTION(BlockNotFound); diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index a32f41830..8db2e9356 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -427,11 +427,11 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c return make_tuple(ImportRoute{dead, fresh, goodTransactions}, _bq.doneDrain(badBlocks), count); } -pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept +pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _mustBeNew) noexcept { try { - return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir | ImportRequirements::TransactionBasic)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, ImportRequirements::OutOfOrderChecks), _stateDB, _mustBeNew)); } catch (UnknownParent&) { @@ -453,7 +453,7 @@ pair BlockChain::attemptImport(bytes const& _block, O } } -ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir) +ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _mustBeNew) { // VERIFY: populates from the block and checks the block is internally coherent. VerifiedBlockRef block; @@ -462,7 +462,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(&_block, m_onBad, _ir | ImportRequirements::TransactionBasic); + block = verifyBlock(&_block, m_onBad, ImportRequirements::OutOfOrderChecks); } #if ETH_CATCH catch (Exception& ex) @@ -474,10 +474,10 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import } #endif - return import(block, _db, _ir); + return import(block, _db, _mustBeNew); } -ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir) +ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _db, bool _mustBeNew) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -492,7 +492,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif // Check block doesn't already exist first! - if (isKnown(_block.info.hash()) && (_ir & ImportRequirements::DontHave)) + if (isKnown(_block.info.hash()) && _mustBeNew) { clog(BlockChainNote) << _block.info.hash() << ": Not new."; BOOST_THROW_EXCEPTION(AlreadyHaveBlock()); @@ -528,6 +528,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& BOOST_THROW_EXCEPTION(FutureTime()); } + // Verify parent-critical parts + verifyBlock(_block.block, m_onBad, ImportRequirements::InOrderChecks); + clog(BlockChainChat) << "Attempting import of " << _block.info.hash() << "..."; #if ETH_TIMED_IMPORTS @@ -758,7 +761,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& try { State canary(_db, BaseState::Empty); - canary.populateFromChain(*this, _block.info.hash(), ImportRequirements::DontHave); + canary.populateFromChain(*this, _block.info.hash()); } catch (...) { diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index c08faaa22..54a3e6c0c 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -122,12 +122,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _mutBeNew = true) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, bool _mustBeNew = true); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, bool _mustBeNew = true); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -289,7 +289,7 @@ public: State genesisState(OverlayDB const& _db); /// Verify block and prepare it for enactment - virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir = ImportRequirements::OutOfOrderChecks) const = 0; protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } @@ -410,7 +410,7 @@ public: typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } typename Sealer::BlockHeader header() const { return header(currentHash()); } - virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir = ImportRequirements::OutOfOrderChecks) const override { VerifiedBlockRef res; BlockHeader h; @@ -418,11 +418,11 @@ public: { h = BlockHeader(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - if ((_ir & ImportRequirements::Parent) != 0) + if (!!(_ir & ImportRequirements::Parent)) { bytes parentHeader(headerData(h.parentHash())); if (parentHeader.empty()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); + BOOST_THROW_EXCEPTION(InvalidParentHash() << errinfo_required_h256(h.parentHash()) << errinfo_currentNumber(h.number())); h.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, h.parentHash(), HeaderData)); } res.info = static_cast(h); @@ -443,17 +443,20 @@ public: RLP r(_block); unsigned i = 0; - if (_ir && ImportRequirements::UncleBasic) + if (_ir && (ImportRequirements::UncleBasic | ImportRequirements::UncleParent | ImportRequirements::UncleSeals)) for (auto const& uncle: r[2]) { - BlockHeader h; + BlockHeader uh; try { - h.populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); - bytes parentHeader(headerData(h.parentHash())); - if (parentHeader.empty()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - h.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, h.parentHash(), HeaderData)); + uh.populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + if (!!(_ir & ImportRequirements::UncleParent)) + { + bytes parentHeader(headerData(uh.parentHash())); + if (parentHeader.empty()) + BOOST_THROW_EXCEPTION(InvalidUncleParentHash() << errinfo_required_h256(uh.parentHash()) << errinfo_currentNumber(h.number()) << errinfo_uncleNumber(uh.number())); + uh.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, uh.parentHash(), HeaderData)); + } } catch (Exception& ex) { @@ -463,8 +466,8 @@ public: ex << errinfo_block(_block.toBytes()); // only populate extraData if we actually managed to extract it. otherwise, // we might be clobbering the existing one. - if (!h.extraData().empty()) - ex << errinfo_extraData(h.extraData()); + if (!uh.extraData().empty()) + ex << errinfo_extraData(uh.extraData()); if (_onBad) _onBad(ex); throw; @@ -472,7 +475,7 @@ public: ++i; } i = 0; - if (_ir && ImportRequirements::TransactionBasic) + if (_ir && (ImportRequirements::TransactionBasic | ImportRequirements::TransactionSignatures)) for (RLP const& tr: r[1]) { bytesConstRef d = tr.data(); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b0ebf8547..83b1c0703 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -111,7 +111,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::OutOfOrderChecks); } catch (...) { diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 635b0bbd7..be4d8d081 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -111,7 +111,7 @@ unordered_map CanonBlockChain::createGenesisState() if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); + js::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()["alloc"].get_obj()) { u256 balance;