bool State::sync(BlockChain const& _bc, h256 _block) { bool ret = false; // BLOCK BlockInfo bi; try { auto b = _bc.block(_block); bi.populate(b); bi.verifyInternals(_bc.block(_block)); } catch (...) { // TODO: Slightly nicer handling? :-) cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl; exit(1); } if (bi == m_currentBlock) { // We mined the last block. // Our state is good - we just need to move on to next. m_previousBlock = m_currentBlock; resetCurrent(); m_currentNumber++; ret = true; } else if (bi == m_previousBlock) { // No change since last sync. // Carry on as we were. } else { // New blocks available, or we've switched to a different branch. All change. // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) std::vector<h256> chain; while (bi.stateRoot != BlockInfo::genesis().hash && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash); // push back for later replay. bi.populate(_bc.block(bi.parentHash)); // move to parent. } m_previousBlock = bi; resetCurrent(); // Iterate through in reverse, playing back each of the blocks. for (auto it = chain.rbegin(); it != chain.rend(); ++it) playback(_bc.block(*it), true); m_currentNumber = _bc.details(_block).number + 1; resetCurrent(); ret = true; } return ret; }
// @returns the block that represents the difference between m_previousBlock and m_currentBlock. // (i.e. all the transactions we executed). void State::commitToMine(BlockChain const& _bc) { if (m_currentBlock.sha3Transactions != h256() || m_currentBlock.sha3Uncles != h256()) { Addresses uncleAddresses; for (auto i: RLP(m_currentUncles)) uncleAddresses.push_back(i[2].toHash<Address>()); unapplyRewards(uncleAddresses); } cnote << "Commiting to mine on" << m_previousBlock.hash; RLPStream uncles; Addresses uncleAddresses; if (m_previousBlock != BlockInfo::genesis()) { // Find uncles if we're not a direct child of the genesis. // cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; auto us = _bc.details(m_previousBlock.parentHash).children; assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent! uncles.appendList(us.size() - 1); // one fewer - uncles precludes our parent from the list of grandparent's children. for (auto const& u: us) if (u != m_previousBlock.hash) // ignore our own parent - it's not an uncle. { BlockInfo ubi(_bc.block(u)); ubi.fillStream(uncles, true); uncleAddresses.push_back(ubi.coinbaseAddress); } } else uncles.appendList(0); applyRewards(uncleAddresses); RLPStream txs(m_transactions.size()); for (auto const& i: m_transactions) i.fillStream(txs); txs.swapOut(m_currentTxs); uncles.swapOut(m_currentUncles); m_currentBlock.sha3Transactions = sha3(m_currentTxs); m_currentBlock.sha3Uncles = sha3(m_currentUncles); // Commit any and all changes to the trie that are in the cache, then update the state root accordingly. commit(); cnote << "stateRoot:" << m_state.root(); // cnote << m_state; // cnote << *this; m_currentBlock.stateRoot = m_state.root(); m_currentBlock.parentHash = m_previousBlock.hash; }
LastHashes State::getLastHashes(BlockChain const& _bc, unsigned _n) const { LastHashes ret; ret.resize(256); if (c_protocolVersion > 49) { ret[0] = _bc.numberHash(_n); for (unsigned i = 1; i < 256; ++i) ret[i] = ret[i - 1] ? _bc.details(ret[i - 1]).parent : h256(); } return ret; }
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) { // Check if we already know this block. h256 h = BlockInfo::headerHash(_block); cblockq << "Queuing block" << h.abridged() << "for import..."; UpgradableGuard l(m_lock); if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h)) { // Already know about this one. cblockq << "Already known."; return ImportResult::AlreadyKnown; } // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; #if ETH_CATCH try #endif { bi.populate(_block); bi.verifyInternals(_block); } #if ETH_CATCH catch (Exception const& _e) { cwarn << "Ignoring malformed block: " << diagnostic_information(_e); return false; return ImportResult::Malformed; } #endif // Check block doesn't already exist first! if (_bc.details(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; } UpgradeGuard ul(l); // Check it's not in the future if (bi.timestamp > (u256)time(0)) { m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes())); cblockq << "OK - queued for future."; return ImportResult::FutureTime; } else { // We now know it. if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged(); m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); return ImportResult::UnknownParent; } else { // If valid, append to blocks. cblockq << "OK - ready for chain insertion."; m_ready.push_back(_block.toBytes()); m_readySet.insert(h); noteReadyWithoutWriteGuard(h); return ImportResult::Success; } } }
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; }