diff options
author | Fabian Jahr <fjahr@protonmail.com> | 2020-09-06 00:22:19 +0200 |
---|---|---|
committer | Fabian Jahr <fjahr@protonmail.com> | 2022-10-23 01:33:41 +0200 |
commit | 2ca5a496c2f3cbcc63ea15fa05c1658e7f527bbc (patch) | |
tree | dddf50c34e7b573be29b446d6e3e40aeaf7d563c | |
parent | cb94db119f4643f49da63520d64efc99fb0c0795 (diff) |
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
-rw-r--r-- | src/rpc/blockchain.cpp | 31 | ||||
-rw-r--r-- | test/functional/data/rpc_getblockstats.json | 14 | ||||
-rwxr-xr-x | test/functional/rpc_getblockstats.py | 8 |
3 files changed, 45 insertions, 8 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; diff --git a/test/functional/data/rpc_getblockstats.json b/test/functional/data/rpc_getblockstats.json index 16dbc5fe60..487945dd9f 100644 --- a/test/functional/data/rpc_getblockstats.json +++ b/test/functional/data/rpc_getblockstats.json @@ -142,7 +142,9 @@ "totalfee": 0, "txs": 1, "utxo_increase": 2, - "utxo_size_inc": 163 + "utxo_increase_actual": 1, + "utxo_size_inc": 163, + "utxo_size_inc_actual": 75 }, { "avgfee": 4460, @@ -179,7 +181,9 @@ "totalfee": 4460, "txs": 2, "utxo_increase": 3, - "utxo_size_inc": 236 + "utxo_increase_actual": 2, + "utxo_size_inc": 236, + "utxo_size_inc_actual": 148 }, { "avgfee": 24906, @@ -216,7 +220,9 @@ "totalfee": 74720, "txs": 4, "utxo_increase": 5, - "utxo_size_inc": 384 + "utxo_size_inc": 384, + "utxo_increase_actual": 4, + "utxo_size_inc_actual": 296 } ] -}
\ No newline at end of file +} diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py index 1ea1ee5659..1372cf95da 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -161,6 +161,14 @@ class GetblockstatsTest(BitcoinTestFramework): assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats, '00', 1, 2) assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats) + self.log.info('Test block height 0') + genesis_stats = self.nodes[0].getblockstats(0) + assert_equal(genesis_stats["blockhash"], "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206") + assert_equal(genesis_stats["utxo_increase"], 1) + assert_equal(genesis_stats["utxo_size_inc"], 117) + assert_equal(genesis_stats["utxo_increase_actual"], 0) + assert_equal(genesis_stats["utxo_size_inc_actual"], 0) + if __name__ == '__main__': GetblockstatsTest().main() |