Merge bitcoin/bitcoin#31449: coins,refactor: Reduce getblockstats RPC UTXO overhead estimation

5f36e0ff1e rpc: fix getblockstats UTXO overhead accounting (Lőrinc)
76190489e6 coins: pack `Coin` height/coinbase consistently (Lőrinc)
1f309d1aa2 coins: make `Coin::fCoinBase` a bool (Lőrinc)

Pull request description:

  The [`getblockstats` RPC](https://github.com/bitcoin/bitcoin/pull/10757) currently overestimates UTXO overhead by treating the `fCoinBase` bitfield as an additional `bool` in `PER_UTXO_OVERHEAD`.
  However, `fCoinBase` and `nHeight` are stored as bitfields and effectively packed into a single 32-bit value; counting an extra bool in the overhead calculation is unnecessary.

  This PR introduces the following changes across three commits:
  * Store `fCoinBase` as a `bool` bitfield to reduce implicit conversions at call sites.
  * Use a consistent height/coinbase packing style across `Coin` serialization, undo serialization, and coinstats hashing (casting `nHeight` to `uint32_t` before shifting to avoid signed-promotion UB).
  * Adjust UTXO overhead estimation to match the actual `Coin` layout and update the related tests accordingly.

ACKs for top commit:
  achow101:
    ACK 5f36e0ff1e
  sedited:
    ACK 5f36e0ff1e
  vasild:
    ACK 5f36e0ff1e
  optout21:
    crACK 5f36e0ff1e

Tree-SHA512: f4a44debed358e9e130da9d6fae5f89289daa34f0bdb7155edc3e9b691c219451f4c80b1e16aca5b011f0fa2fa975484ef1af4ca4563b7c6ba4ca9dd133f30be
This commit is contained in:
Ava Chow
2026-04-20 15:52:45 -07:00
10 changed files with 26 additions and 25 deletions

View File

@@ -524,7 +524,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
// Good example
Coin cc1;
SpanReader{"97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"_hex} >> cc1;
BOOST_CHECK_EQUAL(cc1.fCoinBase, false);
BOOST_CHECK_EQUAL(cc1.IsCoinBase(), false);
BOOST_CHECK_EQUAL(cc1.nHeight, 203998U);
BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000});
BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("816115944e077fe7c803cfa57f29b36bf87c1d35"_hex_u8)))));
@@ -532,7 +532,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
// Good example
Coin cc2;
SpanReader{"8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex} >> cc2;
BOOST_CHECK_EQUAL(cc2.fCoinBase, true);
BOOST_CHECK_EQUAL(cc2.IsCoinBase(), true);
BOOST_CHECK_EQUAL(cc2.nHeight, 120891U);
BOOST_CHECK_EQUAL(cc2.out.nValue, 110397);
BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex_u8)))));
@@ -540,7 +540,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
// Smallest possible example
Coin cc3;
SpanReader{"000006"_hex} >> cc3;
BOOST_CHECK_EQUAL(cc3.fCoinBase, false);
BOOST_CHECK_EQUAL(cc3.IsCoinBase(), false);
BOOST_CHECK_EQUAL(cc3.nHeight, 0U);
BOOST_CHECK_EQUAL(cc3.out.nValue, 0);
BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0U);
@@ -880,7 +880,7 @@ Coin MakeCoin()
Coin coin;
coin.out.nValue = m_rng.rand32();
coin.nHeight = m_rng.randrange(4096);
coin.fCoinBase = 0;
coin.fCoinBase = false;
return coin;
}

View File

@@ -138,7 +138,7 @@ void utxo_snapshot_fuzz(FuzzBufferType buffer)
outfile << coinbase->GetHash();
WriteCompactSize(outfile, 1); // number of coins for the hash
WriteCompactSize(outfile, 0); // index of coin
outfile << Coin(coinbase->vout[0], height, /*fCoinBaseIn=*/1);
outfile << Coin(coinbase->vout[0], height, /*fCoinBaseIn=*/true);
height++;
}
}
@@ -150,7 +150,7 @@ void utxo_snapshot_fuzz(FuzzBufferType buffer)
outfile << coinbase->GetHash();
WriteCompactSize(outfile, 1); // number of coins for the hash
WriteCompactSize(outfile, 999); // index of coin
outfile << Coin{coinbase->vout[0], /*nHeightIn=*/999, /*fCoinBaseIn=*/0};
outfile << Coin{coinbase->vout[0], /*nHeightIn=*/999, /*fCoinBaseIn=*/false};
}
assert(outfile.fclose() == 0);
}