@@ -771,14 +771,15 @@ class PeerManagerImpl final : public PeerManager
771771 */
772772 void ProcessHeadersMessage (CNode& pfrom, Peer& peer,
773773 std::vector<CBlockHeader>&& headers,
774+ std::vector<uint256>&& hashes,
774775 bool via_compact_block, bool uses_compressed)
775776 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
776777 [[nodiscard]] MessageProcessingResult ProcessPlatformBanMessage (NodeId node, std::string_view msg_type, CDataStream& vRecv)
777778 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
778779
779780 /* * Various helpers for headers processing, invoked by ProcessHeadersMessage() */
780781 /* * Return true if headers are continuous and have valid proof-of-work (DoS points assigned on failure) */
781- bool CheckHeadersPoW (const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams, CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
782+ bool CheckHeadersPoW (const std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, const Consensus::Params& consensusParams, CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
782783 /* * Calculate an anti-DoS work threshold for headers chains */
783784 arith_uint256 GetAntiDoSWorkThreshold ();
784785 /* * Deal with state tracking and headers sync for peers that send the
@@ -787,7 +788,7 @@ class PeerManagerImpl final : public PeerManager
787788 void HandleFewUnconnectingHeaders (CNode& pfrom, Peer& peer, const std::vector<CBlockHeader>& headers)
788789 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex);
789790 /* * Return true if the headers connect to each other, false otherwise */
790- bool CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers) const ;
791+ bool CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes ) const ;
791792 /* * Try to continue a low-work headers sync that has already begun.
792793 * Assumes the caller has already verified the headers connect, and has
793794 * checked that each header satisfies the proof-of-work target included in
@@ -807,7 +808,7 @@ class PeerManagerImpl final : public PeerManager
807808 * acceptance by the caller).
808809 */
809810 bool IsContinuationOfLowWorkHeadersSync (Peer& peer, CNode& pfrom,
810- std::vector<CBlockHeader>& headers, bool uses_compressed)
811+ std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, bool uses_compressed)
811812 EXCLUSIVE_LOCKS_REQUIRED(peer.m_headers_sync_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
812813 /* * Check work on a headers chain to be processed, and if insufficient,
813814 * initiate our anti-DoS headers sync mechanism.
@@ -822,7 +823,7 @@ class PeerManagerImpl final : public PeerManager
822823 */
823824 bool TryLowWorkHeadersSync (Peer& peer, CNode& pfrom,
824825 const CBlockIndex* chain_start_header,
825- std::vector<CBlockHeader>& headers, bool uses_compressed)
826+ std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, bool uses_compressed)
826827 EXCLUSIVE_LOCKS_REQUIRED(!peer.m_headers_sync_mutex, !m_peer_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
827828
828829 /* * Return true if the given header is an ancestor of
@@ -3162,16 +3163,16 @@ void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, const CBlock& block, c
31623163 m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::BLOCKTXN , resp));
31633164}
31643165
3165- bool PeerManagerImpl::CheckHeadersPoW (const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams, CNode& pfrom)
3166+ bool PeerManagerImpl::CheckHeadersPoW (const std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, const Consensus::Params& consensusParams, CNode& pfrom)
31663167{
31673168 // Do these headers have proof-of-work matching what's claimed?
3168- if (!HasValidProofOfWork (headers, consensusParams)) {
3169+ if (!HasValidProofOfWork (headers, hashes, consensusParams)) {
31693170 Misbehaving (pfrom.GetId (), 100 , " header with invalid proof of work" );
31703171 return false ;
31713172 }
31723173
31733174 // Are these headers connected to each other?
3174- if (!CheckHeadersAreContinuous (headers)) {
3175+ if (!CheckHeadersAreContinuous (headers, hashes )) {
31753176 Misbehaving (pfrom.GetId (), 20 , " non-continuous headers sequence" );
31763177 return false ;
31773178 }
@@ -3232,22 +3233,21 @@ void PeerManagerImpl::HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer,
32323233 }
32333234}
32343235
3235- bool PeerManagerImpl::CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers) const
3236+ bool PeerManagerImpl::CheckHeadersAreContinuous (const std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes ) const
32363237{
3237- uint256 hashLastBlock ;
3238- for (const CBlockHeader& header : headers) {
3239- if (!hashLastBlock. IsNull () && header. hashPrevBlock != hashLastBlock ) {
3238+ assert (headers. size () == hashes. size ()) ;
3239+ for (size_t i = 1 ; i < headers. size (); ++i ) {
3240+ if (headers[i]. hashPrevBlock != hashes[i - 1 ] ) {
32403241 return false ;
32413242 }
3242- hashLastBlock = header.GetHash ();
32433243 }
32443244 return true ;
32453245}
32463246
3247- bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync (Peer& peer, CNode& pfrom, std::vector<CBlockHeader>& headers, bool uses_compressed)
3247+ bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync (Peer& peer, CNode& pfrom, std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, bool uses_compressed)
32483248{
32493249 if (peer.m_headers_sync ) {
3250- auto result = peer.m_headers_sync ->ProcessNextHeaders (headers, headers.size () == GetHeadersLimit (pfrom, uses_compressed));
3250+ auto result = peer.m_headers_sync ->ProcessNextHeaders (headers, hashes, headers.size () == GetHeadersLimit (pfrom, uses_compressed));
32513251 if (result.request_more ) {
32523252 auto locator = peer.m_headers_sync ->NextHeadersRequestLocator ();
32533253 // If we were instructed to ask for a locator, it should not be empty.
@@ -3331,7 +3331,7 @@ bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(Peer& peer, CNode& pfro
33313331 return false ;
33323332}
33333333
3334- bool PeerManagerImpl::TryLowWorkHeadersSync (Peer& peer, CNode& pfrom, const CBlockIndex* chain_start_header, std::vector<CBlockHeader>& headers, bool uses_compressed)
3334+ bool PeerManagerImpl::TryLowWorkHeadersSync (Peer& peer, CNode& pfrom, const CBlockIndex* chain_start_header, std::vector<CBlockHeader>& headers, const std::vector<uint256>& hashes, bool uses_compressed)
33353335{
33363336 // Calculate the total work on this chain.
33373337 arith_uint256 total_work = chain_start_header->nChainWork + CalculateHeadersWork (headers);
@@ -3363,7 +3363,7 @@ bool PeerManagerImpl::TryLowWorkHeadersSync(Peer& peer, CNode& pfrom, const CBlo
33633363 // Now a HeadersSyncState object for tracking this synchronization
33643364 // is created, process the headers using it as normal. Failures are
33653365 // handled inside of IsContinuationOfLowWorkHeadersSync.
3366- (void )IsContinuationOfLowWorkHeadersSync (peer, pfrom, headers, uses_compressed);
3366+ (void )IsContinuationOfLowWorkHeadersSync (peer, pfrom, headers, hashes, uses_compressed);
33673367 } else {
33683368 LogPrint (BCLog::NET , " Ignoring low-work chain (height=%u) from peer=%d\n " , chain_start_header->nHeight + headers.size (), pfrom.GetId ());
33693369 }
@@ -3534,8 +3534,10 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom,
35343534
35353535void PeerManagerImpl::ProcessHeadersMessage (CNode& pfrom, Peer& peer,
35363536 std::vector<CBlockHeader>&& headers,
3537+ std::vector<uint256>&& hashes,
35373538 bool via_compact_block, bool uses_compressed)
35383539{
3540+ Assume (headers.size () == hashes.size ());
35393541 size_t nCount = headers.size ();
35403542
35413543 if (nCount == 0 ) {
@@ -3556,7 +3558,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
35563558 // We'll rely on headers having valid proof-of-work further down, as an
35573559 // anti-DoS criteria (note: this check is required before passing any
35583560 // headers into HeadersSyncState).
3559- if (!CheckHeadersPoW (headers, m_chainparams.GetConsensus (), pfrom)) {
3561+ if (!CheckHeadersPoW (headers, hashes, m_chainparams.GetConsensus (), pfrom)) {
35603562 // Misbehaving() calls are handled within CheckHeadersPoW(), so we can
35613563 // just return. (Note that even if a header is announced via compact
35623564 // block, the header itself should be valid, so this type of error can
@@ -3578,7 +3580,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
35783580 {
35793581 LOCK (peer.m_headers_sync_mutex );
35803582
3581- already_validated_work = IsContinuationOfLowWorkHeadersSync (peer, pfrom, headers, uses_compressed);
3583+ already_validated_work = IsContinuationOfLowWorkHeadersSync (peer, pfrom, headers, hashes, uses_compressed);
35823584
35833585 // The headers we passed in may have been:
35843586 // - untouched, perhaps if no headers-sync was in progress, or some
@@ -3620,7 +3622,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
36203622 const CBlockIndex *last_received_header{nullptr };
36213623 {
36223624 LOCK (cs_main);
3623- last_received_header = m_chainman.m_blockman .LookupBlockIndex (headers .back (). GetHash ());
3625+ last_received_header = m_chainman.m_blockman .LookupBlockIndex (hashes .back ());
36243626 if (IsAncestorOfBestHeaderOrTip (last_received_header)) {
36253627 already_validated_work = true ;
36263628 }
@@ -3637,7 +3639,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
36373639 // Do anti-DoS checks to determine if we should process or store for later
36383640 // processing.
36393641 if (!already_validated_work && TryLowWorkHeadersSync (peer, pfrom,
3640- chain_start_header, headers, uses_compressed)) {
3642+ chain_start_header, headers, hashes, uses_compressed)) {
36413643 // If we successfully started a low-work headers sync, then there
36423644 // should be no headers to process any further.
36433645 Assume (headers.empty ());
@@ -5330,7 +5332,7 @@ void PeerManagerImpl::ProcessMessage(
53305332 // the peer if the header turns out to be for an invalid block.
53315333 // Note that if a peer tries to build on an invalid chain, that
53325334 // will be detected and the peer will be disconnected/discouraged.
5333- return ProcessHeadersMessage (pfrom, *peer, {cmpctblock.header }, /* via_compact_block=*/ true , UsesCompressedHeaders (*peer));
5335+ return ProcessHeadersMessage (pfrom, *peer, {cmpctblock.header }, {cmpctblock. header . GetHash ()}, /* via_compact_block=*/ true , UsesCompressedHeaders (*peer));
53345336 }
53355337
53365338 if (fBlockReconstructed ) {
@@ -5473,7 +5475,14 @@ void PeerManagerImpl::ProcessMessage(
54735475 }
54745476 }
54755477
5476- ProcessHeadersMessage (pfrom, *peer, std::move (headers), /* via_compact_block=*/ false , msg_type == NetMsgType::HEADERS2 );
5478+ // Pre-compute each header's hash once so downstream PRESYNC/REDOWNLOAD/
5479+ // CheckHeadersPoW/CheckHeadersAreContinuous reuse it instead of
5480+ // recomputing X11 multiple times per header.
5481+ std::vector<uint256> hashes;
5482+ hashes.reserve (headers.size ());
5483+ for (const CBlockHeader& h : headers) hashes.push_back (h.GetHash ());
5484+
5485+ ProcessHeadersMessage (pfrom, *peer, std::move (headers), std::move (hashes), /* via_compact_block=*/ false , msg_type == NetMsgType::HEADERS2 );
54775486
54785487 // Check if the headers presync progress needs to be reported to validation.
54795488 // This needs to be done without holding the m_headers_presync_mutex lock.
0 commit comments