This commit is contained in:
l0rinc 2025-04-29 11:58:39 +02:00 committed by GitHub
commit 8053358e0a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 26 additions and 25 deletions

View file

@ -26,7 +26,7 @@
* A UTXO entry. * A UTXO entry.
* *
* Serialized format: * Serialized format:
* - VARINT((coinbase ? 1 : 0) | (height << 1)) * - VARINT((height << 1) | (coinbase ? 1 : 0))
* - the non-spent CTxOut (via TxOutCompression) * - the non-spent CTxOut (via TxOutCompression)
*/ */
class Coin class Coin
@ -36,7 +36,7 @@ public:
CTxOut out; CTxOut out;
//! whether containing transaction was a coinbase //! whether containing transaction was a coinbase
unsigned int fCoinBase : 1; bool fCoinBase : 1;
//! at which height this containing transaction was included in the active block chain //! at which height this containing transaction was included in the active block chain
uint32_t nHeight : 31; uint32_t nHeight : 31;
@ -61,7 +61,7 @@ public:
template<typename Stream> template<typename Stream>
void Serialize(Stream &s) const { void Serialize(Stream &s) const {
assert(!IsSpent()); assert(!IsSpent());
uint32_t code = nHeight * uint32_t{2} + fCoinBase; uint32_t code{static_cast<uint32_t>(nHeight << 1) | fCoinBase};
::Serialize(s, VARINT(code)); ::Serialize(s, VARINT(code));
::Serialize(s, Using<TxOutCompression>(out)); ::Serialize(s, Using<TxOutCompression>(out));
} }

View file

@ -219,7 +219,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry
ScriptToUniv(prev_txout.scriptPubKey, /*out=*/o_script_pub_key, /*include_hex=*/true, /*include_address=*/true); ScriptToUniv(prev_txout.scriptPubKey, /*out=*/o_script_pub_key, /*include_hex=*/true, /*include_address=*/true);
UniValue p(UniValue::VOBJ); UniValue p(UniValue::VOBJ);
p.pushKV("generated", bool(prev_coin.fCoinBase)); p.pushKV("generated", prev_coin.IsCoinBase());
p.pushKV("height", uint64_t(prev_coin.nHeight)); p.pushKV("height", uint64_t(prev_coin.nHeight));
p.pushKV("value", ValueFromAmount(prev_txout.nValue)); p.pushKV("value", ValueFromAmount(prev_txout.nValue));
p.pushKV("scriptPubKey", std::move(o_script_pub_key)); p.pushKV("scriptPubKey", std::move(o_script_pub_key));

View file

@ -51,7 +51,7 @@ template <typename T>
static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin) static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin)
{ {
ss << outpoint; ss << outpoint;
ss << static_cast<uint32_t>((coin.nHeight << 1) + coin.fCoinBase); ss << (static_cast<uint32_t>(coin.nHeight << 1) | coin.fCoinBase);
ss << coin.out; ss << coin.out;
} }

View file

@ -1179,7 +1179,7 @@ static RPCHelpMan gettxout()
UniValue o(UniValue::VOBJ); UniValue o(UniValue::VOBJ);
ScriptToUniv(coin->out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true); ScriptToUniv(coin->out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
ret.pushKV("scriptPubKey", std::move(o)); ret.pushKV("scriptPubKey", std::move(o));
ret.pushKV("coinbase", (bool)coin->fCoinBase); ret.pushKV("coinbase", coin->IsCoinBase());
return ret; return ret;
}, },
@ -1857,8 +1857,8 @@ static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&
return (set.count(key) != 0) || SetHasKeys(set, args...); return (set.count(key) != 0) || SetHasKeys(set, args...);
} }
// outpoint (needed for the utxo index) + nHeight + fCoinBase // outpoint (needed for the utxo index) + nHeight|fCoinBase
static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool); static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t);
static RPCHelpMan getblockstats() static RPCHelpMan getblockstats()
{ {

View file

@ -514,7 +514,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
DataStream ss1{"97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"_hex}; DataStream ss1{"97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"_hex};
Coin cc1; Coin cc1;
ss1 >> cc1; ss1 >> cc1;
BOOST_CHECK_EQUAL(cc1.fCoinBase, false); BOOST_CHECK_EQUAL(cc1.IsCoinBase(), false);
BOOST_CHECK_EQUAL(cc1.nHeight, 203998U); BOOST_CHECK_EQUAL(cc1.nHeight, 203998U);
BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000}); BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000});
BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("816115944e077fe7c803cfa57f29b36bf87c1d35"_hex_u8))))); BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("816115944e077fe7c803cfa57f29b36bf87c1d35"_hex_u8)))));
@ -523,7 +523,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
DataStream ss2{"8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex}; DataStream ss2{"8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex};
Coin cc2; Coin cc2;
ss2 >> cc2; ss2 >> cc2;
BOOST_CHECK_EQUAL(cc2.fCoinBase, true); BOOST_CHECK_EQUAL(cc2.IsCoinBase(), true);
BOOST_CHECK_EQUAL(cc2.nHeight, 120891U); BOOST_CHECK_EQUAL(cc2.nHeight, 120891U);
BOOST_CHECK_EQUAL(cc2.out.nValue, 110397); BOOST_CHECK_EQUAL(cc2.out.nValue, 110397);
BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex_u8))))); BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex_u8)))));
@ -532,7 +532,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
DataStream ss3{"000006"_hex}; DataStream ss3{"000006"_hex};
Coin cc3; Coin cc3;
ss3 >> cc3; ss3 >> cc3;
BOOST_CHECK_EQUAL(cc3.fCoinBase, false); BOOST_CHECK_EQUAL(cc3.IsCoinBase(), false);
BOOST_CHECK_EQUAL(cc3.nHeight, 0U); BOOST_CHECK_EQUAL(cc3.nHeight, 0U);
BOOST_CHECK_EQUAL(cc3.out.nValue, 0); BOOST_CHECK_EQUAL(cc3.out.nValue, 0);
BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0U); BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0U);
@ -870,7 +870,7 @@ Coin MakeCoin()
Coin coin; Coin coin;
coin.out.nValue = m_rng.rand32(); coin.out.nValue = m_rng.rand32();
coin.nHeight = m_rng.randrange(4096); coin.nHeight = m_rng.randrange(4096);
coin.fCoinBase = 0; coin.fCoinBase = false;
return coin; return coin;
} }

