index: Fix coinstatsindex overflow issue
What changed, and why it matters
This commit fixes an integer overflow bug in Bitcoin Core's optional coin statistics index. The index keeps running totals of spent and created coins, and on long-running or high-activity networks these totals could exceed the range of the 64-bit 'CAmount' type, causing wrong statistics or node instability. The fix widens the at-risk totals to a 256-bit type and removes a redundant stored total that can be computed from other values. It also changes the index's database directory name so upgraded nodes do not reuse the old, buggy data, while leaving the old directory in place for users who might downgrade.
Nodes that use -coinstatsindex=1 should upgrade to the fixed version. After upgrading, the old indexes/coinstats directory can be removed once the user is sure they will not downgrade to v29 or earlier. Operators relying on gettxoutsetinfo RPC output should be aware that the on-disk index format and directory changed, and that the index will be rebuilt under the new path.
Security signals we found
Integer overflow in cumulative monetary totals (CAmount overflow observed on Signet)
Data-format change requiring a new database directory to avoid loading legacy overflowed state
Removal of redundant total_unspendable_amount accumulator to reduce consistency risk
RevertBlock integrity checks replaced with direct DB state restoration, lowering rollback error surface
Evidence from the diff
The coinstatsindex previously accumulated total_prevout_spent_amount, total_new_outputs_ex_coinbase_amount, and total_coinbase_amount in CAmount (int64_t). On Signet these cumulative values overflowed. The patch changes the in-memory and on-disk representation of those three fields to arith_uint256, serializing them as uint256. It also removes the redundant total_unspendable_amount field, deriving it from the four unspendable categories. RevertBlock is simplified: instead of manually reversing every arithmetic delta, it now rolls back only the MuHash and then copies the prior block’s stored totals from the DB. The index path moves from indexes/coinstats to indexes/coinstatsindex to avoid loading corrupted/overflowed legacy data; a warning is logged if the old directory exists. RPC output is adjusted to compute per-block differences from the wider types and to reconstruct total_unspendable_amount on the fly.
Changed components
src/index/coinstatsindex.cppsrc/index/coinstatsindex.hsrc/kernel/coinstats.hsrc/rpc/blockchain.cppdoc/files.mdtest/functional/feature_init.pyInspect captured patch +98 / −94
diff --git a/doc/files.md b/doc/files.md
index 0bf115e1..c8d8aab3 100644
--- a/doc/files.md
+++ b/doc/files.md
@@ -57,7 +57,7 @@ Subdirectory | File(s) | Description
`indexes/txindex/` | LevelDB database | Transaction index; *optional*, used if `-txindex=1`
`indexes/blockfilter/basic/db/` | LevelDB database | Blockfilter index LevelDB database for the basic filtertype; *optional*, used if `-blockfilterindex=basic`
`indexes/blockfilter/basic/` | `fltrNNNNN.dat`<sup>[\[2\]](#note2)</sup> | Blockfilter index filters for the basic filtertype; *optional*, used if `-blockfilterindex=basic`
-`indexes/coinstats/db/` | LevelDB database | Coinstats index; *optional*, used if `-coinstatsindex=1`
+`indexes/coinstatsindex/db/` | LevelDB database | Coinstats index; *optional*, used if `-coinstatsindex=1`
`wallets/` | | [Contains wallets](#multi-wallet-environment); can be specified by `-walletdir` option; if `wallets/` subdirectory does not exist, wallets reside in the [data directory](#data-directory-location)
`./` | `anchors.dat` | Anchor IP address database, created on shutdown and deleted at startup. Anchors are last known outgoing block-relay-only peers that are tried to re-connect to on startup
`./` | `banlist.json` | Stores the addresses/subnets of banned nodes.
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index 48d4c749..bb4be90b 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <arith_uint256.h>
#include <chainparams.h>
#include <coins.h>
#include <common/args.h>
@@ -27,35 +28,42 @@ static constexpr uint8_t DB_MUHASH{'M'};
namespace {
struct DBVal {
- uint256 muhash;
- uint64_t transaction_output_count;
- uint64_t bogo_size;
- CAmount total_amount;
- CAmount total_subsidy;
- CAmount total_unspendable_amount;
- CAmount total_prevout_spent_amount;
- CAmount total_new_outputs_ex_coinbase_amount;
- CAmount total_coinbase_amount;
- CAmount total_unspendables_genesis_block;
- CAmount total_unspendables_bip30;
- CAmount total_unspendables_scripts;
- CAmount total_unspendables_unclaimed_rewards;
+ uint256 muhash{uint256::ZERO};
+ uint64_t transaction_output_count{0};
+ uint64_t bogo_size{0};
+ CAmount total_amount{0};
+ CAmount total_subsidy{0};
+ arith_uint256 total_prevout_spent_amount{0};
+ arith_uint256 total_new_outputs_ex_coinbase_amount{0};
+ arith_uint256 total_coinbase_amount{0};
+ CAmount total_unspendables_genesis_block{0};
+ CAmount total_unspendables_bip30{0};
+ CAmount total_unspendables_scripts{0};
+ CAmount total_unspendables_unclaimed_rewards{0};
SERIALIZE_METHODS(DBVal, obj)
{
+ uint256 prevout_spent, new_outputs, coinbase;
+ SER_WRITE(obj, prevout_spent = ArithToUint256(obj.total_prevout_spent_amount));
+ SER_WRITE(obj, new_outputs = ArithToUint256(obj.total_new_outputs_ex_coinbase_amount));
+ SER_WRITE(obj, coinbase = ArithToUint256(obj.total_coinbase_amount));
+
READWRITE(obj.muhash);
READWRITE(obj.transaction_output_count);
READWRITE(obj.bogo_size);
READWRITE(obj.total_amount);
READWRITE(obj.total_subsidy);
- READWRITE(obj.total_unspendable_amount);
- READWRITE(obj.total_prevout_spent_amount);
- READWRITE(obj.total_new_outputs_ex_coinbase_amount);
- READWRITE(obj.total_coinbase_amount);
+ READWRITE(prevout_spent);
+ READWRITE(new_outputs);
+ READWRITE(coinbase);
READWRITE(obj.total_unspendables_genesis_block);
READWRITE(obj.total_unspendables_bip30);
READWRITE(obj.total_unspendables_scripts);
READWRITE(obj.total_unspendables_unclaimed_rewards);
+
+ SER_READ(obj, obj.total_prevout_spent_amount = UintToArith256(prevout_spent));
+ SER_READ(obj, obj.total_new_outputs_ex_coinbase_amount = UintToArith256(new_outputs));
+ SER_READ(obj, obj.total_coinbase_amount = UintToArith256(coinbase));
}
};
@@ -106,7 +114,17 @@ std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
: BaseIndex(std::move(chain), "coinstatsindex")
{
- fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
+ // An earlier version of the index used "indexes/coinstats" but it contained
+ // a bug and is superseded by a fixed version at "indexes/coinstatsindex".
+ // The original index is kept around until the next release in case users
+ // decide to downgrade their node.
+ auto old_path = gArgs.GetDataDirNet() / "indexes" / "coinstats";
+ if (fs::exists(old_path)) {
+ // TODO: Change this to deleting the old index with v31.
+ LogWarning("Old version of coinstatsindex found at %s. This folder can be safely deleted unless you " \
+ "plan to downgrade your node to version 29 or lower.", fs::PathToString(old_path));
+ }
+ fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstatsindex"};
fs::create_directories(path);
m_db = std::make_unique<CoinStatsIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
@@ -144,7 +162,6 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
// Skip duplicate txid coinbase transactions (BIP30).
if (is_coinbase && IsBIP30Unspendable(block.hash, block.height)) {
- m_total_unspendable_amount += block_subsidy;
m_total_unspendables_bip30 += block_subsidy;
continue;
}
@@ -156,7 +173,6 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
// Skip unspendable coins
if (coin.out.scriptPubKey.IsUnspendable()) {
- m_total_unspendable_amount += coin.out.nValue;
m_total_unspendables_scripts += coin.out.nValue;
continue;
}
@@ -179,7 +195,7 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
const auto& tx_undo{Assert(block.undo_data)->vtxundo.at(i - 1)};
for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
- const Coin coin{tx_undo.vprevout[j]};
+ const Coin& coin{tx_undo.vprevout[j]};
const COutPoint outpoint{tx->vin[j].prevout.hash, tx->vin[j].prevout.n};
RemoveCoinHash(m_muhash, outpoint, coin);
@@ -194,7 +210,6 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
}
} else {
// genesis block
- m_total_unspendable_amount += block_subsidy;
m_total_unspendables_genesis_block += block_subsidy;
}
@@ -202,9 +217,10 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
// new outputs + coinbase + current unspendable amount this means
// the miner did not claim the full block reward. Unclaimed block
// rewards are also unspendable.
- const CAmount unclaimed_rewards{(m_total_prevout_spent_amount + m_total_subsidy) - (m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + m_total_unspendable_amount)};
- m_total_unspendable_amount += unclaimed_rewards;
- m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
+ const CAmount temp_total_unspendable_amount{m_total_unspendables_genesis_block + m_total_unspendables_bip30 + m_total_unspendables_scripts + m_total_unspendables_unclaimed_rewards};
+ const arith_uint256 unclaimed_rewards{(m_total_prevout_spent_amount + m_total_subsidy) - (m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + temp_total_unspendable_amount)};
+ assert(unclaimed_rewards <= arith_uint256(std::numeric_limits<CAmount>::max()));
+ m_total_unspendables_unclaimed_rewards += static_cast<CAmount>(unclaimed_rewards.GetLow64());
std::pair<uint256, DBVal> value;
value.first = block.hash;
@@ -212,7 +228,6 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
value.second.bogo_size = m_bogo_size;
value.second.total_amount = m_total_amount;
value.second.total_subsidy = m_total_subsidy;
- value.second.total_unspendable_amount = m_total_unspendable_amount;
value.second.total_prevout_spent_amount = m_total_prevout_spent_amount;
value.second.total_new_outputs_ex_coinbase_amount = m_total_new_outputs_ex_coinbase_amount;
value.second.total_coinbase_amount = m_total_coinbase_amount;
@@ -307,7 +322,6 @@ std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex& block_
stats.nBogoSize = entry.bogo_size;
stats.total_amount = entry.total_amount;
stats.total_subsidy = entry.total_subsidy;
- stats.total_unspendable_amount = entry.total_unspendable_amount;
stats.total_prevout_spent_amount = entry.total_prevout_spent_amount;
stats.total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount;
stats.total_coinbase_amount = entry.total_coinbase_amount;
@@ -352,7 +366,6 @@ bool CoinStatsIndex::CustomInit(const std::optional<interfaces::BlockRef>& block
m_bogo_size = entry.bogo_size;
m_total_amount = entry.total_amount;
m_total_subsidy = entry.total_subsidy;
- m_total_unspendable_amount = entry.total_unspendable_amount;
m_total_prevout_spent_amount = entry.total_prevout_spent_amount;
m_total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount;
m_total_coinbase_amount = entry.total_coinbase_amount;
@@ -387,9 +400,6 @@ bool CoinStatsIndex::RevertBlock(const interfaces::BlockInfo& block)
{
std::pair<uint256, DBVal> read_out;
- const CAmount block_subsidy{GetBlockSubsidy(block.height, Params().GetConsensus())};
- m_total_subsidy -= block_subsidy;
-
// Ignore genesis block
if (block.height > 0) {
if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
@@ -409,7 +419,8 @@ bool CoinStatsIndex::RevertBlock(const interfaces::BlockInfo& block)
}
}
- // Remove the new UTXOs that were created from the block
+ // Roll back muhash by removing the new UTXOs that were created by the
+ // block and reapplying the old UTXOs that were spent by the block
assert(block.data);
assert(block.undo_data);
for (size_t i = 0; i < block.data->vtx.size(); ++i) {
@@ -421,24 +432,9 @@ bool CoinStatsIndex::RevertBlock(const interfaces::BlockInfo& block)
const COutPoint outpoint{tx->GetHash(), j};
const Coin coin{out, block.height, is_coinbase};
- // Skip unspendable coins
- if (coin.out.scriptPubKey.IsUnspendable()) {
- m_total_unspendable_amount -= coin.out.nValue;
- m_total_unspendables_scripts -= coin.out.nValue;
- continue;
+ if (!coin.out.scriptPubKey.IsUnspendable()) {
+ RemoveCoinHash(m_muhash, outpoint, coin);
}
-
- RemoveCoinHash(m_muhash, outpoint, coin);
-
- if (tx->IsCoinBase()) {
- m_total_coinbase_amount -= coin.out.nValue;
- } else {
- m_total_new_outputs_ex_coinbase_amount -= coin.out.nValue;
- }
-
- --m_transaction_output_count;
- m_total_amount -= coin.out.nValue;
- m_bogo_size -= GetBogoSize(coin.out.scriptPubKey);
}
// The coinbase tx has no undo data since no former output is spent
@@ -446,40 +442,30 @@ bool CoinStatsIndex::RevertBlock(const interfaces::BlockInfo& block)
const auto& tx_undo{block.undo_data->vtxundo.at(i - 1)};
for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
- const Coin coin{tx_undo.vprevout[j]};
+ const Coin& coin{tx_undo.vprevout[j]};
const COutPoint outpoint{tx->vin[j].prevout.hash, tx->vin[j].prevout.n};
ApplyCoinHash(m_muhash, outpoint, coin);
-
- m_total_prevout_spent_amount -= coin.out.nValue;
-
- m_transaction_output_count++;
- m_total_amount += coin.out.nValue;
- m_bogo_size += GetBogoSize(coin.out.scriptPubKey);
}
}
}
- const CAmount unclaimed_rewards{(m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + m_total_unspendable_amount) - (m_total_prevout_spent_amount + m_total_subsidy)};
- m_total_unspendable_amount -= unclaimed_rewards;
- m_total_unspendables_unclaimed_rewards -= unclaimed_rewards;
-
- // Check that the rolled back internal values are consistent with the DB read out
+ // Check that the rolled back muhash is consistent with the DB read out
uint256 out;
m_muhash.Finalize(out);
Assert(read_out.second.muhash == out);
- Assert(m_transaction_output_count == read_out.second.transaction_output_count);
- Assert(m_total_amount == read_out.second.total_amount);
- Assert(m_bogo_size == read_out.second.bogo_size);
- Assert(m_total_subsidy == read_out.second.total_subsidy);
- Assert(m_total_unspendable_amount == read_out.second.total_unspendable_amount);
- Assert(m_total_prevout_spent_amount == read_out.second.total_prevout_spent_amount);
- Assert(m_total_new_outputs_ex_coinbase_amount == read_out.second.total_new_outputs_ex_coinbase_amount);
- Assert(m_total_coinbase_amount == read_out.second.total_coinbase_amount);
- Assert(m_total_unspendables_genesis_block == read_out.second.total_unspendables_genesis_block);
- Assert(m_total_unspendables_bip30 == read_out.second.total_unspendables_bip30);
- Assert(m_total_unspendables_scripts == read_out.second.total_unspendables_scripts);
- Assert(m_total_unspendables_unclaimed_rewards == read_out.second.total_unspendables_unclaimed_rewards);
+ // Apply the other values from the DB to the member variables
+ m_transaction_output_count = read_out.second.transaction_output_count;
+ m_total_amount = read_out.second.total_amount;
+ m_bogo_size = read_out.second.bogo_size;
+ m_total_subsidy = read_out.second.total_subsidy;
+ m_total_prevout_spent_amount = read_out.second.total_prevout_spent_amount;
+ m_total_new_outputs_ex_coinbase_amount = read_out.second.total_new_outputs_ex_coinbase_amount;
+ m_total_coinbase_amount = read_out.second.total_coinbase_amount;
+ m_total_unspendables_genesis_block = read_out.second.total_unspendables_genesis_block;
+ m_total_unspendables_bip30 = read_out.second.total_unspendables_bip30;
+ m_total_unspendables_scripts = read_out.second.total_unspendables_scripts;
+ m_total_unspendables_unclaimed_rewards = read_out.second.total_unspendables_unclaimed_rewards;
return true;
}
diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h
index f2e95b44..5dcbc186 100644
--- a/src/index/coinstatsindex.h
+++ b/src/index/coinstatsindex.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_INDEX_COINSTATSINDEX_H
#define BITCOIN_INDEX_COINSTATSINDEX_H
+#include <arith_uint256.h>
#include <crypto/muhash.h>
#include <index/base.h>
@@ -29,10 +30,9 @@ private:
uint64_t m_bogo_size{0};
CAmount m_total_amount{0};
CAmount m_total_subsidy{0};
- CAmount m_total_unspendable_amount{0};
- CAmount m_total_prevout_spent_amount{0};
- CAmount m_total_new_outputs_ex_coinbase_amount{0};
- CAmount m_total_coinbase_amount{0};
+ arith_uint256 m_total_prevout_spent_amount{0};
+ arith_uint256 m_total_new_outputs_ex_coinbase_amount{0};
+ arith_uint256 m_total_coinbase_amount{0};
CAmount m_total_unspendables_genesis_block{0};
CAmount m_total_unspendables_bip30{0};
CAmount m_total_unspendables_scripts{0};
diff --git a/src/kernel/coinstats.h b/src/kernel/coinstats.h
index c0c363a8..8a782ed5 100644
--- a/src/kernel/coinstats.h
+++ b/src/kernel/coinstats.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_KERNEL_COINSTATS_H
#define BITCOIN_KERNEL_COINSTATS_H
+#include <arith_uint256.h>
#include <consensus/amount.h>
#include <crypto/muhash.h>
#include <streams.h>
@@ -50,14 +51,6 @@ struct CCoinsStats {
//! Total cumulative amount of block subsidies up to and including this block
CAmount total_subsidy{0};
- //! Total cumulative amount of unspendable coins up to and including this block
- CAmount total_unspendable_amount{0};
- //! Total cumulative amount of prevouts spent up to and including this block
- CAmount total_prevout_spent_amount{0};
- //! Total cumulative amount of outputs created up to and including this block
- CAmount total_new_outputs_ex_coinbase_amount{0};
- //! Total cumulative amount of coinbase outputs up to and including this block
- CAmount total_coinbase_amount{0};
//! The unspendable coinbase amount from the genesis block
CAmount total_unspendables_genesis_block{0};
//! The two unspendable coinbase outputs total amount caused by BIP30
@@ -67,6 +60,15 @@ struct CCoinsStats {
//! Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block
CAmount total_unspendables_unclaimed_rewards{0};
+ // Despite containing amounts the following values use a uint256 type to prevent overflowing
+
+ //! Total cumulative amount of prevouts spent up to and including this block
+ arith_uint256 total_prevout_spent_amount{0};
+ //! Total cumulative amount of outputs created up to and including this block
+ arith_uint256 total_new_outputs_ex_coinbase_amount{0};
+ //! Total cumulative amount of coinbase outputs up to and including this block
+ arith_uint256 total_coinbase_amount{0};
+
CCoinsStats() = default;
CCoinsStats(int block_height, const uint256& block_hash);
};
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index cfc0379f..bd5deedf 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1101,8 +1101,6 @@ static RPCHelpMan gettxoutsetinfo()
ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
ret.pushKV("disk_size", stats.nDiskSize);
} else {
- ret.pushKV("total_unspendable_amount", ValueFromAmount(stats.total_unspendable_amount));
-
CCoinsStats prev_stats{};
if (pindex->nHeight > 0) {
const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex->pprev, index_requested);
@@ -1112,11 +1110,29 @@ static RPCHelpMan gettxoutsetinfo()
prev_stats = maybe_prev_stats.value();
}
+ CAmount block_total_unspendable_amount = stats.total_unspendables_genesis_block +
+ stats.total_unspendables_bip30 +
+ stats.total_unspendables_scripts +
+ stats.total_unspendables_unclaimed_rewards;
+ CAmount prev_block_total_unspendable_amount = prev_stats.total_unspendables_genesis_block +
+ prev_stats.total_unspendables_bip30 +
+ prev_stats.total_unspendables_scripts +
+ prev_stats.total_unspendables_unclaimed_rewards;
+
+ ret.pushKV("total_unspendable_amount", ValueFromAmount(block_total_unspendable_amount));
+
UniValue block_info(UniValue::VOBJ);
- block_info.pushKV("prevout_spent", ValueFromAmount(stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount));
- block_info.pushKV("coinbase", ValueFromAmount(stats.total_coinbase_amount - prev_stats.total_coinbase_amount));
- block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount));
- block_info.pushKV("unspendable", ValueFromAmount(stats.total_unspendable_amount - prev_stats.total_unspendable_amount));
+ // These per-block values should fit uint64 under normal circumstances
+ arith_uint256 diff_prevout = stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount;
+ arith_uint256 diff_coinbase = stats.total_coinbase_amount - prev_stats.total_coinbase_amount;
+ arith_uint256 diff_outputs = stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount;
+ CAmount prevout_amount = static_cast<CAmount>(diff_prevout.GetLow64());
+ CAmount coinbase_amount = static_cast<CAmount>(diff_coinbase.GetLow64());
+ CAmount outputs_amount = static_cast<CAmount>(diff_outputs.GetLow64());
+ block_info.pushKV("prevout_spent", ValueFromAmount(prevout_amount));
+ block_info.pushKV("coinbase", ValueFromAmount(coinbase_amount));
+ block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(outputs_amount));
+ block_info.pushKV("unspendable", ValueFromAmount(block_total_unspendable_amount - prev_block_total_unspendable_amount));
UniValue unspendables(UniValue::VOBJ);
unspendables.pushKV("genesis_block", ValueFromAmount(stats.total_unspendables_genesis_block - prev_stats.total_unspendables_genesis_block));
diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py
index a7b7e0c6..b9d41a97 100755
--- a/test/functional/feature_init.py
+++ b/test/functional/feature_init.py
@@ -128,7 +128,7 @@ class InitTest(BitcoinTestFramework):
'startup_args': ['-txindex=1'],
},
# Removing these files does not result in a startup error:
- # 'indexes/blockfilter/basic/*.dat', 'indexes/blockfilter/basic/db/*.*', 'indexes/coinstats/db/*.*',
+ # 'indexes/blockfilter/basic/*.dat', 'indexes/blockfilter/basic/db/*.*', 'indexes/coinstatsindex/db/*.*',
# 'indexes/txindex/*.log', 'indexes/txindex/CURRENT', 'indexes/txindex/LOCK'
]
@@ -154,7 +154,7 @@ class InitTest(BitcoinTestFramework):
'startup_args': ['-blockfilterindex=1'],
},
{
- 'filepath_glob': 'indexes/coinstats/db/*.*',
+ 'filepath_glob': 'indexes/coinstatsindex/db/*.*',
'error_message': 'LevelDB error: Corruption',
'startup_args': ['-coinstatsindex=1'],
},
Why this scored 57/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.