Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
91588a8
fix: annotate `getblockchaininfo[softforks]` as `OBJ_DYN`
kwvg Oct 11, 2025
a0b38e9
test: drop extra `generate`s from `wallet_signrawtransactionwithwallet`
kwvg Oct 17, 2025
8b4a1aa
merge bitcoin#23345: Drop unneeded dependencies for bitcoin-wallet tool
kwvg Oct 17, 2025
bf69eb9
merge bitcoin#23508: Add getdeploymentinfo RPC
kwvg Oct 17, 2025
9e79118
merge bitcoin#24187: Followups for getdeploymentinfo
kwvg Oct 11, 2025
780afc1
merge bitcoin#24528: rename getdeploymentinfo status-next to status_next
kwvg Oct 11, 2025
9547c59
merge bitcoin#24579: Fix getblockchaininfo/getdeploymentinfo RPC docs
kwvg Mar 16, 2022
8411522
partial bitcoin#24595: move g_versionbitscache global to ChainstateMa…
kwvg Jan 18, 2022
2b7d35b
merge bitcoin#24410: Split hashing/index `GetUTXOStats` codepaths, de…
kwvg Oct 16, 2025
34b0b25
merge bitcoin#15936: Expose settings.json methods to GUI
kwvg Apr 29, 2019
358bdfe
merge bitcoin#25748: Avoid copies in FlatSigningProvider Merge
kwvg Jul 30, 2022
b8ffa84
merge bitcoin#25863: remove unused norm_prv parameter in `descriptor_…
kwvg Oct 17, 2025
a34f9c6
merge bitcoin#24051: bitcoin-{cli,tx,util} don't need UPnP, NAT-PMP, …
kwvg Jan 12, 2022
cc73b1e
merge bitcoin#25315: Add warning on first startup if free disk space …
kwvg Oct 17, 2025
0f6e1f4
merge bitcoin#26624: Rename local variable to distinguish it from typ…
kwvg Dec 2, 2022
de5b4bf
merge bitcoin#26894: Remove redundant key_to_p2pkh call
kwvg Jan 16, 2023
908eb3d
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
17 changes: 17 additions & 0 deletions doc/release-notes-6901.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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` can currently be restored using the
configuration `-deprecatedrpc=softforks`, but this will be 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 @@ -258,6 +258,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 @@ -304,7 +305,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 @@ -526,6 +526,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 @@ -557,7 +558,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 @@ -1082,7 +1082,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 @@ -13,10 +13,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 @@ -315,28 +316,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 Down Expand Up @@ -134,10 +133,11 @@
#include <zmq/zmqrpc.h>
#endif

using kernel::CCoinsStats;
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 @@ -1937,7 +1936,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 @@ -2290,6 +2289,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()
));
}
}

// 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 @@ -2380,8 +2397,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 bitcoin.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