diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 32c3bff73482..8286f93cfa70 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -68,8 +68,8 @@ void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& opti for (const std::string& strDeployment : args.GetArgs("-vbparams")) { std::vector vDeploymentParams = SplitString(strDeployment, ':'); - if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) { - throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]"); + if (vDeploymentParams.size() < 3 || 7 < vDeploymentParams.size()) { + throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height[:max_activation_height[:active_duration[:threshold]]]]"); } CChainParams::VersionBitsParameters vbparams{}; const auto start_time{ToIntegral(vDeploymentParams[1])}; @@ -91,13 +91,38 @@ void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& opti } else { vbparams.min_activation_height = 0; } + if (vDeploymentParams.size() >= 5) { + const auto max_activation_height{ToIntegral(vDeploymentParams[4])}; + if (!max_activation_height) { + throw std::runtime_error(strprintf("Invalid max_activation_height (%s)", vDeploymentParams[4])); + } + vbparams.max_activation_height = *max_activation_height; + } + if (vDeploymentParams.size() >= 6) { + const auto active_duration{ToIntegral(vDeploymentParams[5])}; + if (!active_duration) { + throw std::runtime_error(strprintf("Invalid active_duration (%s)", vDeploymentParams[5])); + } + vbparams.active_duration = *active_duration; + } + if (vDeploymentParams.size() >= 7) { + const auto threshold{ToIntegral(vDeploymentParams[6])}; + if (!threshold) { + throw std::runtime_error(strprintf("Invalid threshold (%s)", vDeploymentParams[6])); + } + vbparams.threshold = *threshold; + } + // Validate that timeout and max_activation_height are mutually exclusive + if (vbparams.timeout != Consensus::BIP9Deployment::NO_TIMEOUT && vbparams.max_activation_height < std::numeric_limits::max()) { + throw std::runtime_error(strprintf("Cannot specify both timeout (%ld) and max_activation_height (%d) for deployment %s. Use timeout for BIP9 or max_activation_height for mandatory activation deadline, not both.", vbparams.timeout, vbparams.max_activation_height, vDeploymentParams[0])); + } bool found = false; for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) { options.version_bits_parameters[Consensus::DeploymentPos(j)] = vbparams; found = true; - LogInfo("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d", - vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height); + LogInfo("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d, max_activation_height=%d, active_duration=%d, threshold=%d", + vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height, vbparams.max_activation_height, vbparams.active_duration, vbparams.threshold); break; } } diff --git a/src/consensus/params.h b/src/consensus/params.h index 93ee071fdc16..902a933c9d00 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -54,6 +54,10 @@ struct BIP9Deployment { * boundary. */ int min_activation_height{0}; + /** Maximum height for activation. If less than INT_MAX, the deployment will activate + * at this height regardless of signaling (similar to BIP8 flag day). + * std::numeric_limits::max() means no maximum (activation only via signaling). */ + int max_activation_height{std::numeric_limits::max()}; /** Period of blocks to check signalling in (usually retarget period, ie params.DifficultyAdjustmentInterval()) */ uint32_t period{2016}; /** @@ -62,6 +66,9 @@ struct BIP9Deployment { * Examples: 1916 for 95%, 1512 for testchains. */ uint32_t threshold{1916}; + /** For temporary softforks: number of blocks the deployment remains active after activation. + * std::numeric_limits::max() means permanent (never expires). */ + int active_duration{std::numeric_limits::max()}; /** Constant for nTimeout very far in the future. */ static constexpr int64_t NO_TIMEOUT = std::numeric_limits::max(); diff --git a/src/deploymentstatus.h b/src/deploymentstatus.h index 921c7c187735..ae93cefa75cf 100644 --- a/src/deploymentstatus.h +++ b/src/deploymentstatus.h @@ -49,4 +49,5 @@ inline bool DeploymentEnabled(const Consensus::Params& params, Consensus::Deploy return params.vDeployments[dep].nStartTime != Consensus::BIP9Deployment::NEVER_ACTIVE; } + #endif // BITCOIN_DEPLOYMENTSTATUS_H diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index 64809a75911e..26b8b78e0582 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -16,6 +16,7 @@ #include #include