Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
50d593c
fix: annotate `getblockchaininfo[softforks]` as `OBJ_DYN`
kwvg Oct 11, 2025
464ec01
test: drop extra `generate`s from `wallet_signrawtransactionwithwallet`
kwvg Oct 17, 2025
0610617
merge bitcoin#23345: Drop unneeded dependencies for bitcoin-wallet tool
kwvg Oct 17, 2025
150c47d
merge bitcoin#23508: Add getdeploymentinfo RPC
kwvg Oct 22, 2025
13b8120
rpc: drop `-deprecatedrpc=softforks` requirement.
kwvg Oct 22, 2025
bebbeb7
merge bitcoin#24187: Followups for getdeploymentinfo
kwvg Oct 11, 2025
40cfb98
merge bitcoin#24528: rename getdeploymentinfo status-next to status_next
kwvg Oct 11, 2025
8e5399b
merge bitcoin#24579: Fix getblockchaininfo/getdeploymentinfo RPC docs
kwvg Mar 16, 2022
f9078ae
partial bitcoin#24595: move g_versionbitscache global to ChainstateMa…
kwvg Oct 22, 2025
cd1d259
merge bitcoin#24410: Split hashing/index `GetUTXOStats` codepaths, de…
kwvg Oct 21, 2025
7c3bd1c
merge bitcoin#15936: Expose settings.json methods to GUI
kwvg Oct 21, 2025
7232bed
merge bitcoin#25748: Avoid copies in FlatSigningProvider Merge
kwvg Jul 30, 2022
417c1c9
merge bitcoin#25863: remove unused norm_prv parameter in `descriptor_…
kwvg Oct 17, 2025
3ffdf2b
merge bitcoin#24051: bitcoin-{cli,tx,util} don't need UPnP, NAT-PMP, …
kwvg Jan 12, 2022
75d8ec3
merge bitcoin#25315: Add warning on first startup if free disk space …
kwvg Oct 17, 2025
e8ed632
merge bitcoin#26624: Rename local variable to distinguish it from typ…
kwvg Dec 2, 2022
3f163db
merge bitcoin#26894: Remove redundant key_to_p2pkh call
kwvg Jan 16, 2023
6112563
merge bitcoin#25412: add `/deploymentinfo` endpoint
kwvg Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1502,6 +1502,12 @@ if test "$use_usdt" != "no"; then
fi
AM_CONDITIONAL([ENABLE_USDT_TRACEPOINTS], [test "$use_usdt" = "yes"])

if test "$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests" = "nononono"; then
use_upnp=no
use_natpmp=no
use_zmq=no
fi

dnl Check for libminiupnpc (optional)
if test "$use_upnp" != "no"; then
TEMP_CPPFLAGS="$CPPFLAGS"
Expand Down
9 changes: 9 additions & 0 deletions doc/REST-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ Returns various state info regarding block chain processing.
Only supports JSON as output format.
Refer to the `getblockchaininfo` RPC help for details.

#### Deployment info
`GET /rest/deploymentinfo.json`
`GET /rest/deploymentinfo/<BLOCKHASH>.json`

Returns an object containing various state info regarding deployments of
consensus changes at the current chain tip, or at <BLOCKHASH> if provided.
Only supports JSON as output format.
Refer to the `getdeploymentinfo` RPC help for details.

#### Query UTXO set
- `GET /rest/getutxos/<TXID>-<N>/<TXID>-<N>/.../<TXID>-<N>.<bin|hex|json>`
- `GET /rest/getutxos/checkmempool/<TXID>-<N>/<TXID>-<N>/.../<TXID>-<N>.<bin|hex|json>`
Expand Down
16 changes: 16 additions & 0 deletions doc/release-notes-6901.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Updated RPCs
------------

- Information on soft fork status has been moved from `getblockchaininfo`
to the new `getdeploymentinfo` RPC which allows querying soft fork status at any
block, rather than just at the chain tip. Inclusion of soft fork
status in `getblockchaininfo` is currently available but this will be
restricted or removed in a future release. Note that in either case, the
`status` field now reflects the status of the current block rather than
the next block.

New REST endpoint
-----------------

