From e9e4cad8e8affa82f047acf999d4195168024287 Mon Sep 17 00:00:00 2001 From: Capri Date: Tue, 15 Sep 2026 22:06:59 +0000 Subject: [PATCH] Validate RandomX proof of work when reading blocks --- src/node/blockstorage.cpp | 29 ++++++++++++++++++++++++++--- src/validation.cpp | 9 +-------- src/validation.h | 8 ++++++++ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index ae867a9..de6646f 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -379,9 +379,16 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); } - // Check the header - if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) { - return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); + // Check context-free proof of work. RandomX requires the previous block + // index to resolve its deterministic seed and is therefore checked by + // the CBlockIndex overload below. + if (block.GetHash() == consensusParams.hashGenesisBlock || + block.GetAlgo() == ALGO_SHA256D) { + if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) { + return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); + } + } else if (block.GetAlgo() != ALGO_RANDOMX) { + return error("ReadBlockFromDisk: Unknown proof-of-work algorithm at %s", pos.ToString()); } // Signet only: check block solution @@ -403,6 +410,22 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", pindex->ToString(), block_pos.ToString()); } + + if (block.GetHash() != consensusParams.hashGenesisBlock && + block.GetAlgo() == ALGO_RANDOMX) { + if (pindex->pprev == nullptr) { + return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): RandomX block has no previous block index for %s at %s", + pindex->ToString(), block_pos.ToString()); + } + + BlockValidationState state; + if (!CheckContextualRandomXProofOfWork( + block, state, consensusParams, pindex->pprev, true)) { + return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): RandomX proof of work failed for %s at %s: %s", + pindex->ToString(), block_pos.ToString(), state.ToString()); + } + } + return true; } diff --git a/src/validation.cpp b/src/validation.cpp index c763ffb..e02fce2 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1747,13 +1747,6 @@ static int64_t nTimeCallbacks = 0; static int64_t nTimeTotal = 0; static int64_t nBlocksTotal = 0; -static bool CheckContextualRandomXProofOfWork( - const CBlockHeader& block, - BlockValidationState& state, - const Consensus::Params& consensusParams, - const CBlockIndex* pindexPrev, - bool fCheckPOW); - /** Apply the effects of this block (with given index) on the UTXO set represented by coins. * Validity checks that depend on the UTXO set are also done; ConnectBlock() * can fail if those validity checks fail (among other reasons). */ @@ -3157,7 +3150,7 @@ static bool CheckRandomXProofOfWork( return true; } -static bool CheckContextualRandomXProofOfWork( +bool CheckContextualRandomXProofOfWork( const CBlockHeader& block, BlockValidationState& state, const Consensus::Params& consensusParams, diff --git a/src/validation.h b/src/validation.h index 646dc06..1d785fe 100644 --- a/src/validation.h +++ b/src/validation.h @@ -346,6 +346,14 @@ void InitScriptExecutionCache(); /** Context-independent validity checks */ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +/** Context-dependent RandomX proof-of-work validation. */ +bool CheckContextualRandomXProofOfWork( + const CBlockHeader& block, + BlockValidationState& state, + const Consensus::Params& consensusParams, + const CBlockIndex* pindexPrev, + bool fCheckPOW = true); + /** Check a block is completely valid from start to finish (only works on top of our current best block) */ bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainparams,