void State::commitToMine(BlockChain const& _bc) { uncommitToMine(); // cnote << "Committing to mine on block" << m_previousBlock.hash.abridged(); #ifdef ETH_PARANOIA commit(); cnote << "Pre-reward stateRoot:" << m_state.root(); #endif m_lastTx = m_db; Addresses uncleAddresses; RLPStream unclesData; unsigned unclesCount = 0; if (m_previousBlock.number != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. // cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); auto p = m_previousBlock.parentHash; for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash(); ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent! for (auto const& u: us) if (!knownUncles.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); ubi.streamRLP(unclesData, WithNonce); ++unclesCount; uncleAddresses.push_back(ubi.coinbaseAddress); } } } MemoryDB tm; GenericTrieDB<MemoryDB> transactionsTrie(&tm); transactionsTrie.init(); MemoryDB rm; GenericTrieDB<MemoryDB> receiptsTrie(&rm); receiptsTrie.init(); RLPStream txs; txs.appendList(m_transactions.size()); for (unsigned i = 0; i < m_transactions.size(); ++i) { RLPStream k; k << i; RLPStream receiptrlp; m_receipts[i].streamRLP(receiptrlp); receiptsTrie.insert(&k.out(), &receiptrlp.out()); RLPStream txrlp; m_transactions[i].streamRLP(txrlp); transactionsTrie.insert(&k.out(), &txrlp.out()); txs.appendRaw(txrlp.out()); } txs.swapOut(m_currentTxs); RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); m_currentBlock.transactionsRoot = transactionsTrie.root(); m_currentBlock.receiptsRoot = receiptsTrie.root(); m_currentBlock.logBloom = logBloom(); m_currentBlock.sha3Uncles = sha3(m_currentUncles); // Apply rewards last of all. applyRewards(uncleAddresses); // Commit any and all changes to the trie that are in the cache, then update the state root accordingly. commit(); // cnote << "Post-reward stateRoot:" << m_state.root().abridged(); // cnote << m_state; // cnote << *this; m_currentBlock.gasUsed = gasUsed(); m_currentBlock.stateRoot = m_state.root(); m_currentBlock.parentHash = m_previousBlock.hash; }
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) { // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE BlockInfo bi(_block, _checkNonce); assert(m_previousBlock.hash == bi.parentHash); assert(m_currentBlock.parentHash == bi.parentHash); assert(rootHash() == m_previousBlock.stateRoot); #endif if (m_currentBlock.parentHash != m_previousBlock.hash) BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. m_currentBlock.populate(_block, _checkNonce); m_currentBlock.verifyInternals(_block); // cnote << "playback begins:" << m_state.root(); // cnote << m_state; MemoryDB tm; GenericTrieDB<MemoryDB> transactionsTrie(&tm); transactionsTrie.init(); MemoryDB rm; GenericTrieDB<MemoryDB> receiptsTrie(&rm); receiptsTrie.init(); LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number); // All ok with the block generally. Play back the transactions now... unsigned i = 0; for (auto const& tr: RLP(_block)[1]) { RLPStream k; k << i; transactionsTrie.insert(&k.out(), tr.data()); execute(lh, tr.data()); RLPStream receiptrlp; m_receipts.back().streamRLP(receiptrlp); receiptsTrie.insert(&k.out(), &receiptrlp.out()); ++i; } if (transactionsTrie.root() != m_currentBlock.transactionsRoot) { cwarn << "Bad transactions state root!"; BOOST_THROW_EXCEPTION(InvalidTransactionsStateRoot()); } if (receiptsTrie.root() != m_currentBlock.receiptsRoot) { cwarn << "Bad receipts state root."; cwarn << "Block:" << toHex(_block); cwarn << "Block RLP:" << RLP(_block); cwarn << "Calculated: " << receiptsTrie.root(); for (unsigned j = 0; j < i; ++j) { RLPStream k; k << j; auto b = asBytes(receiptsTrie.at(&k.out())); cwarn << j << ": "; cwarn << "RLP: " << RLP(b); cwarn << "Hex: " << toHex(b); cwarn << TransactionReceipt(&b); } cwarn << "Recorded: " << m_currentBlock.receiptsRoot; auto rs = _bc.receipts(m_currentBlock.hash); for (unsigned j = 0; j < rs.receipts.size(); ++j) { auto b = rs.receipts[j].rlp(); cwarn << j << ": "; cwarn << "RLP: " << RLP(b); cwarn << "Hex: " << toHex(b); cwarn << rs.receipts[j]; } BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot()); } if (m_currentBlock.logBloom != logBloom()) { cwarn << "Bad log bloom!"; BOOST_THROW_EXCEPTION(InvalidLogBloom()); } // Initialise total difficulty calculation. u256 tdIncrease = m_currentBlock.difficulty; // Check uncles & apply their rewards to state. set<h256> nonces = { m_currentBlock.nonce }; Addresses rewarded; set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); for (auto const& i: RLP(_block)[2]) { if (knownUncles.count(sha3(i.data()))) BOOST_THROW_EXCEPTION(UncleInChain(knownUncles, sha3(i.data()) )); BlockInfo uncle = BlockInfo::fromHeader(i.data()); if (nonces.count(uncle.nonce)) BOOST_THROW_EXCEPTION(DuplicateUncleNonce()); BlockInfo uncleParent(_bc.block(uncle.parentHash)); if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) BOOST_THROW_EXCEPTION(UncleTooOld()); uncle.verifyParent(uncleParent); nonces.insert(uncle.nonce); tdIncrease += uncle.difficulty; rewarded.push_back(uncle.coinbaseAddress); } applyRewards(rewarded); // Commit all cached state changes to the state trie. commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) { cwarn << "Bad state root!"; cnote << "Given to be:" << m_currentBlock.stateRoot; cnote << TrieDB<Address, OverlayDB>(&m_db, m_currentBlock.stateRoot); cnote << "Calculated to be:" << rootHash(); cnote << m_state; cnote << *this; // Rollback the trie. m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidStateRoot()); } if (m_currentBlock.gasUsed != gasUsed()) { // Rollback the trie. m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } return tdIncrease; }