- A new `/rest/deploymentinfo` endpoint has been added for fetching various
state info regarding deployments of consensus changes.
20 changes: 17 additions & 3 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ BITCOIN_CORE_H = \
instantsend/instantsend.h \
instantsend/lock.h \
instantsend/signing.h \
kernel/coinstats.h \
key.h \
key_io.h \
limitedmap.h \
Expand Down Expand Up @@ -305,7 +306,6 @@ BITCOIN_CORE_H = \
node/caches.h \
node/chainstate.h \
node/coin.h \
node/coinstats.h \
node/connection_types.h \
node/context.h \
node/eviction.h \
Expand Down Expand Up @@ -529,6 +529,7 @@ libbitcoin_node_a_SOURCES = \
instantsend/instantsend.cpp \
instantsend/lock.cpp \
instantsend/signing.cpp \
kernel/coinstats.cpp \
llmq/blockprocessor.cpp \
llmq/commitment.cpp \
llmq/context.cpp \
Expand Down Expand Up @@ -560,7 +561,6 @@ libbitcoin_node_a_SOURCES = \
node/caches.cpp \
node/chainstate.cpp \
node/coin.cpp \
node/coinstats.cpp \
node/connection_types.cpp \
node/context.cpp \
node/eviction.cpp \
Expand Down Expand Up @@ -1086,7 +1086,21 @@ dash_wallet_SOURCES = bitcoin-wallet.cpp
dash_wallet_CPPFLAGS = $(bitcoin_bin_cppflags)
dash_wallet_CXXFLAGS = $(bitcoin_bin_cxxflags)
dash_wallet_LDFLAGS = $(bitcoin_bin_ldflags)
dash_wallet_LDADD = $(LIBBITCOIN_WALLET_TOOL) $(bitcoin_bin_ldadd)
dash_wallet_LDADD = \
$(LIBBITCOIN_WALLET_TOOL) \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBDASHBLS) \
$(LIBSECP256K1) \
$(BACKTRACE_LIB) \
$(BOOST_LIBS) \
$(BDB_LIBS) \
$(SQLITE_LIBS) \
$(GMP_LIBS)

if TARGET_WINDOWS
dash_wallet_SOURCES += dash-wallet-res.rc
Expand Down
44 changes: 24 additions & 20 deletions src/index/coinstatsindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
#include <validation.h>
#include <util/check.h>

using node::CCoinsStats;
using node::GetBogoSize;
using kernel::CCoinsStats;
using kernel::GetBogoSize;
using kernel::TxOutSer;

using node::ReadBlockFromDisk;
using node::TxOutSer;
using node::UndoReadFromDisk;

static constexpr uint8_t DB_BLOCK_HASH{'s'};
Expand Down Expand Up @@ -316,28 +317,31 @@ static bool LookUpOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVa
return db.Read(DBHashKey(block_index->GetBlockHash()), result);
}

bool CoinStatsIndex::LookUpStats(const CBlockIndex* block_index, CCoinsStats& coins_stats) const
std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_index) const
{
CCoinsStats stats{Assert(block_index)->nHeight, block_index->GetBlockHash()};
stats.index_used = true;

DBVal entry;
if (!LookUpOne(*m_db, block_index, entry)) {
return false;
return std::nullopt;
}

coins_stats.hashSerialized = entry.muhash;
coins_stats.nTransactionOutputs = entry.transaction_output_count;
coins_stats.nBogoSize = entry.bogo_size;
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;
coins_stats.total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount;
coins_stats.total_coinbase_amount = entry.total_coinbase_amount;
coins_stats.total_unspendables_genesis_block = entry.total_unspendables_genesis_block;
coins_stats.total_unspendables_bip30 = entry.total_unspendables_bip30;
coins_stats.total_unspendables_scripts = entry.total_unspendables_scripts;
coins_stats.total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards;

return true;
stats.hashSerialized = entry.muhash;
stats.nTransactionOutputs = entry.transaction_output_count;
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;
stats.total_unspendables_genesis_block = entry.total_unspendables_genesis_block;
stats.total_unspendables_bip30 = entry.total_unspendables_bip30;
stats.total_unspendables_scripts = entry.total_unspendables_scripts;
stats.total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards;

return stats;
}

bool CoinStatsIndex::Init()
Expand Down
4 changes: 2 additions & 2 deletions src/index/coinstatsindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <crypto/muhash.h>
#include <flatfile.h>
#include <index/base.h>
#include <node/coinstats.h>
#include <kernel/coinstats.h>

