PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& _h, ImportRequirements::value _ir) { PopulationStatistics ret { 0.0, 0.0 }; if (!_bc.isKnown(_h)) { // Might be worth throwing here. cwarn << "Invalid block given for state population: " << _h; return ret; } auto b = _bc.block(_h); BlockInfo bi(b); if (bi.number) { // Non-genesis: // 1. Start at parent's end state (state root). BlockInfo bip; bip.populate(_bc.block(bi.parentHash)); sync(_bc, bi.parentHash, bip, _ir); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; auto vb = BlockChain::verifyBlock(b); ret.verify = t.elapsed(); t.restart(); enact(vb, _bc, _ir); ret.enact = t.elapsed(); } else { // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); sync(_bc, _h, bi, _ir); } return ret; }
PopulationStatistics Block::populateFromChain(BlockChain const& _bc, h256 const& _h, ImportRequirements::value _ir) { PopulationStatistics ret { 0.0, 0.0 }; if (!_bc.isKnown(_h)) { // Might be worth throwing here. cwarn << "Invalid block given for state population: " << _h; BOOST_THROW_EXCEPTION(BlockNotFound() << errinfo_target(_h)); } auto b = _bc.block(_h); BlockInfo bi(b); if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). BlockInfo bip(_bc.block(bi.parentHash())); sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. m_beneficiary = bi.beneficiary(); Timer t; auto vb = _bc.verifyBlock(&b, function<void(Exception&)>(), _ir | ImportRequirements::TransactionBasic); ret.verify = t.elapsed(); t.restart(); enact(vb, _bc); ret.enact = t.elapsed(); } else { // Genesis required: // We know there are no transactions, so just populate directly. m_state = State(m_state.db(), BaseState::Empty); // TODO: try with PreExisting. sync(_bc, _h, bi); } 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; } } }
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. h256 h = BlockInfo::headerHash(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; UpgradableGuard l(m_lock); if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h)) { // Already know about this one. clog(BlockQueueTraceChannel) << "Already known."; return ImportResult::AlreadyKnown; } // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; try { // TODO: quick verify bi.populate(_block); bi.verifyInternals(_block); } catch (Exception const& _e) { cwarn << "Ignoring malformed block: " << diagnostic_information(_e); return ImportResult::Malformed; } clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! if (_bc.isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; } UpgradeGuard ul(l); DEV_INVARIANT_CHECK; // Check it's not in the future (void)_isOurs; if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) { m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); char buf[24]; time_t bit = (unsigned)bi.timestamp; if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. if (m_knownBad.count(bi.parentHash)) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } else 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. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); m_difficulty += bi.difficulty; m_unknownCount++; return ImportResult::UnknownParent; } else { // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); m_difficulty += bi.difficulty; m_knownCount++; noteReady_WITH_LOCK(h); return ImportResult::Success; } } }