Skip to content

Commit e31cdb0

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#23411: refactor: Avoid integer overflow in ApplyStats when activating snapshot
fa996c5 refactor: Avoid integer overflow in ApplyStats when activating snapshot (MarcoFalke) fac0188 Move AdditionOverflow to util, Add CheckedAdd with unit tests (MarcoFalke) fa526d8 Add dev doc to CCoinsStats::m_hash_type and make it const (MarcoFalke) faff051 style: Remove unused whitespace (MarcoFalke) Pull request description: A snapshot contains the utxo set, including the out value. To activate the snapshot, the hash needs to be calculated. As a side-effect, the total amount in the snapshot is calculated (as the sum of all out values), but never used. Instead of running into an integer overflow in an unused result, don't calculate the result in the first place. Other code paths (using the active utxo set) can not run into an integer overflow, since the active utxo set is valid. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=39716 ACKs for top commit: shaavan: reACK fa996c5 vasild: ACK fa996c5 Tree-SHA512: 4f207f634841f6f634fd02ae1e5907e343fd767524fd0e8149aa99fa9a1834fe50167d14874834d45236e9c325d567925f28129bacb7d80be29cf22277a16a14
2 parents e00e990 + fa996c5 commit e31cdb0

File tree

13 files changed

+86
-23
lines changed

13 files changed

+86
-23
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ BITCOIN_CORE_H = \
248248
util/macros.h \
249249
util/message.h \
250250
util/moneystr.h \
251+
util/overflow.h \
251252
util/overloaded.h \
252253
util/rbf.h \
253254
util/readwritefile.h \

src/index/coinstatsindex.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ bool CoinStatsIndex::LookUpStats(const CBlockIndex* block_index, CCoinsStats& co
321321
coins_stats.hashSerialized = entry.muhash;
322322
coins_stats.nTransactionOutputs = entry.transaction_output_count;
323323
coins_stats.nBogoSize = entry.bogo_size;
324-
coins_stats.nTotalAmount = entry.total_amount;
324+
coins_stats.total_amount = entry.total_amount;
325325
coins_stats.total_subsidy = entry.total_subsidy;
326326
coins_stats.total_unspendable_amount = entry.total_unspendable_amount;
327327
coins_stats.total_prevout_spent_amount = entry.total_prevout_spent_amount;

src/node/coinstats.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <index/coinstatsindex.h>
1212
#include <serialize.h>
1313
#include <uint256.h>
14+
#include <util/overflow.h>
1415
#include <util/system.h>
1516
#include <validation.h>
1617

@@ -82,7 +83,9 @@ static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map<u
8283
stats.nTransactions++;
8384
for (auto it = outputs.begin(); it != outputs.end(); ++it) {
8485
stats.nTransactionOutputs++;
85-
stats.nTotalAmount += it->second.out.nValue;
86+
if (stats.total_amount.has_value()) {
87+
stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);
88+
}
8689
stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
8790
}
8891
}
@@ -95,10 +98,8 @@ static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats&
9598
assert(pcursor);
9699

97100
if (!pindex) {
98-
{
99-
LOCK(cs_main);
100-
pindex = blockman.LookupBlockIndex(view->GetBestBlock());
101-
}
101+
LOCK(cs_main);
102+
pindex = blockman.LookupBlockIndex(view->GetBestBlock());
102103
}
103104
stats.nHeight = Assert(pindex)->nHeight;
104105
stats.hashBlock = pindex->GetBlockHash();

src/node/coinstats.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,19 @@ enum class CoinStatsHashType {
2424
NONE,
2525
};
2626

27-
struct CCoinsStats
28-
{
29-
CoinStatsHashType m_hash_type;
27+
struct CCoinsStats {
28+
//! Which hash type to use
29+
const CoinStatsHashType m_hash_type;
30+
3031
int nHeight{0};
3132
uint256 hashBlock{};
3233
uint64_t nTransactions{0};
3334
uint64_t nTransactionOutputs{0};
3435
uint64_t nBogoSize{0};
3536
uint256 hashSerialized{};
3637
uint64_t nDiskSize{0};
37-
CAmount nTotalAmount{0};
38+
//! The total amount, or nullopt if an overflow occurred calculating it
39+
std::optional<CAmount> total_amount{0};
3840

3941
//! The number of coins contained.
4042
uint64_t coins_count{0};

src/rpc/blockchain.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,9 +1274,10 @@ static RPCHelpMan gettxoutsetinfo()
12741274
ret.pushKV("hash_serialized_2", stats.hashSerialized.GetHex());
12751275
}
12761276
if (hash_type == CoinStatsHashType::MUHASH) {
1277-
ret.pushKV("muhash", stats.hashSerialized.GetHex());
1277+
ret.pushKV("muhash", stats.hashSerialized.GetHex());
12781278
}
1279-
ret.pushKV("total_amount", ValueFromAmount(stats.nTotalAmount));
1279+
CHECK_NONFATAL(stats.total_amount.has_value());
1280+
ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
12801281
if (!stats.index_used) {
12811282
ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
12821283
ret.pushKV("disk_size", stats.nDiskSize);

src/test/fuzz/addition_overflow.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <test/fuzz/FuzzedDataProvider.h>
66
#include <test/fuzz/fuzz.h>
77
#include <test/fuzz/util.h>
8+
#include <util/overflow.h>
89

910
#include <cstdint>
1011
#include <string>

src/test/fuzz/crypto_chacha20_poly1305_aead.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <test/fuzz/FuzzedDataProvider.h>
88
#include <test/fuzz/fuzz.h>
99
#include <test/fuzz/util.h>
10+
#include <util/overflow.h>
1011

1112
#include <cassert>
1213
#include <cstdint>

src/test/fuzz/integer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <univalue.h>
2727
#include <util/check.h>
2828
#include <util/moneystr.h>
29+
#include <util/overflow.h>
2930
#include <util/strencodings.h>
3031
#include <util/string.h>
3132
#include <util/system.h>

src/test/fuzz/pow.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <test/fuzz/FuzzedDataProvider.h>
1010
#include <test/fuzz/fuzz.h>
1111
#include <test/fuzz/util.h>
12+
#include <util/overflow.h>
1213

1314
#include <cstdint>
1415
#include <optional>

src/test/fuzz/util.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <pubkey.h>
99
#include <test/fuzz/util.h>
1010
#include <test/util/script.h>
11+
#include <util/overflow.h>
1112
#include <util/rbf.h>
1213
#include <util/time.h>
1314
#include <version.h>

0 commit comments

Comments
 (0)