/**
* CoinStatsIndex maintains statistics on the UTXO set.
Expand Down Expand Up @@ -56,7 +56,7 @@ class CoinStatsIndex final : public BaseIndex
explicit CoinStatsIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false);

// Look up stats for a specific block using CBlockIndex
bool LookUpStats(const CBlockIndex* block_index, node::CCoinsStats& coins_stats) const;
std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex* block_index) const;
};

/// The global UTXO set hash object.
Expand Down
45 changes: 30 additions & 15 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include <context.h>
#include <consensus/amount.h>
#include <deploymentstatus.h>
#include <node/coinstats.h>
#include <fs.h>
#include <hash.h>
#include <httpserver.h>
Expand All @@ -32,6 +31,7 @@
#include <interfaces/init.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
#include <kernel/coinstats.h>
#include <mapport.h>
#include <node/miner.h>
#include <net.h>
Expand Down Expand Up @@ -134,10 +134,10 @@
#include <zmq/zmqrpc.h>
#endif

using kernel::CoinStatsHashType;

using node::CacheSizes;
using node::CalculateCacheSizes;
using node::CCoinsStats;
using node::CoinStatsHashType;
using node::ChainstateLoadingError;
using node::ChainstateLoadVerifyError;
using node::DashChainstateSetupClose;
Expand Down Expand Up @@ -430,7 +430,6 @@ void Shutdown(NodeContext& node)
LogPrintf("%s: Unable to remove PID file: %s\n", __func__, fsbridge::get_filesystem_error_message(e));
}

node.args = nullptr;
LogPrintf("%s: done\n", __func__);
}

Expand Down Expand Up @@ -831,15 +830,15 @@ static void PeriodicStats(NodeContext& node)
ChainstateManager& chainman = *Assert(node.chainman);
const CTxMemPool& mempool = *Assert(node.mempool);
const llmq::CInstantSendManager& isman = *Assert(node.llmq_ctx->isman);
CCoinsStats stats{CoinStatsHashType::NONE};
chainman.ActiveChainstate().ForceFlushStateToDisk();
if (WITH_LOCK(cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, stats, node.rpc_interruption_point, chainman.ActiveChain().Tip()))) {
::g_stats_client->gauge("utxoset.tx", stats.nTransactions, 1.0f);
::g_stats_client->gauge("utxoset.txOutputs", stats.nTransactionOutputs, 1.0f);
::g_stats_client->gauge("utxoset.dbSizeBytes", stats.nDiskSize, 1.0f);
::g_stats_client->gauge("utxoset.blockHeight", stats.nHeight, 1.0f);
if (stats.total_amount.has_value()) {
::g_stats_client->gauge("utxoset.totalAmount", (double)stats.total_amount.value() / (double)COIN, 1.0f);
const auto maybe_stats = WITH_LOCK(::cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, /*hash_type=*/CoinStatsHashType::NONE, node.rpc_interruption_point, chainman.ActiveChain().Tip(), /*index_requested=*/true));
if (maybe_stats.has_value()) {
::g_stats_client->gauge("utxoset.tx", maybe_stats->nTransactions, 1.0f);
::g_stats_client->gauge("utxoset.txOutputs", maybe_stats->nTransactionOutputs, 1.0f);
::g_stats_client->gauge("utxoset.dbSizeBytes", maybe_stats->nDiskSize, 1.0f);
::g_stats_client->gauge("utxoset.blockHeight", maybe_stats->nHeight, 1.0f);
if (maybe_stats->total_amount.has_value()) {
::g_stats_client->gauge("utxoset.totalAmount", (double)maybe_stats->total_amount.value() / (double)COIN, 1.0f);
}
} else {
// something went wrong
Expand Down Expand Up @@ -1936,7 +1935,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), mempool_check_ratio);

node.chainman = std::make_unique<ChainstateManager>();
node.chainman = std::make_unique<ChainstateManager>(chainparams);
ChainstateManager& chainman = *node.chainman;

