@@ -772,14 +772,15 @@ class PeerManagerImpl final : public PeerManager
772772 */
773773 void ProcessHeadersMessage (CNode& pfrom, Peer& peer,
774774 std::vector<CBlockHeader>&& headers,
775+ std::vector<uint256>&& hashes,
775776 bool via_compact_block, bool uses_compressed)
776777 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
777778 [[nodiscard]] MessageProcessingResult ProcessPlatformBanMessage (NodeId node, std::string_view msg_type, CDataStream& vRecv)
778779 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
779780
780781 /* * Various helpers for headers processing, invoked by ProcessHeadersMessage() */
781782 /* * Return true if headers are continuous and have valid proof-of-work (DoS points assigned on failure) */
782- bool CheckHeadersPoW (const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams, CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
783+ bool CheckHeadersPoW (const std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, const Consensus::Params& consensusParams, CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
783784 /* * Calculate an anti-DoS work threshold for headers chains */
784785 arith_uint256 GetAntiDoSWorkThreshold ();
785786 /* * Deal with state tracking and headers sync for peers that send the
@@ -788,7 +789,7 @@ class PeerManagerImpl final : public PeerManager
788789 void HandleFewUnconnectingHeaders (CNode& pfrom, Peer& peer, const std::vector<CBlockHeader>& headers)
789790 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex);
790791 /* * Return true if the headers connect to each other, false otherwise */
791- bool CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers) const ;
792+ bool CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes ) const ;
792793 /* * Try to continue a low-work headers sync that has already begun.
793794 * Assumes the caller has already verified the headers connect, and has
794795 * checked that each header satisfies the proof-of-work target included in
@@ -808,7 +809,7 @@ class PeerManagerImpl final : public PeerManager
808809 * acceptance by the caller).
809810 */
810811 bool IsContinuationOfLowWorkHeadersSync (Peer& peer, CNode& pfrom,
811- std::vector<CBlockHeader>& headers, bool uses_compressed)
812+ std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, bool uses_compressed)
812813 EXCLUSIVE_LOCKS_REQUIRED(peer.m_headers_sync_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
813814 /* * Check work on a headers chain to be processed, and if insufficient,
814815 * initiate our anti-DoS headers sync mechanism.
@@ -823,7 +824,7 @@ class PeerManagerImpl final : public PeerManager
823824 */
824825 bool TryLowWorkHeadersSync (Peer& peer, CNode& pfrom,
825826 const CBlockIndex* chain_start_header,
826- std::vector<CBlockHeader>& headers, bool uses_compressed)
827+ std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, bool uses_compressed)
827828 EXCLUSIVE_LOCKS_REQUIRED(!peer.m_headers_sync_mutex, !m_peer_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
828829
829830 /* * Return true if the given header is an ancestor of
@@ -3196,16 +3197,16 @@ void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, const CBlock& block, c
31963197 m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::BLOCKTXN , resp));
31973198}
31983199
3199- bool PeerManagerImpl::CheckHeadersPoW (const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams, CNode& pfrom)
3200+ bool PeerManagerImpl::CheckHeadersPoW (const std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, const Consensus::Params& consensusParams, CNode& pfrom)
32003201{
32013202 // Do these headers have proof-of-work matching what's claimed?
3202- if (!HasValidProofOfWork (headers, consensusParams)) {
3203+ if (!HasValidProofOfWork (headers, hashes, consensusParams)) {
32033204 Misbehaving (pfrom.GetId (), 100 , " header with invalid proof of work" );
32043205 return false ;
32053206 }
32063207
32073208 // Are these headers connected to each other?
3208- if (!CheckHeadersAreContinuous (headers)) {
3209+ if (!CheckHeadersAreContinuous (headers, hashes )) {
32093210 Misbehaving (pfrom.GetId (), 20 , " non-continuous headers sequence" );
32103211 return false ;
32113212 }
@@ -3266,22 +3267,21 @@ void PeerManagerImpl::HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer,
32663267 }
32673268}
32683269
3269- bool PeerManagerImpl::CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers) const
3270+ bool PeerManagerImpl::CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes ) const
32703271{
3271- uint256 hashLastBlock ;
3272- for (const CBlockHeader& header : headers) {
3273- if (!hashLastBlock. IsNull () && header. hashPrevBlock != hashLastBlock ) {
3272+ assert (headers. size () == hashes. size ()) ;
3273+ for (size_t i = 1 ; i < headers. size (); ++i ) {
3274+ if (headers[i]. hashPrevBlock != hashes[i - 1 ] ) {
32743275 return false ;
32753276 }
3276- hashLastBlock = header.GetHash ();
32773277 }
32783278 return true ;
32793279}
32803280
3281- bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync (Peer& peer, CNode& pfrom, std::vector<CBlockHeader>& headers, bool uses_compressed)
3281+ bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync (Peer& peer, CNode& pfrom, std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, bool uses_compressed)
32823282{
32833283 if (peer.m_headers_sync ) {
3284- auto result = peer.m_headers_sync ->ProcessNextHeaders (headers, headers.size () == GetHeadersLimit (pfrom, uses_compressed));
3284+ auto result = peer.m_headers_sync ->ProcessNextHeaders (headers, hashes, headers.size () == GetHeadersLimit (pfrom, uses_compressed));
32853285 if (result.request_more ) {
32863286 auto locator = peer.m_headers_sync ->NextHeadersRequestLocator ();
32873287 // If we were instructed to ask for a locator, it should not be empty.
@@ -3365,7 +3365,7 @@ bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(Peer& peer, CNode& pfro
33653365 return false ;
33663366}
33673367
3368- bool PeerManagerImpl::TryLowWorkHeadersSync (Peer& peer, CNode& pfrom, const CBlockIndex* chain_start_header, std::vector<CBlockHeader>& headers, bool uses_compressed)
3368+ bool PeerManagerImpl::TryLowWorkHeadersSync (Peer& peer, CNode& pfrom, const CBlockIndex* chain_start_header, std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, bool uses_compressed)
33693369{
33703370 // Calculate the total work on this chain.
33713371 arith_uint256 total_work = chain_start_header->nChainWork + CalculateHeadersWork (headers);
@@ -3397,7 +3397,7 @@ bool PeerManagerImpl::TryLowWorkHeadersSync(Peer& peer, CNode& pfrom, const CBlo
33973397 // Now a HeadersSyncState object for tracking this synchronization
33983398 // is created, process the headers using it as normal. Failures are
33993399 // handled inside of IsContinuationOfLowWorkHeadersSync.
3400- (void )IsContinuationOfLowWorkHeadersSync (peer, pfrom, headers, uses_compressed);
3400+ (void )IsContinuationOfLowWorkHeadersSync (peer, pfrom, headers, hashes, uses_compressed);
34013401 } else {
34023402 LogPrint (BCLog::NET , " Ignoring low-work chain (height=%u) from peer=%d\n " , chain_start_header->nHeight + headers.size (), pfrom.GetId ());
34033403 }
@@ -3568,8 +3568,10 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom,
35683568
35693569void PeerManagerImpl::ProcessHeadersMessage (CNode& pfrom, Peer& peer,
35703570 std::vector<CBlockHeader>&& headers,
3571+ std::vector<uint256>&& hashes,
35713572 bool via_compact_block, bool uses_compressed)
35723573{
3574+ Assume (headers.size () == hashes.size ());
35733575 size_t nCount = headers.size ();
35743576
35753577 if (nCount == 0 ) {
@@ -3590,7 +3592,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
35903592 // We'll rely on headers having valid proof-of-work further down, as an
35913593 // anti-DoS criteria (note: this check is required before passing any
35923594 // headers into HeadersSyncState).
3593- if (!CheckHeadersPoW (headers, m_chainparams.GetConsensus (), pfrom)) {
3595+ if (!CheckHeadersPoW (headers, hashes, m_chainparams.GetConsensus (), pfrom)) {
35943596 // Misbehaving() calls are handled within CheckHeadersPoW(), so we can
35953597 // just return. (Note that even if a header is announced via compact
35963598 // block, the header itself should be valid, so this type of error can
@@ -3612,7 +3614,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
36123614 {
36133615 LOCK (peer.m_headers_sync_mutex );
36143616
3615- already_validated_work = IsContinuationOfLowWorkHeadersSync (peer, pfrom, headers, uses_compressed);
3617+ already_validated_work = IsContinuationOfLowWorkHeadersSync (peer, pfrom, headers, hashes, uses_compressed);
36163618
36173619 // The headers we passed in may have been:
36183620 // - untouched, perhaps if no headers-sync was in progress, or some
@@ -3654,7 +3656,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
36543656 const CBlockIndex *last_received_header{nullptr };
36553657 {
36563658 LOCK (cs_main);
3657- last_received_header = m_chainman.m_blockman .LookupBlockIndex (headers .back (). GetHash ());
3659+ last_received_header = m_chainman.m_blockman .LookupBlockIndex (hashes .back ());
36583660 if (IsAncestorOfBestHeaderOrTip (last_received_header)) {
36593661 already_validated_work = true ;
36603662 }
@@ -3671,7 +3673,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
36713673 // Do anti-DoS checks to determine if we should process or store for later
36723674 // processing.
36733675 if (!already_validated_work && TryLowWorkHeadersSync (peer, pfrom,
3674- chain_start_header, headers, uses_compressed)) {
3676+ chain_start_header, headers, hashes, uses_compressed)) {
36753677 // If we successfully started a low-work headers sync, then there
36763678 // should be no headers to process any further.
36773679 Assume (headers.empty ());
@@ -5364,7 +5366,7 @@ void PeerManagerImpl::ProcessMessage(
53645366 // the peer if the header turns out to be for an invalid block.
53655367 // Note that if a peer tries to build on an invalid chain, that
53665368 // will be detected and the peer will be disconnected/discouraged.
5367- return ProcessHeadersMessage (pfrom, *peer, {cmpctblock.header }, /* via_compact_block=*/ true , UsesCompressedHeaders (*peer));
5369+ return ProcessHeadersMessage (pfrom, *peer, {cmpctblock.header }, {cmpctblock. header . GetHash ()}, /* via_compact_block=*/ true , UsesCompressedHeaders (*peer));
53685370 }
53695371
53705372 if (fBlockReconstructed ) {
@@ -5507,7 +5509,14 @@ void PeerManagerImpl::ProcessMessage(
55075509 }
55085510 }
55095511
5510- ProcessHeadersMessage (pfrom, *peer, std::move (headers), /* via_compact_block=*/ false , msg_type == NetMsgType::HEADERS2 );
5512+ // Pre-compute each header's hash once so downstream PRESYNC/REDOWNLOAD/
5513+ // CheckHeadersPoW/CheckHeadersAreContinuous reuse it instead of
5514+ // recomputing X11 multiple times per header.
5515+ std::vector<uint256> hashes;
5516+ hashes.reserve (headers.size ());
5517+ for (const CBlockHeader& h : headers) hashes.push_back (h.GetHash ());
5518+
5519+ ProcessHeadersMessage (pfrom, *peer, std::move (headers), std::move (hashes), /* via_compact_block=*/ false , msg_type == NetMsgType::HEADERS2 );
55115520
55125521 // Check if the headers presync progress needs to be reported to validation.
55135522 // This needs to be done without holding the m_headers_presync_mutex lock.
0 commit comments