diff options
author | Andrew Chow <github@achow101.com> | 2022-12-05 17:38:27 -0500 |
---|---|---|
committer | Andrew Chow <github@achow101.com> | 2022-12-05 17:46:54 -0500 |
commit | 5d9b5305af4aaf9d4903d9d2996c5eea613b51a1 (patch) | |
tree | 73525029d75b2589b4452e72e4cd5f88613605a6 /src | |
parent | 2ce3d26757ed08f2e580120af9bc5e26881302a0 (diff) | |
parent | d885bb2f6ea34cd21dacfebe763a07dbb389c1bd (diff) | |
download | bitcoin-5d9b5305af4aaf9d4903d9d2996c5eea613b51a1.tar.xz |
Merge bitcoin/bitcoin#19888: rpc, test: Improve getblockstats for unspendables
d885bb2f6ea34cd21dacfebe763a07dbb389c1bd test: Test exclusion of OP_RETURN from getblockstats (Fabian Jahr)
ba9d288b2468f047e5a8e4637dd8749e247ff547 test: Fix getblockstats test data generator (Fabian Jahr)
2ca5a496c2f3cbcc63ea15fa05c1658e7f527bbc rpc: Improve getblockstats (Fabian Jahr)
cb94db119f4643f49da63520d64efc99fb0c0795 validation, index: Add unspendable coinbase helper functions (Fabian Jahr)
Pull request description:
Fixes #19885
The genesis block does not have undo data saved to disk so the RPC errored because of that.
ACKs for top commit:
achow101:
ACK d885bb2f6ea34cd21dacfebe763a07dbb389c1bd
aureleoules:
ACK d885bb2f6ea34cd21dacfebe763a07dbb389c1bd
stickies-v:
ACK d885bb2f6
Tree-SHA512: f37bda736ed605b7a41a81eeb4bfbb5d2b8518f847819e5d6a090548a61caf1455623e15165d72589ab3f4478252b00e7b624f9313ad6708cac06dd5edb62e9a
Diffstat (limited to 'src')
-rw-r--r-- | src/index/coinstatsindex.cpp | 6 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 31 | ||||
-rw-r--r-- | src/validation.cpp | 15 | ||||
-rw-r--r-- | src/validation.h | 6 |
4 files changed, 47 insertions, 11 deletions
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index d3559b1b75..271e5bb1f6 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -144,17 +144,13 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block) } } - // TODO: Deduplicate BIP30 related code - bool is_bip30_block{(block.height == 91722 && block.hash == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) || - (block.height == 91812 && block.hash == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))}; - // Add the new utxos created from the block assert(block.data); for (size_t i = 0; i < block.data->vtx.size(); ++i) { const auto& tx{block.data->vtx.at(i)}; // Skip duplicate txid coinbase transactions (BIP30). - if (is_bip30_block && tx->IsCoinBase()) { + if (IsBIP30Unspendable(*pindex) && tx->IsCoinBase()) { m_total_unspendable_amount += block_subsidy; m_total_unspendables_bip30 += block_subsidy; continue; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 90eb954153..9c8d19722b 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -601,6 +601,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)"); } @@ -1779,8 +1783,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"]')") + @@ -1811,7 +1817,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"); @@ -1833,7 +1839,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; @@ -1846,7 +1854,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; } } @@ -1888,7 +1907,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; @@ -1948,6 +1969,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/src/validation.cpp b/src/validation.cpp index 1cf6fc0675..8fdb4d0b47 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2080,8 +2080,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the // two in the chain that violate it. This prevents exploiting the issue against nodes during their // initial block download. - bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || - (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); + bool fEnforceBIP30 = !IsBIP30Repeat(*pindex); // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the @@ -5313,3 +5312,15 @@ Chainstate& ChainstateManager::ActivateExistingSnapshot(CTxMemPool* mempool, uin m_active_chainstate = m_snapshot_chainstate.get(); return *m_snapshot_chainstate; } + +bool IsBIP30Repeat(const CBlockIndex& block_index) +{ + return (block_index.nHeight==91842 && block_index.GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || + (block_index.nHeight==91880 && block_index.GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")); +} + +bool IsBIP30Unspendable(const CBlockIndex& block_index) +{ + return (block_index.nHeight==91722 && block_index.GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) || + (block_index.nHeight==91812 && block_index.GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f")); +} diff --git a/src/validation.h b/src/validation.h index b8151dc1fc..a080d12fe2 100644 --- a/src/validation.h +++ b/src/validation.h @@ -1066,4 +1066,10 @@ bool DeploymentEnabled(const ChainstateManager& chainman, DEP dep) */ const AssumeutxoData* ExpectedAssumeutxo(const int height, const CChainParams& params); +/** Identifies blocks that overwrote an existing coinbase output in the UTXO set (see BIP30) */ +bool IsBIP30Repeat(const CBlockIndex& block_index); + +/** Identifies blocks which coinbase output was subsequently overwritten in the UTXO set (see BIP30) */ +bool IsBIP30Unspendable(const CBlockIndex& block_index); + #endif // BITCOIN_VALIDATION_H |