fix: gate the RandomX PoW-verification skip on the in-index checkpoint
RandomXValidationRequired skipped RandomX verification for blocks below the static top checkpoint (GetTotalBlocksEstimate), while the fork-rejection guard uses the in-index checkpoint (GetLastCheckpoint). Once the checkpoint list extends above the RandomX activation height, that asymmetry opens a gap during IBD/eclipse in which a peer with no RandomX hashpower can get SHA256-grinded, RandomX-forged blocks accepted (CheckProofOfWork hashes the header including the attacker-controlled nSolution). Gate the skip on GetLastCheckpoint()->GetHeight() so a block is PoW-exempt only when provably below a checkpoint the node has locked into its index -- the same boundary the fork guard uses. Currently inert (top checkpoint 2838000 < activation 2838976) but becomes live at the next checkpoint refresh; the check runs under cs_main and only ever adds verification. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
14
src/pow.cpp
14
src/pow.cpp
@@ -739,8 +739,18 @@ bool RandomXValidationRequired(int32_t height)
|
||||
if (HUSH_LOADINGBLOCKS != 0)
|
||||
return false;
|
||||
extern bool fCheckpointsEnabled;
|
||||
if (fCheckpointsEnabled && height < Checkpoints::GetTotalBlocksEstimate(Params().Checkpoints()))
|
||||
return false;
|
||||
// Gate the RandomX skip on the last checkpoint actually LOCKED INTO this node's block index
|
||||
// (GetLastCheckpoint), NOT the static top checkpoint (GetTotalBlocksEstimate). The fork-rejection
|
||||
// guard uses this same in-index boundary, so a block below it is provably on the checkpoint-pinned
|
||||
// chain and cannot be a forged fork. Using the static boundary would, once checkpoints extend above
|
||||
// the RandomX activation height, leave a gap (in-index checkpoint .. static top) during IBD/eclipse
|
||||
// where a no-hashpower peer could get SHA256-grinded, RandomX-forged blocks accepted. Safe to walk
|
||||
// mapBlockIndex here: called only under cs_main (ActivateBestChainStep + inline CheckRandomXSolution).
|
||||
if (fCheckpointsEnabled) {
|
||||
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(Params().Checkpoints());
|
||||
if (pcheckpoint != NULL && height < pcheckpoint->GetHeight())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user