mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
merge bitcoin#23411: Avoid integer overflow in ApplyStats when activating snapshot
This commit is contained in:
parent
a2dcf74cf4
commit
9964cbe772
@ -323,6 +323,7 @@ BITCOIN_CORE_H = \
|
||||
util/macros.h \
|
||||
util/message.h \
|
||||
util/moneystr.h \
|
||||
util/overflow.h \
|
||||
util/ranges.h \
|
||||
util/readwritefile.h \
|
||||
util/underlying.h \
|
||||
|
@ -321,7 +321,7 @@ bool CoinStatsIndex::LookUpStats(const CBlockIndex* block_index, CCoinsStats& co
|
||||
coins_stats.hashSerialized = entry.muhash;
|
||||
coins_stats.nTransactionOutputs = entry.transaction_output_count;
|
||||
coins_stats.nBogoSize = entry.bogo_size;
|
||||
coins_stats.nTotalAmount = entry.total_amount;
|
||||
coins_stats.total_amount = entry.total_amount;
|
||||
coins_stats.total_subsidy = entry.total_subsidy;
|
||||
coins_stats.total_unspendable_amount = entry.total_unspendable_amount;
|
||||
coins_stats.total_prevout_spent_amount = entry.total_prevout_spent_amount;
|
||||
|
@ -885,7 +885,9 @@ static void PeriodicStats(ArgsManager& args, const CTxMemPool& mempool)
|
||||
statsClient.gauge("utxoset.txOutputs", stats.nTransactionOutputs, 1.0f);
|
||||
statsClient.gauge("utxoset.dbSizeBytes", stats.nDiskSize, 1.0f);
|
||||
statsClient.gauge("utxoset.blockHeight", stats.nHeight, 1.0f);
|
||||
statsClient.gauge("utxoset.totalAmount", (double)stats.nTotalAmount / (double)COIN, 1.0f);
|
||||
if (stats.total_amount.has_value()) {
|
||||
statsClient.gauge("utxoset.totalAmount", (double)stats.total_amount.value() / (double)COIN, 1.0f);
|
||||
}
|
||||
} else {
|
||||
// something went wrong
|
||||
LogPrintf("%s: GetUTXOStats failed\n", __func__);
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include <index/coinstatsindex.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
// #include <util/system.h>
|
||||
#include <util/check.h>
|
||||
#include <util/overflow.h>
|
||||
#include <util/system.h>
|
||||
#include <validation.h>
|
||||
|
||||
@ -83,7 +83,9 @@ static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map<u
|
||||
stats.nTransactions++;
|
||||
for (auto it = outputs.begin(); it != outputs.end(); ++it) {
|
||||
stats.nTransactionOutputs++;
|
||||
stats.nTotalAmount += it->second.out.nValue;
|
||||
if (stats.total_amount.has_value()) {
|
||||
stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);
|
||||
}
|
||||
stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
|
||||
}
|
||||
}
|
||||
@ -94,7 +96,9 @@ static void ApplyStats(CCoinsStats& stats, std::nullptr_t, const uint256& hash,
|
||||
stats.nTransactions++;
|
||||
for (const auto& output : outputs) {
|
||||
stats.nTransactionOutputs++;
|
||||
stats.nTotalAmount += output.second.out.nValue;
|
||||
if (stats.total_amount.has_value()) {
|
||||
stats.total_amount = CheckedAdd(*stats.total_amount, output.second.out.nValue);
|
||||
}
|
||||
stats.nBogoSize += GetBogoSize(output.second.out.scriptPubKey);
|
||||
}
|
||||
}
|
||||
@ -107,11 +111,9 @@ static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats&
|
||||
assert(pcursor);
|
||||
|
||||
if (!pindex) {
|
||||
{
|
||||
LOCK(cs_main);
|
||||
assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman));
|
||||
pindex = blockman.LookupBlockIndex(view->GetBestBlock());
|
||||
}
|
||||
LOCK(cs_main);
|
||||
assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman));
|
||||
pindex = blockman.LookupBlockIndex(view->GetBestBlock());
|
||||
}
|
||||
stats.nHeight = Assert(pindex)->nHeight;
|
||||
stats.hashBlock = pindex->GetBlockHash();
|
||||
|
@ -24,9 +24,10 @@ enum class CoinStatsHashType {
|
||||
NONE,
|
||||
};
|
||||
|
||||
struct CCoinsStats
|
||||
{
|
||||
CoinStatsHashType m_hash_type;
|
||||
struct CCoinsStats {
|
||||
//! Which hash type to use
|
||||
const CoinStatsHashType m_hash_type;
|
||||
|
||||
int nHeight{0};
|
||||
uint256 hashBlock{};
|
||||
uint64_t nTransactions{0};
|
||||
@ -34,7 +35,8 @@ struct CCoinsStats
|
||||
uint64_t nBogoSize{0};
|
||||
uint256 hashSerialized{};
|
||||
uint64_t nDiskSize{0};
|
||||
CAmount nTotalAmount{0};
|
||||
//! The total amount, or nullopt if an overflow occurred calculating it
|
||||
std::optional<CAmount> total_amount{0};
|
||||
|
||||
//! The number of coins contained.
|
||||
uint64_t coins_count{0};
|
||||
|
@ -1423,9 +1423,10 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
|
||||
ret.pushKV("hash_serialized_2", stats.hashSerialized.GetHex());
|
||||
}
|
||||
if (hash_type == CoinStatsHashType::MUHASH) {
|
||||
ret.pushKV("muhash", stats.hashSerialized.GetHex());
|
||||
ret.pushKV("muhash", stats.hashSerialized.GetHex());
|
||||
}
|
||||
ret.pushKV("total_amount", ValueFromAmount(stats.nTotalAmount));
|
||||
CHECK_NONFATAL(stats.total_amount.has_value());
|
||||
ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
|
||||
if (!stats.index_used) {
|
||||
ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
|
||||
ret.pushKV("disk_size", stats.nDiskSize);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <test/fuzz/fuzz.h>
|
||||
#include <test/fuzz/util.h>
|
||||
#include <util/overflow.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <test/fuzz/fuzz.h>
|
||||
#include <test/fuzz/util.h>
|
||||
#include <util/overflow.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <uint256.h>
|
||||
#include <util/check.h>
|
||||
#include <util/moneystr.h>
|
||||
#include <util/overflow.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
#include <util/system.h>
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <test/fuzz/fuzz.h>
|
||||
#include <test/fuzz/util.h>
|
||||
#include <util/overflow.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
@ -3,6 +3,8 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <test/fuzz/util.h>
|
||||
|
||||
#include <util/overflow.h>
|
||||
#include <version.h>
|
||||
|
||||
FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <test/util/setup_common.h>
|
||||
#include <txmempool.h>
|
||||
#include <uint256.h>
|
||||
#include <util/overflow.h>
|
||||
#include <util/time.h>
|
||||
#include <util/vector.h>
|
||||
#include <version.h>
|
||||
@ -217,17 +218,6 @@ template <typename T>
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
[[ nodiscard ]] bool AdditionOverflow(const T i, const T j) noexcept
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "Integral required.");
|
||||
if (std::numeric_limits<T>::is_signed) {
|
||||
return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
|
||||
(i < 0 && j < std::numeric_limits<T>::min() - i);
|
||||
}
|
||||
return std::numeric_limits<T>::max() - i < j;
|
||||
}
|
||||
|
||||
[[ nodiscard ]] inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
|
||||
{
|
||||
for (const CTxIn& tx_in : tx.vin) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <util/getuniquepath.h>
|
||||
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
|
||||
#include <util/moneystr.h>
|
||||
#include <util/overflow.h>
|
||||
#include <util/ranges_set.h>
|
||||
#include <util/spanparsing.h>
|
||||
#include <util/strencodings.h>
|
||||
@ -1449,6 +1450,38 @@ BOOST_AUTO_TEST_CASE(test_IsDigit)
|
||||
BOOST_CHECK_EQUAL(IsDigit(9), false);
|
||||
}
|
||||
|
||||
/* Check for overflow */
|
||||
template <typename T>
|
||||
static void TestAddMatrixOverflow()
|
||||
{
|
||||
constexpr T MAXI{std::numeric_limits<T>::max()};
|
||||
BOOST_CHECK(!CheckedAdd(T{1}, MAXI));
|
||||
BOOST_CHECK(!CheckedAdd(MAXI, MAXI));
|
||||
BOOST_CHECK_EQUAL(0, CheckedAdd(T{0}, T{0}).value());
|
||||
BOOST_CHECK_EQUAL(MAXI, CheckedAdd(T{0}, MAXI).value());
|
||||
BOOST_CHECK_EQUAL(MAXI, CheckedAdd(T{1}, MAXI - 1).value());
|
||||
}
|
||||
|
||||
/* Check for overflow or underflow */
|
||||
template <typename T>
|
||||
static void TestAddMatrix()
|
||||
{
|
||||
TestAddMatrixOverflow<T>();
|
||||
constexpr T MINI{std::numeric_limits<T>::min()};
|
||||
constexpr T MAXI{std::numeric_limits<T>::max()};
|
||||
BOOST_CHECK(!CheckedAdd(T{-1}, MINI));
|
||||
BOOST_CHECK(!CheckedAdd(MINI, MINI));
|
||||
BOOST_CHECK_EQUAL(MINI, CheckedAdd(T{0}, MINI).value());
|
||||
BOOST_CHECK_EQUAL(MINI, CheckedAdd(T{-1}, MINI + 1).value());
|
||||
BOOST_CHECK_EQUAL(-1, CheckedAdd(MINI, MAXI).value());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_overflow)
|
||||
{
|
||||
TestAddMatrixOverflow<unsigned>();
|
||||
TestAddMatrix<signed>();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ParseInt32)
|
||||
{
|
||||
int32_t n;
|
||||
|
31
src/util/overflow.h
Normal file
31
src/util/overflow.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2021 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_UTIL_OVERFLOW_H
|
||||
#define BITCOIN_UTIL_OVERFLOW_H
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
template <class T>
|
||||
[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "Integral required.");
|
||||
if (std::numeric_limits<T>::is_signed) {
|
||||
return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
|
||||
(i < 0 && j < std::numeric_limits<T>::min() - i);
|
||||
}
|
||||
return std::numeric_limits<T>::max() - i < j;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
[[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept
|
||||
{
|
||||
if (AdditionOverflow(i, j)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return i + j;
|
||||
}
|
||||
|
||||
#endif // BITCOIN_UTIL_OVERFLOW_H
|
Loading…
Reference in New Issue
Block a user