Skip to content

Commit 0f64bac

Browse files
jamesobryanofsky
andcommitted
rpc: add getchainstates
Co-authored-by: Ryan Ofsky <[email protected]>
1 parent bb05857 commit 0f64bac

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

doc/release-notes-27596.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ are always checked by hash.
2424

2525
You can find more information on this process in the `assumeutxo` design
2626
document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).
27+
28+
`getchainstates` has been added to aid in monitoring the assumeutxo sync process.

src/rpc/blockchain.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,6 +2799,79 @@ static RPCHelpMan loadtxoutset()
27992799
};
28002800
}
28012801

2802+
const std::vector<RPCResult> RPCHelpForChainstate{
2803+
{RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
2804+
{RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
2805+
{RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
2806+
{RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"},
2807+
{RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"},
2808+
{RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},
2809+
{RPCResult::Type::NUM, "coins_tip_cache_bytes", "size of the coinstip cache"},
2810+
};
2811+
2812+
static RPCHelpMan getchainstates()
2813+
{
2814+
return RPCHelpMan{
2815+
"getchainstates",
2816+
"\nReturn information about chainstates.\n",
2817+
{},
2818+
RPCResult{
2819+
RPCResult::Type::OBJ, "", "", {
2820+
{RPCResult::Type::NUM, "headers", "the number of headers seen so far"},
2821+
{RPCResult::Type::OBJ, "normal", /*optional=*/true, "fully validated chainstate containing blocks this node has validated starting from the genesis block", RPCHelpForChainstate},
2822+
{RPCResult::Type::OBJ, "snapshot", /*optional=*/true, "only present if an assumeutxo snapshot is loaded. Partially validated chainstate containing blocks this node has validated starting from the snapshot. After the snapshot is validated (when the 'normal' chainstate advances far enough to validate it), this chainstate will replace and become the 'normal' chainstate.", RPCHelpForChainstate},
2823+
}
2824+
},
2825+
RPCExamples{
2826+
HelpExampleCli("getchainstates", "")
2827+
+ HelpExampleRpc("getchainstates", "")
2828+
},
2829+
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2830+
{
2831+
LOCK(cs_main);
2832+
UniValue obj(UniValue::VOBJ);
2833+
2834+
NodeContext& node = EnsureAnyNodeContext(request.context);
2835+
ChainstateManager& chainman = *node.chainman;
2836+
2837+
auto make_chain_data = [&](const Chainstate& cs) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
2838+
AssertLockHeld(::cs_main);
2839+
UniValue data(UniValue::VOBJ);
2840+
if (!cs.m_chain.Tip()) {
2841+
return data;
2842+
}
2843+
const CChain& chain = cs.m_chain;
2844+
const CBlockIndex* tip = chain.Tip();
2845+
2846+
data.pushKV("blocks", (int)chain.Height());
2847+
data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
2848+
data.pushKV("difficulty", (double)GetDifficulty(tip));
2849+
data.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
2850+
data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
2851+
data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
2852+
if (cs.m_from_snapshot_blockhash) {
2853+
data.pushKV("snapshot_blockhash", cs.m_from_snapshot_blockhash->ToString());
2854+
}
2855+
return data;
2856+
};
2857+
2858+
if (chainman.GetAll().size() > 1) {
2859+
for (Chainstate* chainstate : chainman.GetAll()) {
2860+
obj.pushKV(
2861+
chainstate->m_from_snapshot_blockhash ? "snapshot" : "normal",
2862+
make_chain_data(*chainstate));
2863+
}
2864+
} else {
2865+
obj.pushKV("normal", make_chain_data(chainman.ActiveChainstate()));
2866+
}
2867+
obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
2868+
2869+
return obj;
2870+
}
2871+
};
2872+
}
2873+
2874+
28022875
void RegisterBlockchainRPCCommands(CRPCTable& t)
28032876
{
28042877
static const CRPCCommand commands[]{
@@ -2824,6 +2897,7 @@ void RegisterBlockchainRPCCommands(CRPCTable& t)
28242897
{"blockchain", &getblockfilter},
28252898
{"blockchain", &dumptxoutset},
28262899
{"blockchain", &loadtxoutset},
2900+
{"blockchain", &getchainstates},
28272901
{"hidden", &invalidateblock},
28282902
{"hidden", &reconsiderblock},
28292903
{"hidden", &waitfornewblock},

src/test/fuzz/rpc.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
123123
"getblockstats",
124124
"getblocktemplate",
125125
"getchaintips",
126+
"getchainstates",
126127
"getchaintxstats",
127128
"getconnectioncount",
128129
"getdeploymentinfo",

0 commit comments

Comments
 (0)