diff --git a/eth/main.cpp b/eth/main.cpp index 0b287471d..1f5b6d574 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -200,6 +200,15 @@ enum class NodeMode Full }; +void doInitDAG(unsigned _n) +{ + BlockInfo bi; + bi.number = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + Ethasher::get()->full(bi); + exit(0); +} + static const unsigned NoDAGInit = (unsigned)-3; int main(int argc, char** argv) @@ -440,6 +449,12 @@ int main(int argc, char** argv) } } + + // Two codepaths is necessary since named block require database, but numbered + // blocks are superuseful to have when database is already open in another process. + if (initDAG < NoDAGInit) + doInitDAG(initDAG); + if (!clientName.empty()) clientName += "/"; @@ -460,16 +475,8 @@ int main(int argc, char** argv) miners ); - if (initDAG != NoDAGInit) - { - BlockInfo bi; - bi.number = (initDAG == LatestBlock || initDAG == PendingBlock) ? - web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0) : - initDAG; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; - Ethasher::get()->full(bi); - return 0; - } + if (initDAG == LatestBlock || initDAG == PendingBlock) + doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0)); web3.setIdealPeerCount(peers); std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index ccb9a2768..f645f15fa 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -161,9 +161,15 @@ public: } } + std::string at(bytes const& _key) const { return at(&_key); } std::string at(bytesConstRef _key) const; + void insert(bytes const& _key, bytes const& _value) { insert(&_key, &_value); } + void insert(bytesConstRef _key, bytes const& _value) { insert(_key, &_value); } + void insert(bytes const& _key, bytesConstRef _value) { insert(&_key, _value); } void insert(bytesConstRef _key, bytesConstRef _value); + void remove(bytes const& _key) { remove(&_key); } void remove(bytesConstRef _key); + bool contains(bytes const& _key) { return contains(&_key); } bool contains(bytesConstRef _key) { return !at(_key).empty(); } class iterator diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 66f08d2bf..0be8cd765 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -40,7 +40,7 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) populate(_block, _s, _h); } -void BlockInfo::setEmpty() +void BlockInfo::clear() { parentHash = h256(); sha3Uncles = EmptyListSHA3; @@ -105,8 +105,9 @@ h256 BlockInfo::headerHash(bytesConstRef _block) void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) { -// m_hash = dev::sha3(_header.data()); m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); m_seedHash = h256(); int field = 0; @@ -172,13 +173,21 @@ void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); } +template h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue) +{ + MemoryDB db; + GenericTrieDB t(&db); + t.init(); + for (unsigned i = 0; i < _itemCount; ++i) + t.insert(_getKey(i), _getValue(i)); + return t.root(); +} + void BlockInfo::verifyInternals(bytesConstRef _block) const { RLP root(_block); - u256 mgp = (u256)-1; - - OverlayDB db; + /*OverlayDB db; GenericTrieDB t(&db); t.init(); unsigned i = 0; @@ -186,12 +195,13 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const { bytes k = rlp(i); t.insert(&k, tr.data()); - u256 gasprice = tr[1].toInt(); - mgp = min(mgp, gasprice); // the minimum gas price is not used for anything //TODO delete? ++i; } - if (transactionsRoot != t.root()) - BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(t.root(), transactionsRoot)); + if (transactionsRoot != t.root())*/ + auto txList = root[1]; + auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); }); + if (transactionsRoot != expectedRoot) + BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot)); if (sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); @@ -199,7 +209,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - m_hash = m_seedHash = h256(); + noteDirty(); stateRoot = _parent.stateRoot; parentHash = _parent.hash(); number = _parent.number + 1; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 6a3ca68b2..302db5f17 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -116,9 +116,9 @@ public: } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void setEmpty(); + void clear(); - void noteDirty() const { m_hash = m_seedHash= h256(); } + void noteDirty() const { m_hash = m_seedHash = h256(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 48ec55077..f64d6557c 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -384,19 +384,18 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, throw; } #endif - auto newHash = BlockInfo::headerHash(_block); // Check block doesn't already exist first! - if (isKnown(newHash) && !_force) + if (isKnown(bi.hash()) && !_force) { - clog(BlockChainNote) << newHash << ": Not new."; + clog(BlockChainNote) << bi.hash() << ": Not new."; BOOST_THROW_EXCEPTION(AlreadyHaveBlock()); } // Work out its number as the parent's number + 1 if (!isKnown(bi.parentHash)) { - clog(BlockChainNote) << newHash << ": Unknown parent " << bi.parentHash; + clog(BlockChainNote) << bi.hash() << ": Unknown parent " << bi.parentHash; // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } @@ -413,12 +412,12 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, // Check it's not crazy if (bi.timestamp > (u256)time(0)) { - clog(BlockChainNote) << newHash << ": Future time " << bi.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainNote) << bi.hash() << ": Future time " << bi.timestamp << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } - clog(BlockChainNote) << "Attempting import of " << newHash.abridged() << "..."; + clog(BlockChainNote) << "Attempting import of " << bi.hash().abridged() << "..."; #if ETH_TIMED_IMPORTS preliminaryChecks = t.elapsed(); @@ -463,16 +462,16 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, details(bi.parentHash); WriteGuard l(x_details); - m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}); - m_details[bi.parentHash].children.push_back(newHash); + m_details[bi.hash()] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}); + m_details[bi.parentHash].children.push_back(bi.hash()); } { WriteGuard l(x_logBlooms); - m_logBlooms[newHash] = blb; + m_logBlooms[bi.hash()] = blb; } { WriteGuard l(x_receipts); - m_receipts[newHash] = br; + m_receipts[bi.hash()] = br; } #if ETH_TIMED_IMPORTS @@ -484,11 +483,11 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, ReadGuard l2(x_details); ReadGuard l4(x_receipts); ReadGuard l5(x_logBlooms); - m_blocksDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block)); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[newHash].rlp())); + m_blocksDB->Put(m_writeOptions, toSlice(bi.hash()), (ldb::Slice)ref(_block)); + m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.hash()].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraReceipts), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); + m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[bi.hash()].rlp())); + m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(m_receipts[bi.hash()].rlp())); } #if ETH_TIMED_IMPORTS @@ -535,13 +534,13 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, if (td > details(last).totalDifficulty) { unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, newHash); + tie(route, common, commonIndex) = treeRoute(last, bi.hash()); { WriteGuard l(x_lastBlockHash); - m_lastBlockHash = newHash; + m_lastBlockHash = bi.hash(); } - m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32)); + m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32)); // Most of the time these two will be equal - only when we're doing a chain revert will they not be if (common != last) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c1f37a553..fcd223661 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -99,7 +99,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock = CanonBlockChain::genesis(); } else - m_previousBlock.setEmpty(); + m_previousBlock.clear(); resetCurrent(); @@ -190,6 +190,8 @@ State& State::operator=(State const& _s) m_blockReward = _s.m_blockReward; m_lastTx = _s.m_lastTx; paranoia("after state cloning (assignment op)", true); + + m_committedToMine = false; return *this; } @@ -276,8 +278,8 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi) { bool ret = false; // BLOCK - BlockInfo bi = _bi; - if (!bi) + BlockInfo bi = _bi ? _bi : _bc.info(_block); +/* if (!bi) while (1) { try @@ -299,7 +301,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi) cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl; cerr << _e.what() << endl; } - } + }*/ if (bi == m_currentBlock) { // We mined the last block. @@ -364,7 +366,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const #endif // Check family: - BlockInfo biParent(_bc.block(_bi.parentHash)); + BlockInfo biParent = _bc.info(_bi.parentHash); _bi.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -374,7 +376,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const BlockInfo biGrandParent; if (biParent.number) - biGrandParent.populate(_bc.block(biParent.parentHash)); + biGrandParent = _bc.info(biParent.parentHash); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); @@ -434,6 +436,8 @@ void State::resetCurrent() m_lastTx = m_db; m_state.setRoot(m_previousBlock.stateRoot); + m_committedToMine = false; + paranoia("begin resetCurrent", true); } @@ -539,6 +543,9 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) // m_currentBlock is assumed to be prepopulated and reset. BlockInfo bi(_block, _checkNonce ? CheckEverything : IgnoreNonce); + cdebug << "enacting" << BlockInfo::headerHash(_block).abridged() << "==" << bi.hash().abridged() << "on" << m_previousBlock.hash().abridged(); + cdebug << m_currentBlock; + #if !ETH_RELEASE assert(m_previousBlock.hash() == bi.parentHash); assert(m_currentBlock.parentHash == bi.parentHash); @@ -551,6 +558,10 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) // Populate m_currentBlock with the correct values. m_currentBlock = bi; m_currentBlock.verifyInternals(_block); + m_currentBlock.noteDirty(); + + cdebug << "populated and verified. incoming block hash is" << m_currentBlock.hash().abridged(); + cdebug << m_currentBlock; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -620,6 +631,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) // Initialise total difficulty calculation. u256 tdIncrease = m_currentBlock.difficulty; + // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) BOOST_THROW_EXCEPTION(TooManyUncles()); @@ -646,6 +658,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) tdIncrease += uncle.difficulty; rewarded.push_back(uncle); } + applyRewards(rewarded); // Commit all cached state changes to the state trie. @@ -673,6 +686,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } + cdebug << m_currentBlock; + auto hh = m_currentBlock.hash(); + m_currentBlock.noteDirty(); + cdebug << "done enacting. new stateroot is" << m_currentBlock.stateRoot.abridged() << ", hash is" << m_currentBlock.hash().abridged() << " = " << hh; + return tdIncrease; } @@ -687,6 +705,9 @@ void State::cleanup(bool _fullCommit) paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; + m_currentBlock.populateFromParent(m_previousBlock); + + cdebug << "finalising enactment. current -> previous, hash is" << m_previousBlock.hash().abridged(); } else m_db.rollback(); @@ -696,7 +717,7 @@ void State::cleanup(bool _fullCommit) void State::uncommitToMine() { - if (m_currentBlock.sha3Uncles) + if (m_committedToMine) { m_cache.clear(); if (!m_transactions.size()) @@ -705,7 +726,7 @@ void State::uncommitToMine() m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; paranoia("Uncommited to mine", true); - m_currentBlock.sha3Uncles = h256(); + m_committedToMine = false; } } @@ -842,6 +863,8 @@ void State::commitToMine(BlockChain const& _bc) m_currentBlock.gasUsed = gasUsed(); m_currentBlock.stateRoot = m_state.root(); m_currentBlock.parentHash = m_previousBlock.hash(); + + m_committedToMine = true; } MineInfo State::mine(unsigned _msTimeout, bool _turbo) diff --git a/libethereum/State.h b/libethereum/State.h index 2fa4d4af4..451a34806 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -363,6 +363,7 @@ private: BlockInfo m_previousBlock; ///< The previous block's information. BlockInfo m_currentBlock; ///< The current block's information. bytes m_currentBytes; ///< The current block. + bool m_committedToMine = false; ///< Have we committed to mine on the present m_currentBlock? bytes m_currentTxs; ///< The RLP-encoded block of transactions. bytes m_currentUncles; ///< The RLP-encoded block of uncles.