/**
Expand Down Expand Up @@ -2289,6 +2288,24 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return false;
}

int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height());

// On first startup, warn on low block storage space
if (!fReindex && !fReindexChainState && chain_active_height <= 1) {
uint64_t additional_bytes_needed = fPruneMode ? nPruneTarget
: chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024;

if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {
InitWarning(strprintf(_(
"Disk space for %s may not accommodate the block files. " \
"Approximately %u GB of data will be stored in this directory."
),
fs::quoted(fs::PathToString(args.GetBlocksDirPath())),
chainparams.AssumedBlockchainSize()
));
}
}
Comment on lines +2291 to +2307
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix first‑startup disk‑space warning for -prune=1.

For manual prune (-prune=1) nPruneTarget == UINT64_MAX, so this branch always warns. Use the smaller of nPruneTarget and AssumedBlockchainSize().

-    // On first startup, warn on low block storage space
+    // On first startup, warn on low block storage space
     if (!fReindex && !fReindexChainState && chain_active_height <= 1) {
-        uint64_t additional_bytes_needed = fPruneMode ? nPruneTarget
-            : chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024;
+        const uint64_t approx_chain_bytes =
+            static_cast<uint64_t>(chainparams.AssumedBlockchainSize()) * 1024 * 1024 * 1024;
+        uint64_t additional_bytes_needed =
+            fPruneMode ? std::min(nPruneTarget, approx_chain_bytes) : approx_chain_bytes;
 
-        if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {
-            InitWarning(strprintf(_(
-                    "Disk space for %s may not accommodate the block files. " \
-                    "Approximately %u GB of data will be stored in this directory."
-                ),
-                fs::quoted(fs::PathToString(args.GetBlocksDirPath())),
-                chainparams.AssumedBlockchainSize()
-            ));
-        }
+        if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {
+            InitWarning(strprintf(_("Disk space for %s may not accommodate the block files. Approximately %u GB of data will be stored in this directory."),
+                fs::quoted(fs::PathToString(args.GetBlocksDirPath())),
+                chainparams.AssumedBlockchainSize()));
+        }
     }
🤖 Prompt for AI Agents
In src/init.cpp around lines 2291-2307, the first-startup disk-space warning
uses nPruneTarget directly when fPruneMode is true, but nPruneTarget ==
UINT64_MAX for manual prune (-prune=1) so the code always warns; compute the
assumed blockchain size in bytes (chainparams.AssumedBlockchainSize() * 1024 *
1024 * 1024) and when fPruneMode is true set additional_bytes_needed to the
smaller of nPruneTarget and that assumed size (use std::min), otherwise use the
assumed size; keep the displayed GB value as
chainparams.AssumedBlockchainSize().


// Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.
// No locking, as this happens before any background thread is started.
boost::signals2::connection block_notify_genesis_wait_connection;
Expand Down Expand Up @@ -2379,8 +2396,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)

// ********************************************************* Step 12: start node

int chain_active_height;

//// debug print
{
LOCK(cs_main);
Expand Down
29 changes: 24 additions & 5 deletions src/interfaces/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
#ifndef BITCOIN_INTERFACES_NODE_H
#define BITCOIN_INTERFACES_NODE_H

#include <consensus/amount.h> // For CAmount
#include <net.h> // For NodeId
#include <net_types.h> // For banmap_t
#include <netaddress.h> // For Network
#include <netbase.h> // For ConnectionDirection
#include <consensus/amount.h> // For CAmount
#include <net.h> // For NodeId
#include <net_types.h> // For banmap_t
#include <netaddress.h> // For Network
#include <netbase.h> // For ConnectionDirection
#include <support/allocators/secure.h> // For SecureString
#include <uint256.h>
#include <util/settings.h> // For util::SettingsValue
#include <util/translation.h>

#include <functional>
Expand Down Expand Up @@ -193,6 +194,24 @@ class Node
//! Return whether shutdown was requested.
virtual bool shutdownRequested() = 0;

//! Return whether a particular setting in <datadir>/settings.json is or
//! would be ignored because it is also specified in the command line.
virtual bool isSettingIgnored(const std::string& name) = 0;

//! Return setting value from <datadir>/settings.json or dash.conf.
virtual util::SettingsValue getPersistentSetting(const std::string& name) = 0;

//! Update a setting in <datadir>/settings.json.
virtual void updateRwSetting(const std::string& name, const util::SettingsValue& value) = 0;

//! Force a setting value to be applied, overriding any other configuration
//! source, but not being persisted.
virtual void forceSetting(const std::string& name, const util::SettingsValue& value) = 0;

//! Clear all settings in <datadir>/settings.json and store a backup of
//! previous settings in <datadir>/settings.json.bak.
virtual void resetSettings() = 0;

//! Map port.
virtual void mapPort(bool use_upnp, bool use_natpmp) = 0;

Expand Down
Loading
Loading