View file

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

View file

@ -23,7 +23,8 @@ struct TxInUndoFormatter
{ {
template<typename Stream> template<typename Stream>
void Ser(Stream &s, const Coin& txout) { void Ser(Stream &s, const Coin& txout) {
::Serialize(s, VARINT(txout.nHeight * uint32_t{2} + txout.fCoinBase )); uint32_t nCode{static_cast<uint32_t>(txout.nHeight << 1) | txout.fCoinBase};
::Serialize(s, VARINT(nCode));
if (txout.nHeight > 0) { if (txout.nHeight > 0) {
// Required to maintain compatibility with older undo format. // Required to maintain compatibility with older undo format.
::Serialize(s, (unsigned char)0); ::Serialize(s, (unsigned char)0);

View file

@ -2334,7 +2334,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
COutPoint out(hash, o); COutPoint out(hash, o);
Coin coin; Coin coin;
bool is_spent = view.SpendCoin(out, &coin); bool is_spent = view.SpendCoin(out, &coin);
if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) { if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.IsCoinBase()) {
if (!is_bip30_exception) { if (!is_bip30_exception) {
fClean = false; // transaction output mismatch fClean = false; // transaction output mismatch
} }

View file

@ -143,8 +143,8 @@
"txs": 1, "txs": 1,
"utxo_increase": 2, "utxo_increase": 2,
"utxo_increase_actual": 1, "utxo_increase_actual": 1,
"utxo_size_inc": 163, "utxo_size_inc": 161,
"utxo_size_inc_actual": 75 "utxo_size_inc_actual": 74
}, },
{ {
"avgfee": 4440, "avgfee": 4440,
@ -182,8 +182,8 @@
"txs": 2, "txs": 2,
"utxo_increase": 3, "utxo_increase": 3,
"utxo_increase_actual": 2, "utxo_increase_actual": 2,
"utxo_size_inc": 235, "utxo_size_inc": 232,
"utxo_size_inc_actual": 147 "utxo_size_inc_actual": 145
}, },
{ {
"avgfee": 21390, "avgfee": 21390,
@ -221,8 +221,8 @@
"txs": 5, "txs": 5,
"utxo_increase": 6, "utxo_increase": 6,
"utxo_increase_actual": 4, "utxo_increase_actual": 4,
"utxo_size_inc": 441, "utxo_size_inc": 435,
"utxo_size_inc_actual": 300 "utxo_size_inc_actual": 296
} }
] ]
} }

View file

@ -171,16 +171,16 @@ class GetblockstatsTest(BitcoinTestFramework):
genesis_stats = self.nodes[0].getblockstats(0) genesis_stats = self.nodes[0].getblockstats(0)
assert_equal(genesis_stats["blockhash"], "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206") assert_equal(genesis_stats["blockhash"], "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")
assert_equal(genesis_stats["utxo_increase"], 1) assert_equal(genesis_stats["utxo_increase"], 1)
assert_equal(genesis_stats["utxo_size_inc"], 117) assert_equal(genesis_stats["utxo_size_inc"], 116)
assert_equal(genesis_stats["utxo_increase_actual"], 0) assert_equal(genesis_stats["utxo_increase_actual"], 0)
assert_equal(genesis_stats["utxo_size_inc_actual"], 0) assert_equal(genesis_stats["utxo_size_inc_actual"], 0)
self.log.info('Test tip including OP_RETURN') self.log.info('Test tip including OP_RETURN')
tip_stats = self.nodes[0].getblockstats(tip) tip_stats = self.nodes[0].getblockstats(tip)
assert_equal(tip_stats["utxo_increase"], 6) assert_equal(tip_stats["utxo_increase"], 6)
assert_equal(tip_stats["utxo_size_inc"], 441) assert_equal(tip_stats["utxo_size_inc"], 435)
assert_equal(tip_stats["utxo_increase_actual"], 4) assert_equal(tip_stats["utxo_increase_actual"], 4)
assert_equal(tip_stats["utxo_size_inc_actual"], 300) assert_equal(tip_stats["utxo_size_inc_actual"], 296)
self.log.info("Test when only header is known") self.log.info("Test when only header is known")
block = self.generateblock(self.nodes[0], output="raw(55)", transactions=[], submit=False) block = self.generateblock(self.nodes[0], output="raw(55)", transactions=[], submit=False)