aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
authorFabian Jahr <fjahr@protonmail.com>2020-09-06 00:22:19 +0200
committerFabian Jahr <fjahr@protonmail.com>2022-10-23 01:33:41 +0200
commit2ca5a496c2f3cbcc63ea15fa05c1658e7f527bbc (patch)
treedddf50c34e7b573be29b446d6e3e40aeaf7d563c /src/rpc
parentcb94db119f4643f49da63520d64efc99fb0c0795 (diff)
downloadbitcoin-2ca5a496c2f3cbcc63ea15fa05c1658e7f527bbc.tar.xz
rpc: Improve getblockstats
- Fix getblockstats for block height 0 which previously returned an error. - Introduce alternative utxo_*_actual statistics which exclude unspendables: Genesis block, BIP30, unspendable outputs - Update test data - Explicitly test Genesis block results
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp31
1 files changed, 27 insertions, 4 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index f8ba822f54..3adbadb9b0 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -593,6 +593,10 @@ static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblo
{
AssertLockHeld(::cs_main);
CBlockUndo blockUndo;
+
+ // The Genesis block does not have undo data
+ if (pblockindex->nHeight == 0) return blockUndo;
+
if (blockman.IsBlockPruned(pblockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
}
@@ -1771,8 +1775,10 @@ static RPCHelpMan getblockstats()
{RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"},
{RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"},
{RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"},
- {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs"},
+ {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs (not discounting op_return and similar)"},
{RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
+ {RPCResult::Type::NUM, "utxo_increase_actual", /*optional=*/true, "The increase/decrease in the number of unspent outputs, not counting unspendables"},
+ {RPCResult::Type::NUM, "utxo_size_inc_actual", /*optional=*/true, "The increase/decrease in size for the utxo index, not counting unspendables"},
}},
RPCExamples{
HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
@@ -1803,7 +1809,7 @@ static RPCHelpMan getblockstats()
const bool do_medianfee = do_all || stats.count("medianfee") != 0;
const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
- SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
+ SetHasKeys(stats, "utxo_increase", "utxo_increase_actual", "utxo_size_inc", "utxo_size_inc_actual", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
const bool do_calculate_size = do_mediantxsize ||
SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
@@ -1825,7 +1831,9 @@ static RPCHelpMan getblockstats()
int64_t swtxs = 0;
int64_t total_size = 0;
int64_t total_weight = 0;
+ int64_t utxos = 0;
int64_t utxo_size_inc = 0;
+ int64_t utxo_size_inc_actual = 0;
std::vector<CAmount> fee_array;
std::vector<std::pair<CAmount, int64_t>> feerate_array;
std::vector<int64_t> txsize_array;
@@ -1838,7 +1846,18 @@ static RPCHelpMan getblockstats()
if (loop_outputs) {
for (const CTxOut& out : tx->vout) {
tx_total_out += out.nValue;
- utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
+
+ size_t out_size = GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
+ utxo_size_inc += out_size;
+
+ // The Genesis block and the repeated BIP30 block coinbases don't change the UTXO
+ // set counts, so they have to be excluded from the statistics
+ if (pindex.nHeight == 0 || (IsBIP30Repeat(pindex) && tx->IsCoinBase())) continue;
+ // Skip unspendable outputs since they are not included in the UTXO set
+ if (out.scriptPubKey.IsUnspendable()) continue;
+
+ ++utxos;
+ utxo_size_inc_actual += out_size;
}
}
@@ -1880,7 +1899,9 @@ static RPCHelpMan getblockstats()
const CTxOut& prevoutput = coin.out;
tx_total_in += prevoutput.nValue;
- utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
+ size_t prevout_size = GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
+ utxo_size_inc -= prevout_size;
+ utxo_size_inc_actual -= prevout_size;
}
CAmount txfee = tx_total_in - tx_total_out;
@@ -1940,6 +1961,8 @@ static RPCHelpMan getblockstats()
ret_all.pushKV("txs", (int64_t)block.vtx.size());
ret_all.pushKV("utxo_increase", outputs - inputs);
ret_all.pushKV("utxo_size_inc", utxo_size_inc);
+ ret_all.pushKV("utxo_increase_actual", utxos - inputs);
+ ret_all.pushKV("utxo_size_inc_actual", utxo_size_inc_actual);
if (do_all) {
return ret_all;