From 76190489e6c89ad091ebba0781c585afc9a39f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Mon, 9 Dec 2024 13:30:04 +0100 Subject: [PATCH] coins: pack `Coin` height/coinbase consistently Serialize `Coin` metadata using the canonical (height << 1) | coinbase packing across `Coin` serialization, undo records, and coinstats hashing. Cast the 31-bit `nHeight` bitfield to `uint32_t` before shifting to avoid signed promotion undefined behaviour. --- src/coins.h | 4 ++-- src/kernel/coinstats.cpp | 2 +- src/undo.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/coins.h b/src/coins.h index e58586dd6cd..bfd6c5b0d7e 100644 --- a/src/coins.h +++ b/src/coins.h @@ -27,7 +27,7 @@ * A UTXO entry. * * Serialized format: - * - VARINT((coinbase ? 1 : 0) | (height << 1)) + * - VARINT((height << 1) | (coinbase ? 1 : 0)) * - the non-spent CTxOut (via TxOutCompression) */ class Coin @@ -62,7 +62,7 @@ public: template void Serialize(Stream &s) const { assert(!IsSpent()); - uint32_t code = nHeight * uint32_t{2} + fCoinBase; + uint32_t code{(uint32_t{nHeight} << 1) | uint32_t{fCoinBase}}; ::Serialize(s, VARINT(code)); ::Serialize(s, Using(out)); } diff --git a/src/kernel/coinstats.cpp b/src/kernel/coinstats.cpp index d287ec4be6e..53039e57101 100644 --- a/src/kernel/coinstats.cpp +++ b/src/kernel/coinstats.cpp @@ -47,7 +47,7 @@ template static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin) { ss << outpoint; - ss << static_cast((coin.nHeight << 1) + coin.fCoinBase); + ss << ((uint32_t{coin.nHeight} << 1) | uint32_t{coin.fCoinBase}); ss << coin.out; } diff --git a/src/undo.h b/src/undo.h index 5591fe6cc82..13b92349510 100644 --- a/src/undo.h +++ b/src/undo.h @@ -23,7 +23,8 @@ struct TxInUndoFormatter { template void Ser(Stream &s, const Coin& txout) { - ::Serialize(s, VARINT(txout.nHeight * uint32_t{2} + txout.fCoinBase )); + uint32_t nCode{(uint32_t{txout.nHeight} << 1) | uint32_t{txout.fCoinBase}}; + ::Serialize(s, VARINT(nCode)); if (txout.nHeight > 0) { // Required to maintain compatibility with older undo format. ::Serialize(s, (unsigned char)0);