Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 73 additions & 22 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1367,7 +1367,7 @@ static RPCHelpMan verifychain()
};
}

static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep)
static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep)
{
// For buried deployments.

Expand All @@ -1377,66 +1377,88 @@ static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue&
rv.pushKV("type", "buried");
// getblockchaininfo reports the softfork as active from when the chain height is
// one below the activation height
rv.pushKV("active", DeploymentActiveAfter(active_chain_tip, params, dep));
rv.pushKV("active", DeploymentActiveAfter(blockindex, params, dep));
rv.pushKV("height", params.DeploymentHeight(dep));
softforks.pushKV(DeploymentName(dep), rv);
}

static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, const std::unordered_map<uint8_t, int>& signals, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
static void SoftForkDescPushBack(const CBlockIndex* blockindex, const std::unordered_map<uint8_t, int>& signals, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
{
// For BIP9 deployments.

if (!DeploymentEnabled(consensusParams, id)) return;
if (blockindex == nullptr) return;

auto get_state_name = [](const ThresholdState state) -> std::string {
switch (state) {
case ThresholdState::DEFINED: return "defined";
case ThresholdState::STARTED: return "started";
case ThresholdState::LOCKED_IN: return "locked_in";
case ThresholdState::ACTIVE: return "active";
case ThresholdState::FAILED: return "failed";
}
return "invalid";
};

UniValue bip9(UniValue::VOBJ);
const ThresholdState thresholdState = g_versionbitscache.State(active_chain_tip, consensusParams, id);
switch (thresholdState) {
case ThresholdState::DEFINED: bip9.pushKV("status", "defined"); break;
case ThresholdState::STARTED: bip9.pushKV("status", "started"); break;
case ThresholdState::LOCKED_IN: bip9.pushKV("status", "locked_in"); break;
case ThresholdState::ACTIVE: bip9.pushKV("status", "active"); break;
case ThresholdState::FAILED: bip9.pushKV("status", "failed"); break;
}
const bool has_signal = (ThresholdState::STARTED == thresholdState || ThresholdState::LOCKED_IN == thresholdState);

const ThresholdState next_state = g_versionbitscache.State(blockindex, consensusParams, id);
const ThresholdState current_state = g_versionbitscache.State(blockindex->pprev, consensusParams, id);

const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state);

// BIP9 parameters
if (has_signal) {
bip9.pushKV("bit", consensusParams.vDeployments[id].bit);
}
bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime);
bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height);
bip9.pushKV("ehf", consensusParams.vDeployments[id].useEHF);
if (auto it = signals.find(consensusParams.vDeployments[id].bit); it != signals.end()) {
bip9.pushKV("ehf_height", it->second);
}
int64_t since_height = g_versionbitscache.StateSinceHeight(active_chain_tip, consensusParams, id);
bip9.pushKV("since", since_height);

// BIP9 status
bip9.pushKV("status", get_state_name(current_state));
bip9.pushKV("since", g_versionbitscache.StateSinceHeight(blockindex->pprev, consensusParams, id));
bip9.pushKV("status-next", get_state_name(next_state));

// BIP9 signalling status, if applicable
if (has_signal) {
UniValue statsUV(UniValue::VOBJ);
BIP9Stats statsStruct = g_versionbitscache.Statistics(active_chain_tip, consensusParams, id);
BIP9Stats statsStruct = g_versionbitscache.Statistics(blockindex, consensusParams, id);
statsUV.pushKV("period", statsStruct.period);
statsUV.pushKV("elapsed", statsStruct.elapsed);
statsUV.pushKV("count", statsStruct.count);
if (ThresholdState::LOCKED_IN != thresholdState) {
if (ThresholdState::LOCKED_IN != current_state) {
statsUV.pushKV("threshold", statsStruct.threshold);
statsUV.pushKV("possible", statsStruct.possible);
}
bip9.pushKV("statistics", statsUV);
}
if (ThresholdState::LOCKED_IN == thresholdState) {
bip9.pushKV("activation_height", since_height + static_cast<int>(consensusParams.vDeployments[id].nWindowSize));
if (ThresholdState::LOCKED_IN == current_state) {
bip9.pushKV("activation_height", g_versionbitscache.StateSinceHeight(blockindex->pprev, consensusParams, id) + static_cast<int>(consensusParams.vDeployments[id].nWindowSize));
}
bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height);

UniValue rv(UniValue::VOBJ);
rv.pushKV("type", "bip9");
rv.pushKV("bip9", bip9);
if (ThresholdState::ACTIVE == thresholdState) {
rv.pushKV("height", since_height);
if (ThresholdState::ACTIVE == next_state) {
rv.pushKV("height", g_versionbitscache.StateSinceHeight(blockindex, consensusParams, id));
}
rv.pushKV("active", ThresholdState::ACTIVE == thresholdState);
rv.pushKV("active", ThresholdState::ACTIVE == next_state);
rv.pushKV("bip9", bip9);

softforks.pushKV(DeploymentName(id), rv);
}

namespace {
/* TODO: when -deprecatedrpc=softforks is removed, drop these */
extern const std::vector<RPCResult> RPCHelpForDeployment;
}

// used by rest.cpp:rest_chaininfo, so cannot be static
RPCHelpMan getblockchaininfo()
{
return RPCHelpMan{"getblockchaininfo",
Expand Down Expand Up @@ -1570,6 +1592,35 @@ RPCHelpMan getblockchaininfo()
};
}

namespace {
const std::vector<RPCResult> RPCHelpForDeployment{
{RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
{RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"},
{RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
{RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",
{
{RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"},
{RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
{RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
{RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
{RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},
{RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
{RPCResult::Type::STR, "status-next", "status of deployment at the next block"},
{RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",
{
{RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},
{RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},
{RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
{RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
{RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"},
}},
{RPCResult::Type::STR, "signalling", "indicates blocks that signalled with a # and blocks that did not with a -"},
}},
};

} // anon namespace


/** Comparison function for sorting the getchaintips heads. */
struct CompareBlocksByHeight
{
Expand Down
2 changes: 1 addition & 1 deletion src/versionbits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockI
if (pindex == nullptr)
return stats;

// Find beginning of period
// Find how many blocks are in the current period
const CBlockIndex* pindexEndOfPrevPeriod = pindex->GetAncestor(pindex->nHeight - ((pindex->nHeight + 1) % stats.period));
stats.elapsed = pindex->nHeight - pindexEndOfPrevPeriod->nHeight;

Expand Down
Loading