From fa7e191f44d9dee7a3d7bfea80fbf452353ae60d Mon Sep 17 00:00:00 2001 From: AlphaPool Date: Sat, 17 Oct 2026 02:14:42 +0000 Subject: [PATCH 1/4] consensus: Keep rolling coinbase maturity until RDTS expiry Reuse the RDTS parent-MTP expiry on mainnet, preserving testnet4 and existing policy. Bound revalidation by parent MTP while still rewinding unchecked pre-expiry history on upgrades after expiry. Add synthetic expiry parameters and boundary/marker units. --- src/chainparams.cpp | 29 +++- src/chainparamsbase.cpp | 3 +- src/consensus/params.h | 18 ++- src/kernel/chainparams.cpp | 11 +- src/kernel/chainparams.h | 2 + src/rpc/blockchain.cpp | 14 +- src/rpc/mining.cpp | 2 +- src/test/coinbase_maturity_tests.cpp | 145 ++++++++++++----- .../validation_chainstatemanager_tests.cpp | 151 ++++++++++++++++-- src/validation.cpp | 30 +++- .../mempool_long_coinbase_maturity.py | 11 +- 11 files changed, 338 insertions(+), 78 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index e2851d88c986..1a2c3243f4d9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -103,31 +103,50 @@ void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& opti if (const auto arg{args.GetArg("-testcoinbasematuritylong")}; arg) { const auto values{SplitString(*arg, ':')}; - if (values.size() != 3) { - throw std::runtime_error(strprintf("Invalid format (%s) for -testcoinbasematuritylong=::.", *arg)); + if (values.size() < 3 || values.size() > 4) { + throw std::runtime_error(strprintf("Invalid format (%s) for -testcoinbasematuritylong=::[:].", *arg)); } int32_t start_height; int32_t enforce_height; int32_t release_height; if (!ParseInt32(values[0], &start_height) || start_height < 0 || start_height >= std::numeric_limits::max()) { - throw std::runtime_error(strprintf("Invalid start height (%s) for -testcoinbasematuritylong=::.", values[0])); + throw std::runtime_error(strprintf("Invalid start height (%s) for -testcoinbasematuritylong=::[:].", values[0])); } if (!ParseInt32(values[1], &enforce_height) || enforce_height < 2 || enforce_height >= std::numeric_limits::max()) { - throw std::runtime_error(strprintf("Invalid enforce height (%s) for -testcoinbasematuritylong=::.", values[1])); + throw std::runtime_error(strprintf("Invalid enforce height (%s) for -testcoinbasematuritylong=::[:].", values[1])); } if (!ParseInt32(values[2], &release_height) || release_height <= start_height || release_height <= enforce_height || release_height >= std::numeric_limits::max()) { - throw std::runtime_error(strprintf("Invalid release height (%s) for -testcoinbasematuritylong=::.", values[2])); + throw std::runtime_error(strprintf("Invalid release height (%s) for -testcoinbasematuritylong=::[:].", values[2])); } if (release_height - start_height <= COINBASE_MATURITY) { throw std::runtime_error(strprintf("Invalid height range (%s) for -testcoinbasematuritylong=::: release_height - start_height must exceed COINBASE_MATURITY.", *arg)); } + if (values.size() == 4) { + int32_t maturity; + if (!ParseInt32(values[3], &maturity) || maturity < COINBASE_MATURITY || maturity >= std::numeric_limits::max()) { + throw std::runtime_error(strprintf("Invalid maturity (%s) for -testcoinbasematuritylong.", values[3])); + } + options.coinbase_maturity_long_maturity = maturity; + } + options.coinbase_maturity_long_start_height = start_height; options.coinbase_maturity_long_enforce_height = enforce_height; options.coinbase_maturity_long_release_height = release_height; } + if (const auto arg{args.GetArg("-testcoinbasematuritylongexpiry")}; arg) { + int64_t expiry; + if (!options.coinbase_maturity_long_start_height || !ParseInt64(*arg, &expiry) || expiry <= 1296688602) { + throw std::runtime_error("Invalid expiry for -testcoinbasematuritylongexpiry: requires -testcoinbasematuritylong and a time after regtest genesis (1296688602)."); + } + if (options.rdts_expiry_time && *options.rdts_expiry_time != expiry) { + throw std::runtime_error("-testcoinbasematuritylongexpiry must match -rdtsexpiry when both are specified."); + } + options.coinbase_maturity_long_expiry_time = expiry; + } + for (const std::string& strDeployment : args.GetArgs("-vbparams")) { std::vector vDeploymentParams = SplitString(strDeployment, ':'); if (vDeploymentParams.size() < 3 || 7 < vDeploymentParams.size()) { diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index de5a866c7c4f..88bebb86dbfd 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -19,7 +19,8 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman) argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv, blake2b). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-rdtsexpiry=