Make RandomX block templates activation-aware

This commit is contained in:
Capri 2026-09-15 20:02:12 +00:00
commit 00158bc780
Signed by: VextaProject
SSH key fingerprint: SHA256:739BZv8LvIDY2tR7lXLy/IQ6MaGTQtYcG9GNvCjmpVM
7 changed files with 104 additions and 12 deletions

View file

@ -592,6 +592,8 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse
consensus.BIP65Height = int{height};
} else if (name == "csv") {
consensus.CSVHeight = int{height};
} else if (name == "randomx") {
consensus.randomXActivationHeight = int{height};
} else {
throw std::runtime_error(strprintf("Invalid name (%s) for -testactivationheight=name@height.", arg));
}

View file

@ -26,7 +26,7 @@
#include <algorithm>
#include <utility>
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int algo)
{
int64_t nOldTime = pblock->nTime;
int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
@ -36,7 +36,7 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
// Updating time can change work required on testnet:
if (consensusParams.fPowAllowMinDifficultyBlocks)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams, ALGO_SHA256D);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams, algo);
return nNewTime - nOldTime;
}
@ -172,7 +172,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
pblock->SetAlgo(algo);
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev, algo);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus(), algo);
pblock->nNonce = 0;
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);

View file

@ -204,7 +204,7 @@ void RegenerateCommitments(CBlock& block, const CBlockIndex* pindexPrev, const C
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int algo);
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);

View file

@ -639,7 +639,12 @@ static RPCHelpMan getblocktemplate()
if (strAlgo == "sha256d") {
algo = ALGO_SHA256D;
} else if (strAlgo == "randomx") {
throw JSONRPCError(RPC_INVALID_PARAMETER, "RandomX is not active yet");
const CBlockIndex* tip = chainman.ActiveChain().Tip();
if (tip == nullptr ||
tip->nHeight + 1 < Params().GetConsensus().randomXActivationHeight) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "RandomX is not active yet");
}
algo = ALGO_RANDOMX;
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown proof-of-work algorithm");
}
@ -809,7 +814,7 @@ static RPCHelpMan getblocktemplate()
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Update nTime
UpdateTime(pblock, consensusParams, pindexPrev);
UpdateTime(pblock, consensusParams, pindexPrev, algo);
pblock->nNonce = 0;
// NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration

View file

@ -1751,7 +1751,8 @@ static bool CheckContextualRandomXProofOfWork(
const CBlockHeader& block,
BlockValidationState& state,
const Consensus::Params& consensusParams,
const CBlockIndex* pindexPrev);
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()
@ -1793,7 +1794,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
if (!fJustCheck &&
block.GetHash() != m_params.GetConsensus().hashGenesisBlock &&
block.GetAlgo() == ALGO_RANDOMX &&
!CheckContextualRandomXProofOfWork(block, state, m_params.GetConsensus(), pindex->pprev)) {
!CheckContextualRandomXProofOfWork(block, state, m_params.GetConsensus(), pindex->pprev, true)) {
return error("%s: contextual RandomX proof of work check failed: %s", __func__, state.ToString());
}
@ -3160,7 +3161,8 @@ static bool CheckContextualRandomXProofOfWork(
const CBlockHeader& block,
BlockValidationState& state,
const Consensus::Params& consensusParams,
const CBlockIndex* pindexPrev)
const CBlockIndex* pindexPrev,
bool fCheckPOW)
{
assert(pindexPrev != nullptr);
assert(block.GetAlgo() == ALGO_RANDOMX);
@ -3185,6 +3187,9 @@ static bool CheckContextualRandomXProofOfWork(
"incorrect RandomX proof of work difficulty");
}
if (!fCheckPOW)
return true;
return CheckRandomXProofOfWork(
block,
state,
@ -3197,6 +3202,16 @@ static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& st
if (!fCheckPOW)
return true;
// Genesis predates the multi-algo version-bit encoding. Preserve its
// historical SHA256D proof-of-work validation without treating unknown
// algorithm version bits as valid for any other block.
if (block.GetHash() == consensusParams.hashGenesisBlock) {
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "high-hash", "proof of work failed");
return true;
}
const int algo = block.GetAlgo();
// SHA256D proof of work is context-free.
@ -3357,7 +3372,7 @@ CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
* in ConnectBlock().
* Note that -reindex-chainstate skips the validation that happens here!
*/
static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime, bool fCheckPOW = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
assert(pindexPrev != nullptr);
const int nHeight = pindexPrev->nHeight + 1;
@ -3367,7 +3382,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
const int algo = block.GetAlgo();
if (algo == ALGO_RANDOMX) {
if (!CheckContextualRandomXProofOfWork(block, state, consensusParams, pindexPrev))
if (!CheckContextualRandomXProofOfWork(block, state, consensusParams, pindexPrev, fCheckPOW))
return false;
} else if (algo == ALGO_SHA256D) {
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams, ALGO_SHA256D))
@ -3751,7 +3766,7 @@ bool TestBlockValidity(BlockValidationState& state,
indexDummy.phashBlock = &block_hash;
// NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, chainstate.m_blockman, chainparams, pindexPrev, GetAdjustedTime()))
if (!ContextualCheckBlockHeader(block, state, chainstate.m_blockman, chainparams, pindexPrev, GetAdjustedTime(), fCheckPOW))
return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, state.ToString());
if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot))
return error("%s: Consensus::CheckBlock: %s", __func__, state.ToString());