refactor: Compute work from headers without CBlockIndex

Avoid the need to construct a CBlockIndex object just to compute work for a header,
when its nBits value suffices for that.

Co-Authored-By: Pieter Wuille <pieter@wuille.net>
This commit is contained in:
Daniela Brozzoni 2025-08-18 11:46:04 +02:00
parent 0bf6139e19
commit 4066bfe561
No known key found for this signature in database
GPG Key ID: 7DE4F1FDCED0AB87
5 changed files with 16 additions and 9 deletions

View File

@ -124,12 +124,12 @@ void CBlockIndex::BuildSkip()
pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
}
arith_uint256 GetBlockProof(const CBlockIndex& block)
arith_uint256 GetBitsProof(uint32_t bits)
{
arith_uint256 bnTarget;
bool fNegative;
bool fOverflow;
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
bnTarget.SetCompact(bits, &fNegative, &fOverflow);
if (fNegative || fOverflow || bnTarget == 0)
return 0;
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256

View File

@ -348,7 +348,15 @@ protected:
CBlockIndex& operator=(CBlockIndex&&) = delete;
};
arith_uint256 GetBlockProof(const CBlockIndex& block);
/** Compute how much work an nBits value corresponds to. */
arith_uint256 GetBitsProof(uint32_t bits);
/** Compute how much work a block index entry corresponds to. */
inline arith_uint256 GetBlockProof(const CBlockIndex& block) { return GetBitsProof(block.nBits); }
/** Compute how much work a block header corresponds to. */
inline arith_uint256 GetBlockProof(const CBlockHeader& header) { return GetBitsProof(header.nBits); }
/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&);
/** Find the forking point between two chain tips. */

View File

@ -202,7 +202,7 @@ bool HeadersSyncState::ValidateAndProcessSingleHeader(const CBlockHeader& curren
}
}
m_current_chain_work += GetBlockProof(CBlockIndex(current));
m_current_chain_work += GetBlockProof(current);
m_last_header_received = current;
m_current_height = next_height;
@ -238,7 +238,7 @@ bool HeadersSyncState::ValidateAndStoreRedownloadedHeader(const CBlockHeader& he
}
// Track work on the redownloaded chain
m_redownload_chain_work += GetBlockProof(CBlockIndex(header));
m_redownload_chain_work += GetBlockProof(header);
if (m_redownload_chain_work >= m_minimum_required_work) {
m_process_all_remaining_headers = true;

View File

@ -4348,7 +4348,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), *peer);
}
return;
} else if (prev_block->nChainWork + CalculateClaimedHeadersWork({{cmpctblock.header}}) < GetAntiDoSWorkThreshold()) {
} else if (prev_block->nChainWork + GetBlockProof(cmpctblock.header) < GetAntiDoSWorkThreshold()) {
// If we get a low-work header in a compact block, we can ignore it.
LogDebug(BCLog::NET, "Ignoring low-work compact block from peer %d\n", pfrom.GetId());
return;
@ -4666,7 +4666,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
// Check claimed work on this block against our anti-dos thresholds.
if (prev_block && prev_block->nChainWork + CalculateClaimedHeadersWork({{pblock->GetBlockHeader()}}) >= GetAntiDoSWorkThreshold()) {
if (prev_block && prev_block->nChainWork + GetBlockProof(pblock->GetBlockHeader()) >= GetAntiDoSWorkThreshold()) {
min_pow_checked = true;
}
}

View File

@ -4171,8 +4171,7 @@ arith_uint256 CalculateClaimedHeadersWork(std::span<const CBlockHeader> headers)
{
arith_uint256 total_work{0};
for (const CBlockHeader& header : headers) {
CBlockIndex dummy(header);
total_work += GetBlockProof(dummy);
total_work += GetBlockProof(header);
}
return total_work;
}