diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c8f62f3..90dbf42 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -184,6 +184,8 @@ public: consensus.asertHalfLife = 2 * 24 * 60 * 60; consensus.fastRiseActivationHeight = 7000; consensus.randomXActivationHeight = std::numeric_limits::max(); + consensus.randomXSeedEpochLength = 2048; + consensus.randomXSeedLag = 64; @@ -227,6 +229,8 @@ public: consensus.asertHalfLife = 2 * 24 * 60 * 60; consensus.fastRiseActivationHeight = 7000; consensus.randomXActivationHeight = std::numeric_limits::max(); + consensus.randomXSeedEpochLength = 2048; + consensus.randomXSeedLag = 64; @@ -374,6 +378,8 @@ public: consensus.fEasyPow = false; consensus.fPowNoRetargeting = false; consensus.randomXActivationHeight = std::numeric_limits::max(); + consensus.randomXSeedEpochLength = 2048; + consensus.randomXSeedLag = 64; consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016 consensus.nMinerConfirmationWindow = 2016; // legacy Bitcoin confirmation window consensus.fRbfEnabled = false; @@ -464,6 +470,8 @@ public: consensus.asertHalfLife = 2 * 24 * 60 * 60; consensus.fastRiseActivationHeight = 7000; consensus.randomXActivationHeight = std::numeric_limits::max(); + consensus.randomXSeedEpochLength = 64; + consensus.randomXSeedLag = 8; consensus.BIP65Height = 1351; diff --git a/src/consensus/params.h b/src/consensus/params.h index 362ac5f..749a13f 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -125,6 +125,8 @@ struct Params { int64_t asertHalfLife; int fastRiseActivationHeight; int randomXActivationHeight; + int randomXSeedEpochLength; + int randomXSeedLag; diff --git a/src/pow.cpp b/src/pow.cpp index ebd30a9..a922d13 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -17,6 +17,53 @@ inline unsigned int PowLimit(const Consensus::Params& params) return UintToArith256(params.powLimit).GetCompact(); } +int GetRandomXSeedHeight(int blockHeight, const Consensus::Params& params) +{ + if (blockHeight <= 0) { + return 0; + } + + const int epochLength = params.randomXSeedEpochLength; + const int seedLag = params.randomXSeedLag; + + if (epochLength <= 0 || seedLag < 0) { + return 0; + } + + const int epochStart = (blockHeight / epochLength) * epochLength; + + if (epochStart <= seedLag) { + return 0; + } + + return epochStart - seedLag; +} + +bool GetRandomXSeed( + const CBlockIndex* pindexPrev, + int blockHeight, + const Consensus::Params& params, + uint256& seed) +{ + if (pindexPrev == nullptr) { + return false; + } + + const int seedHeight = GetRandomXSeedHeight(blockHeight, params); + + if (seedHeight > pindexPrev->nHeight) { + return false; + } + + const CBlockIndex* pindexSeed = pindexPrev->GetAncestor(seedHeight); + if (pindexSeed == nullptr) { + return false; + } + + seed = pindexSeed->GetBlockHash(); + return true; +} + unsigned int InitialDifficulty(const Consensus::Params& params) { return PowLimit(params); diff --git a/src/pow.h b/src/pow.h index f49168c..000df63 100644 --- a/src/pow.h +++ b/src/pow.h @@ -22,4 +22,19 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); const CBlockIndex* GetLastBlockIndexForAlgoFast(const CBlockIndex* pindex, int algo); +/** Return the block height whose hash is used as the RandomX seed key. */ +int GetRandomXSeedHeight(int blockHeight, const Consensus::Params& params); + +/** + * Resolve the RandomX seed key from the previous block index. + * + * The seed is always derived from an already-known ancestor block hash. + * Returns false if the requested seed ancestor cannot be resolved. + */ +bool GetRandomXSeed( + const CBlockIndex* pindexPrev, + int blockHeight, + const Consensus::Params& params, + uint256& seed); + #endif // DIGIBYTE_POW_H diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp index 5aa0bdc..bc3cb13 100644 --- a/src/test/fuzz/pow.cpp +++ b/src/test/fuzz/pow.cpp @@ -61,7 +61,7 @@ FUZZ_TARGET_INIT(pow, initialize_pow) { (void)GetBlockProof(current_block); if (current_block.nHeight != std::numeric_limits::max() && current_block.nHeight - (consensus_params.nMinerConfirmationWindow - 1) >= 0) { - (void)GetNextWorkRequired(¤t_block, &(*block_header), consensus_params); + (void)GetNextWorkRequired(¤t_block, &(*block_header), consensus_params, ALGO_SHA256D); } } { diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index d536a70..29a4ce8 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -163,13 +164,13 @@ BOOST_AUTO_TEST_CASE(ASERT_behavior_test) // Block 6499 is still governed by the legacy DAA. const unsigned int preActivationBits = - GetNextWorkRequired(&blocks[6498], nullptr, consensus); + GetNextWorkRequired(&blocks[6498], nullptr, consensus, ALGO_SHA256D); BOOST_CHECK_EQUAL(preActivationBits, anchorBits); // Block 6500 is the first ASERT block. Ideal 10-minute spacing // must preserve the anchor target. const unsigned int idealBits = - GetNextWorkRequired(&blocks[6499], nullptr, consensus); + GetNextWorkRequired(&blocks[6499], nullptr, consensus, ALGO_SHA256D); BOOST_CHECK_EQUAL(idealBits, anchorBits); // Block 6501 after a very fast previous block: target must decrease @@ -178,7 +179,7 @@ BOOST_AUTO_TEST_CASE(ASERT_behavior_test) blocks[6499].nTime + consensus.nPowTargetSpacing / 10; const unsigned int fastBits = - GetNextWorkRequired(&blocks[6500], nullptr, consensus); + GetNextWorkRequired(&blocks[6500], nullptr, consensus, ALGO_SHA256D); arith_uint256 fastTarget; fastTarget.SetCompact(fastBits); @@ -194,7 +195,7 @@ BOOST_AUTO_TEST_CASE(ASERT_behavior_test) blocks[6499].nTime + consensus.nPowTargetSpacing * 3; const unsigned int slowBits = - GetNextWorkRequired(&blocks[6500], nullptr, consensus); + GetNextWorkRequired(&blocks[6500], nullptr, consensus, ALGO_SHA256D); arith_uint256 slowTarget; slowTarget.SetCompact(slowBits); @@ -206,7 +207,7 @@ BOOST_AUTO_TEST_CASE(ASERT_behavior_test) blocks[6499].nTime + consensus.asertHalfLife * 16; const unsigned int extremeSlowBits = - GetNextWorkRequired(&blocks[6500], nullptr, consensus); + GetNextWorkRequired(&blocks[6500], nullptr, consensus, ALGO_SHA256D); BOOST_CHECK_EQUAL( extremeSlowBits, @@ -246,7 +247,7 @@ BOOST_AUTO_TEST_CASE(ASERT_reference_vector_run04_test) blocks[2].nBits = 0x01010000; const unsigned int result = - GetNextWorkRequired(&blocks[2], nullptr, consensus); + GetNextWorkRequired(&blocks[2], nullptr, consensus, ALGO_SHA256D); BOOST_CHECK_EQUAL(result, 0x01020000U); } @@ -279,7 +280,7 @@ BOOST_AUTO_TEST_CASE(ASERT_reference_vector_run05_test) blocks[2].nBits = 0x1d00ffff; BOOST_CHECK_EQUAL( - GetNextWorkRequired(&blocks[2], nullptr, consensus), + GetNextWorkRequired(&blocks[2], nullptr, consensus, ALGO_SHA256D), 0x1d00fec5U); // BCHN official ASERT run05 vector, iteration 2: @@ -292,7 +293,7 @@ BOOST_AUTO_TEST_CASE(ASERT_reference_vector_run05_test) } BOOST_CHECK_EQUAL( - GetNextWorkRequired(&blocks[290], nullptr, consensus), + GetNextWorkRequired(&blocks[290], nullptr, consensus, ALGO_SHA256D), 0x1c7f62c0U); } @@ -346,7 +347,7 @@ BOOST_AUTO_TEST_CASE(ASERT_reference_vector_run06_test) blocks[h].nBits = 0x1802aee8; BOOST_CHECK_EQUAL( - GetNextWorkRequired(&blocks[h], nullptr, consensus), + GetNextWorkRequired(&blocks[h], nullptr, consensus, ALGO_SHA256D), expected[h]); } } @@ -386,9 +387,9 @@ BOOST_AUTO_TEST_CASE(FastRise_activation_and_trigger_test) baselineConsensus.fastRiseActivationHeight = 1000000; const unsigned int twoFastBaseline = - GetNextWorkRequired(&blocks[6999], nullptr, baselineConsensus); + GetNextWorkRequired(&blocks[6999], nullptr, baselineConsensus, ALGO_SHA256D); const unsigned int twoFastResult = - GetNextWorkRequired(&blocks[6999], nullptr, consensus); + GetNextWorkRequired(&blocks[6999], nullptr, consensus, ALGO_SHA256D); BOOST_CHECK_EQUAL(twoFastResult, twoFastBaseline); @@ -397,9 +398,9 @@ BOOST_AUTO_TEST_CASE(FastRise_activation_and_trigger_test) blocks[6999].nTime = blocks[6998].nTime + 600; const unsigned int threeFastBaseline = - GetNextWorkRequired(&blocks[6999], nullptr, baselineConsensus); + GetNextWorkRequired(&blocks[6999], nullptr, baselineConsensus, ALGO_SHA256D); const unsigned int threeFastResult = - GetNextWorkRequired(&blocks[6999], nullptr, consensus); + GetNextWorkRequired(&blocks[6999], nullptr, consensus, ALGO_SHA256D); arith_uint256 expectedFastTarget; expectedFastTarget.SetCompact(blocks[6999].nBits); @@ -412,7 +413,7 @@ BOOST_AUTO_TEST_CASE(FastRise_activation_and_trigger_test) consensus.fastRiseActivationHeight = 7001; const unsigned int preActivationResult = - GetNextWorkRequired(&blocks[6999], nullptr, consensus); + GetNextWorkRequired(&blocks[6999], nullptr, consensus, ALGO_SHA256D); BOOST_CHECK_EQUAL(preActivationResult, threeFastBaseline); } @@ -449,7 +450,7 @@ BOOST_AUTO_TEST_CASE(FastRise_returns_to_ASERT_test) blocks[6999].nTime = blocks[6998].nTime + 600; const unsigned int triggeredBits = - GetNextWorkRequired(&blocks[6999], nullptr, consensus); + GetNextWorkRequired(&blocks[6999], nullptr, consensus, ALGO_SHA256D); arith_uint256 triggeredTarget; triggeredTarget.SetCompact(triggeredBits); @@ -470,10 +471,10 @@ BOOST_AUTO_TEST_CASE(FastRise_returns_to_ASERT_test) baselineConsensus.fastRiseActivationHeight = 1000000; const unsigned int expectedASERT = - GetNextWorkRequired(&blocks[7000], nullptr, baselineConsensus); + GetNextWorkRequired(&blocks[7000], nullptr, baselineConsensus, ALGO_SHA256D); const unsigned int actual = - GetNextWorkRequired(&blocks[7000], nullptr, consensus); + GetNextWorkRequired(&blocks[7000], nullptr, consensus, ALGO_SHA256D); BOOST_CHECK_EQUAL(actual, expectedASERT); } @@ -515,10 +516,10 @@ BOOST_AUTO_TEST_CASE(FastRise_zero_and_negative_intervals_test) baselineConsensus.fastRiseActivationHeight = 1000000; const unsigned int baseline = - GetNextWorkRequired(&blocks[6999], nullptr, baselineConsensus); + GetNextWorkRequired(&blocks[6999], nullptr, baselineConsensus, ALGO_SHA256D); const unsigned int actual = - GetNextWorkRequired(&blocks[6999], nullptr, consensus); + GetNextWorkRequired(&blocks[6999], nullptr, consensus, ALGO_SHA256D); arith_uint256 expectedFastTarget; expectedFastTarget.SetCompact(blocks[6999].nBits); @@ -529,4 +530,32 @@ BOOST_AUTO_TEST_CASE(FastRise_zero_and_negative_intervals_test) } + +BOOST_AUTO_TEST_CASE(RandomX_seed_height_test) +{ + auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); + auto consensus = chainParams->GetConsensus(); + + BOOST_CHECK_EQUAL(consensus.randomXSeedEpochLength, 2048); + BOOST_CHECK_EQUAL(consensus.randomXSeedLag, 64); + + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(0, consensus), 0); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(1, consensus), 0); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(64, consensus), 0); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(2047, consensus), 0); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(2048, consensus), 1984); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(2049, consensus), 1984); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(4095, consensus), 1984); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(4096, consensus), 4032); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(6144, consensus), 6080); + + consensus.randomXSeedEpochLength = 64; + consensus.randomXSeedLag = 8; + + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(63, consensus), 0); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(64, consensus), 56); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(127, consensus), 56); + BOOST_CHECK_EQUAL(GetRandomXSeedHeight(128, consensus), 120); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 83be59d..a11c189 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include