@@ -571,6 +571,8 @@ class PeerManagerImpl final : public PeerManager
571
571
void FetchMoreHeaders (CNode& pfrom, const CBlockIndex *pindexLast, const Peer& peer);
572
572
/* * Potentially fetch blocks from this peer upon receipt of new headers tip */
573
573
void HeadersDirectFetchBlocks (CNode& pfrom, const CBlockIndex* pindexLast);
574
+ /* * Update peer state based on received headers message */
575
+ void UpdatePeerStateForReceivedHeaders (CNode& pfrom, const CBlockIndex *pindexLast, bool received_new_header, bool may_have_more_headers);
574
576
575
577
void SendBlockTransactions (CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req);
576
578
@@ -2345,6 +2347,67 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const CBlockIndex*
2345
2347
}
2346
2348
}
2347
2349
2350
+ /* *
2351
+ * Given receipt of headers from a peer ending in pindexLast, along with
2352
+ * whether that header was new and whether the headers message was full,
2353
+ * update the state we keep for the peer.
2354
+ */
2355
+ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders (CNode& pfrom,
2356
+ const CBlockIndex *pindexLast, bool received_new_header, bool may_have_more_headers)
2357
+ {
2358
+ LOCK (cs_main);
2359
+ CNodeState *nodestate = State (pfrom.GetId ());
2360
+ if (nodestate->nUnconnectingHeaders > 0 ) {
2361
+ LogPrint (BCLog::NET, " peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n " , pfrom.GetId (), nodestate->nUnconnectingHeaders );
2362
+ }
2363
+ nodestate->nUnconnectingHeaders = 0 ;
2364
+
2365
+ assert (pindexLast);
2366
+ UpdateBlockAvailability (pfrom.GetId (), pindexLast->GetBlockHash ());
2367
+
2368
+ // From here, pindexBestKnownBlock should be guaranteed to be non-null,
2369
+ // because it is set in UpdateBlockAvailability. Some nullptr checks
2370
+ // are still present, however, as belt-and-suspenders.
2371
+
2372
+ if (received_new_header && pindexLast->nChainWork > m_chainman.ActiveChain ().Tip ()->nChainWork ) {
2373
+ nodestate->m_last_block_announcement = GetTime ();
2374
+ }
2375
+
2376
+ // If we're in IBD, we want outbound peers that will serve us a useful
2377
+ // chain. Disconnect peers that are on chains with insufficient work.
2378
+ if (m_chainman.ActiveChainstate ().IsInitialBlockDownload () && !may_have_more_headers) {
2379
+ // If the peer has no more headers to give us, then we know we have
2380
+ // their tip.
2381
+ if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock ->nChainWork < nMinimumChainWork) {
2382
+ // This peer has too little work on their headers chain to help
2383
+ // us sync -- disconnect if it is an outbound disconnection
2384
+ // candidate.
2385
+ // Note: We compare their tip to nMinimumChainWork (rather than
2386
+ // m_chainman.ActiveChain().Tip()) because we won't start block download
2387
+ // until we have a headers chain that has at least
2388
+ // nMinimumChainWork, even if a peer has a chain past our tip,
2389
+ // as an anti-DoS measure.
2390
+ if (pfrom.IsOutboundOrBlockRelayConn ()) {
2391
+ LogPrintf (" Disconnecting outbound peer %d -- headers chain has insufficient work\n " , pfrom.GetId ());
2392
+ pfrom.fDisconnect = true ;
2393
+ }
2394
+ }
2395
+ }
2396
+
2397
+ // If this is an outbound full-relay peer, check to see if we should protect
2398
+ // it from the bad/lagging chain logic.
2399
+ // Note that outbound block-relay peers are excluded from this protection, and
2400
+ // thus always subject to eviction under the bad/lagging chain logic.
2401
+ // See ChainSyncTimeoutState.
2402
+ if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn () && nodestate->pindexBestKnownBlock != nullptr ) {
2403
+ if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock ->nChainWork >= m_chainman.ActiveChain ().Tip ()->nChainWork && !nodestate->m_chain_sync .m_protect ) {
2404
+ LogPrint (BCLog::NET, " Protecting outbound peer=%d from eviction\n " , pfrom.GetId ());
2405
+ nodestate->m_chain_sync .m_protect = true ;
2406
+ ++m_outbound_peers_with_protect_from_disconnect;
2407
+ }
2408
+ }
2409
+ }
2410
+
2348
2411
void PeerManagerImpl::ProcessHeadersMessage (CNode& pfrom, Peer& peer,
2349
2412
const std::vector<CBlockHeader>& headers,
2350
2413
bool via_compact_block)
@@ -2405,59 +2468,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
2405
2468
FetchMoreHeaders (pfrom, pindexLast, peer);
2406
2469
}
2407
2470
2408
- {
2409
- LOCK (cs_main);
2410
- CNodeState *nodestate = State (pfrom.GetId ());
2411
- if (nodestate->nUnconnectingHeaders > 0 ) {
2412
- LogPrint (BCLog::NET, " peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n " , pfrom.GetId (), nodestate->nUnconnectingHeaders );
2413
- }
2414
- nodestate->nUnconnectingHeaders = 0 ;
2415
-
2416
- assert (pindexLast);
2417
- UpdateBlockAvailability (pfrom.GetId (), pindexLast->GetBlockHash ());
2418
-
2419
- // From here, pindexBestKnownBlock should be guaranteed to be non-null,
2420
- // because it is set in UpdateBlockAvailability. Some nullptr checks
2421
- // are still present, however, as belt-and-suspenders.
2422
-
2423
- if (received_new_header && pindexLast->nChainWork > m_chainman.ActiveChain ().Tip ()->nChainWork ) {
2424
- nodestate->m_last_block_announcement = GetTime ();
2425
- }
2426
-
2427
- // If we're in IBD, we want outbound peers that will serve us a useful
2428
- // chain. Disconnect peers that are on chains with insufficient work.
2429
- if (m_chainman.ActiveChainstate ().IsInitialBlockDownload () && nCount != MAX_HEADERS_RESULTS) {
2430
- // When nCount < MAX_HEADERS_RESULTS, we know we have no more
2431
- // headers to fetch from this peer.
2432
- if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock ->nChainWork < nMinimumChainWork) {
2433
- // This peer has too little work on their headers chain to help
2434
- // us sync -- disconnect if it is an outbound disconnection
2435
- // candidate.
2436
- // Note: We compare their tip to nMinimumChainWork (rather than
2437
- // m_chainman.ActiveChain().Tip()) because we won't start block download
2438
- // until we have a headers chain that has at least
2439
- // nMinimumChainWork, even if a peer has a chain past our tip,
2440
- // as an anti-DoS measure.
2441
- if (pfrom.IsOutboundOrBlockRelayConn ()) {
2442
- LogPrintf (" Disconnecting outbound peer %d -- headers chain has insufficient work\n " , pfrom.GetId ());
2443
- pfrom.fDisconnect = true ;
2444
- }
2445
- }
2446
- }
2447
-
2448
- // If this is an outbound full-relay peer, check to see if we should protect
2449
- // it from the bad/lagging chain logic.
2450
- // Note that outbound block-relay peers are excluded from this protection, and
2451
- // thus always subject to eviction under the bad/lagging chain logic.
2452
- // See ChainSyncTimeoutState.
2453
- if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn () && nodestate->pindexBestKnownBlock != nullptr ) {
2454
- if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock ->nChainWork >= m_chainman.ActiveChain ().Tip ()->nChainWork && !nodestate->m_chain_sync .m_protect ) {
2455
- LogPrint (BCLog::NET, " Protecting outbound peer=%d from eviction\n " , pfrom.GetId ());
2456
- nodestate->m_chain_sync .m_protect = true ;
2457
- ++m_outbound_peers_with_protect_from_disconnect;
2458
- }
2459
- }
2460
- }
2471
+ UpdatePeerStateForReceivedHeaders (pfrom, pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS);
2461
2472
2462
2473
// Consider immediately downloading blocks.
2463
2474
HeadersDirectFetchBlocks (pfrom, pindexLast);
0 commit comments