void PV60Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; if (!isSyncing(_peer)) { clog(NetMessageSummary) << "Ignoring hashes since not syncing"; return; } if (_peer->m_syncHash != (m_syncingLastReceivedHash ? m_syncingLastReceivedHash : m_syncingLatestHash)) { clog(NetMessageSummary) << "Ignoring unexpected hashes"; return; } if (_hashes.size() == 0) { transition(_peer, SyncState::Blocks); return; } unsigned knowns = 0; unsigned unknowns = 0; for (unsigned i = 0; i < _hashes.size(); ++i) { auto h = _hashes[i]; auto status = host().bq().blockStatus(h); if (status == QueueStatus::Importing || status == QueueStatus::Ready || host().chain().isKnown(h)) { clog(NetMessageSummary) << "block hash ready:" << h << ". Start blocks download..."; assert (isSyncing(_peer)); transition(_peer, SyncState::Blocks); return; } else if (status == QueueStatus::Bad) { cwarn << "block hash bad!" << h << ". Bailing..."; _peer->disable("Bad blocks"); restartSync(); return; } else if (status == QueueStatus::Unknown) { unknowns++; m_syncingNeededBlocks.push_back(h); } else knowns++; m_syncingLastReceivedHash = h; } clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLastReceivedHash; if (m_syncingNeededBlocks.size() > _peer->m_expectedHashes) { _peer->disable("Too many hashes"); restartSync(); return; } // run through - ask for more. transition(_peer, SyncState::Hashes); }
void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP const& _r) { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); logNewBlock(h); break; case ImportResult::FutureTimeKnown: //TODO: Rating dependent on how far in future it is. break; case ImportResult::Malformed: case ImportResult::BadChain: logNewBlock(h); _peer->disable("Malformed block received."); return; case ImportResult::AlreadyInChain: case ImportResult::AlreadyKnown: break; case ImportResult::FutureTimeUnknown: case ImportResult::UnknownParent: { logNewBlock(h); u256 totalDifficulty = _r[1].toInt<u256>(); if (totalDifficulty > _peer->m_totalDifficulty) { clog(NetMessageDetail) << "Received block with no known parent. Peer needs syncing..."; resetSyncFor(_peer, h, totalDifficulty); } break; } default:; } DEV_GUARDED(_peer->x_knownBlocks) _peer->m_knownBlocks.insert(h); } }
void SchedulingAgent::disableControllerService(std::shared_ptr<core::controller::ControllerServiceNode> &serviceNode) { // reference the disable function from serviceNode std::function<bool()> f_ex = [serviceNode] { return serviceNode->disable(); }; // create a functor that will be submitted to the thread pool. utils::Worker<bool> functor(f_ex); // move the functor into the thread pool. While a future is returned // we aren't terribly concerned with the result. std::future<bool> future; component_lifecycle_thread_pool_.execute(std::move(functor), future); }
void BlockChainSync::onPeerStatus(std::shared_ptr<EthereumPeer> _peer) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; std::shared_ptr<Session> session = _peer->session(); if (!session) return; // Expired if (_peer->m_genesisHash != host().chain().genesisHash()) _peer->disable("Invalid genesis hash"); else if (_peer->m_protocolVersion != host().protocolVersion() && _peer->m_protocolVersion != EthereumHost::c_oldProtocolVersion) _peer->disable("Invalid protocol version."); else if (_peer->m_networkId != host().networkId()) _peer->disable("Invalid network identifier."); else if (session->info().clientVersion.find("/v0.7.0/") != string::npos) _peer->disable("Blacklisted client version."); else if (host().isBanned(session->id())) _peer->disable("Peer banned for previous bad behaviour."); else { unsigned hashes = estimatedHashes(); _peer->m_expectedHashes = hashes; onNewPeer(_peer); } }
void BlockChainSync::onPeerStatus(std::shared_ptr<ElementremPeer> _peer) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; std::shared_ptr<Session> session = _peer->session(); if (!session) return; // Expired if (_peer->m_genesisHash != host().chain().genesisHash()) _peer->disable("Invalid genesis hash"); else if (_peer->m_protocolVersion != host().protocolVersion() && _peer->m_protocolVersion != ElementremHost::c_oldProtocolVersion) _peer->disable("Invalid protocol version."); else if (_peer->m_networkId != host().networkId()) _peer->disable("Invalid network identifier."); else if (session->info().clientVersion.find("/v0.7.0/") != string::npos) _peer->disable("Blacklisted client version."); else if (host().isBanned(session->id())) _peer->disable("Peer banned for previous bad behaviour."); else if (_peer->m_asking != Asking::State && _peer->m_asking != Asking::Nothing) _peer->disable("Peer banned for unexpected status message."); else syncPeer(_peer, false); }
void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); if (m_syncingBlockNumber == 0 || (_peer == m_syncer.lock() && _peer->m_protocolVersion != host().protocolVersion())) { // Syncing in pv60 mode PV60Sync::onPeerHashes(_peer, _hashes); return; } if (_hashes.size() == 0) { if (isSyncing(_peer) && _peer->m_syncHashNumber == m_syncingBlockNumber) { // End of hash chain, add last chunk to download m_readyChainMap.insert(make_pair(m_syncingBlockNumber, SubChain{ h256s{ _peer->m_latestHash }, _peer->m_latestHash })); m_knownHashes.insert(_peer->m_latestHash); m_hashScanComplete = true; _peer->m_syncHashNumber = 0; requestSubchain(_peer); } else { auto syncPeer = m_chainSyncPeers.find(_peer); if (syncPeer == m_chainSyncPeers.end()) clog(NetMessageDetail) << "Hashes response from unexpected peer"; else { // Peer does not have request hashes, move back from downloading to ready unsigned number = syncPeer->second; m_chainSyncPeers.erase(_peer); m_readyChainMap[number] = move(m_downloadingChainMap.at(number)); m_downloadingChainMap.erase(number); resetNeedsSyncing(_peer); requestSubchains(); } } return; } if (isSyncing(_peer) && _peer->m_syncHashNumber == m_syncingBlockNumber) { // Got new subchain marker if (_hashes.size() != 1) { clog(NetWarn) << "Peer sent too many hashes"; _peer->disable("Too many hashes"); restartSync(); return; } m_knownHashes.insert(_hashes[0]); m_readyChainMap.insert(make_pair(m_syncingBlockNumber, SubChain{ h256s{ _hashes[0] }, _hashes[0] })); if ((m_readyChainMap.size() + m_downloadingChainMap.size() + m_completeChainMap.size()) * c_hashSubchainSize > _peer->m_expectedHashes) { _peer->disable("Too many hashes from lead peer"); restartSync(); return; } transition(_peer, SyncState::Hashes); requestSubchains(); } else { auto syncPeer = m_chainSyncPeers.find(_peer); unsigned number = 0; if (syncPeer == m_chainSyncPeers.end()) { //check downlading peers for (auto const& downloader: m_downloadingChainMap) if (downloader.second.lastHash == _peer->m_syncHash) { number = downloader.first; break; } } else number = syncPeer->second; if (number == 0) { clog(NetAllDetail) << "Hashes response from unexpected/expired peer"; return; } auto downloadingPeer = m_downloadingChainMap.find(number); if (downloadingPeer == m_downloadingChainMap.end() || downloadingPeer->second.lastHash != _peer->m_syncHash) { // Too late, other peer has already downloaded our hashes m_chainSyncPeers.erase(_peer); requestSubchain(_peer); return; } SubChain& subChain = downloadingPeer->second; unsigned knowns = 0; unsigned unknowns = 0; for (unsigned i = 0; i < _hashes.size(); ++i) { auto h = _hashes[i]; auto status = host().bq().blockStatus(h); if (status == QueueStatus::Importing || status == QueueStatus::Ready || host().chain().isKnown(h) || !!m_knownHashes.count(h)) { clog(NetMessageSummary) << "Subchain download complete"; m_chainSyncPeers.erase(_peer); completeSubchain(_peer, number); return; } else if (status == QueueStatus::Bad) { cwarn << "block hash bad!" << h << ". Bailing..."; _peer->disable("Bad hashes"); if (isSyncing(_peer)) restartSync(); else { //try with other peer m_readyChainMap[number] = move(m_downloadingChainMap.at(number)); m_downloadingChainMap.erase(number); m_chainSyncPeers.erase(_peer); } return; } else if (status == QueueStatus::Unknown) { unknowns++; subChain.hashes.push_back(h); } else knowns++; subChain.lastHash = h; } clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << subChain.lastHash; if (subChain.hashes.size() > c_hashSubchainSize) { _peer->disable("Too many subchain hashes"); restartSync(); return; } requestSubchain(_peer); } DEV_INVARIANT_CHECK; }
void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const& _r) { RecursiveGuard l(x_sync); unsigned itemCount = _r.itemCount(); clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks && m_state != SyncState::Waiting) { clog(NetMessageSummary) << "Ignoring unexpected blocks"; return; } if (m_state == SyncState::Waiting) { clog(NetAllDetail) << "Ignored blocks while waiting"; return; } if (itemCount == 0) { // Got to this peer's latest block - just give up. peerDoneBlocks(_peer); if (downloadMan().isComplete()) completeSync(); return; } unsigned success = 0; unsigned future = 0; unsigned unknown = 0; unsigned got = 0; unsigned repeated = 0; u256 maxUnknownNumber = 0; h256 maxUnknown; for (unsigned i = 0; i < itemCount; ++i) { auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; logNewBlock(h); break; case ImportResult::Malformed: case ImportResult::BadChain: logNewBlock(h); _peer->disable("Malformed block received."); restartSync(); return; case ImportResult::FutureTimeKnown: logNewBlock(h); future++; break; case ImportResult::AlreadyInChain: case ImportResult::AlreadyKnown: got++; break; case ImportResult::FutureTimeUnknown: future++; //Fall through case ImportResult::UnknownParent: { unknown++; logNewBlock(h); if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); if (bi.number() > maxUnknownNumber) { maxUnknownNumber = bi.number(); maxUnknown = h; } } break; } default:; } } else { _peer->addRating(0); // -1? repeated++; } } clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; if (host().bq().unknownFull()) { clog(NetWarn) << "Too many unknown blocks, restarting sync"; restartSync(); return; } if (m_state == SyncState::NewBlocks && unknown > 0) { completeSync(); resetSyncFor(_peer, maxUnknown, std::numeric_limits<u256>::max()); //TODO: proper total difficuty } if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) { if (downloadMan().isComplete()) completeSync(); else requestBlocks(_peer); // Some of the blocks might have been downloaded by helping peers, proceed anyway } DEV_INVARIANT_CHECK; }
void NetworkIntegrationTests::disconnect() { if (m_avsConnectionManager) { m_avsConnectionManager->disable(); m_context->waitForDisconnected(); } }
void BlockChainSync::onPeerNewBlock(std::shared_ptr<ElementremPeer> _peer, RLP const& _r) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; if (_r.itemCount() != 2) { _peer->disable("NewBlock without 2 data fields."); return; } BlockHeader info(_r[0][0].data(), HeaderData); auto h = info.hash(); DEV_GUARDED(_peer->x_knownBlocks) _peer->m_knownBlocks.insert(h); unsigned blockNumber = static_cast<unsigned>(info.number()); if (blockNumber > (m_lastImportedBlock + 1)) { clog(NetAllDetail) << "Received unknown new block"; syncPeer(_peer, true); return; } switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); logNewBlock(h); if (blockNumber > m_lastImportedBlock) { m_lastImportedBlock = max(m_lastImportedBlock, blockNumber); m_lastImportedBlockHash = h; } m_highestBlock = max(m_lastImportedBlock, m_highestBlock); m_downloadingBodies.erase(blockNumber); m_downloadingHeaders.erase(blockNumber); removeItem(m_headers, blockNumber); removeItem(m_bodies, blockNumber); if (m_headers.empty()) { assert(m_bodies.empty()); completeSync(); } break; case ImportResult::FutureTimeKnown: //TODO: Rating dependent on how far in future it is. break; case ImportResult::Malformed: case ImportResult::BadChain: logNewBlock(h); _peer->disable("Malformed block received."); return; case ImportResult::AlreadyInChain: case ImportResult::AlreadyKnown: break; case ImportResult::FutureTimeUnknown: case ImportResult::UnknownParent: { _peer->m_unknownNewBlocks++; if (_peer->m_unknownNewBlocks > c_maxPeerUknownNewBlocks) { _peer->disable("Too many uknown new blocks"); restartSync(); } logNewBlock(h); u256 totalDifficulty = _r[1].toInt<u256>(); if (totalDifficulty > _peer->m_totalDifficulty) { clog(NetMessageDetail) << "Received block with no known parent. Peer needs syncing..."; syncPeer(_peer, true); } break; } default:; } }