Merge bitcoin/bitcoin#35452: [30.x] 30.3rc1

d52747d8e7 doc: update manual pages for v30.3rc1 (fanquake)
a1406d6333 build: bump version to v30.3rc1 (fanquake)
1bdd2b1334 doc: update release notes for v30.3rc1 (fanquake)
e7c6d391ef fuzz: Remove unused g_setup pointers (MarcoFalke)
b7c7d1ea28 coins: compact chainstate in background (Lőrinc)
992b1dd39f validation: randomly compact chainstate (Lőrinc)
55ead701a3 coins: test chainstate flush baseline (Lőrinc)
d09bd0f402 lint: disable leveldb subtree check (fanquake)

Pull request description:

  Backports:
  * #34918
  * #35465

  Final changes for v`30.3rc1`.

  Backports since `30.2`:
  * #34283
  * #34459
  * #34689
  * #34754
  * #34805
  * #34856
  * #35211
  * #35232

ACKs for top commit:
  sedited:
    ACK d52747d8e7
  marcofleon:
    ACK d52747d8e7

Tree-SHA512: 75fb64f744a0689a9bc4f5a25128bf2aaad7459d7a430f552200b995498428d89de28820f477780f95e7e8485eea9f657ad5fdeae253940df4f29bf51346b4ff
This commit is contained in:
merge-script
2026-06-23 19:46:02 +02:00
18 changed files with 145 additions and 41 deletions

View File

@@ -28,9 +28,9 @@ get_directory_property(precious_variables CACHE_VARIABLES)
#=============================
set(CLIENT_NAME "Bitcoin Core")
set(CLIENT_VERSION_MAJOR 30)
set(CLIENT_VERSION_MINOR 2)
set(CLIENT_VERSION_MINOR 3)
set(CLIENT_VERSION_BUILD 0)
set(CLIENT_VERSION_RC 0)
set(CLIENT_VERSION_RC 1)
set(CLIENT_VERSION_IS_RELEASE "true")
set(COPYRIGHT_YEAR "2026")

View File

@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-CLI "1" "January 2026" "bitcoin-cli v30.2.0" "User Commands"
.TH BITCOIN-CLI "1" "June 2026" "bitcoin-cli v30.3.0rc1" "User Commands"
.SH NAME
bitcoin-cli \- manual page for bitcoin-cli v30.2.0
bitcoin-cli \- manual page for bitcoin-cli v30.3.0rc1
.SH SYNOPSIS
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,<command> \/\fR[\fI\,params\/\fR]
@@ -15,7 +15,7 @@ bitcoin-cli \- manual page for bitcoin-cli v30.2.0
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,help <command>\/\fR
.SH DESCRIPTION
Bitcoin Core RPC client version v30.2.0
Bitcoin Core RPC client version v30.3.0rc1
.PP
The bitcoin\-cli utility provides a command line interface to interact with a Bitcoin Core RPC server.
.PP

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-QT "1" "January 2026" "bitcoin-qt v30.2.0" "User Commands"
.TH BITCOIN-QT "1" "June 2026" "bitcoin-qt v30.3.0rc1" "User Commands"
.SH NAME
bitcoin-qt \- manual page for bitcoin-qt v30.2.0
bitcoin-qt \- manual page for bitcoin-qt v30.3.0rc1
.SH SYNOPSIS
.B bitcoin-qt
[\fI\,options\/\fR] [\fI\,URI\/\fR]
.SH DESCRIPTION
Bitcoin Core version v30.2.0
Bitcoin Core version v30.3.0rc1
.PP
The bitcoin\-qt application provides a graphical interface for interacting with Bitcoin Core.
.PP

View File

@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-TX "1" "January 2026" "bitcoin-tx v30.2.0" "User Commands"
.TH BITCOIN-TX "1" "June 2026" "bitcoin-tx v30.3.0rc1" "User Commands"
.SH NAME
bitcoin-tx \- manual page for bitcoin-tx v30.2.0
bitcoin-tx \- manual page for bitcoin-tx v30.3.0rc1
.SH SYNOPSIS
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,<hex-tx> \/\fR[\fI\,commands\/\fR]
@@ -9,7 +9,7 @@ bitcoin-tx \- manual page for bitcoin-tx v30.2.0
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR]
.SH DESCRIPTION
Bitcoin Core bitcoin\-tx utility version v30.2.0
Bitcoin Core bitcoin\-tx utility version v30.3.0rc1
.PP
The bitcoin\-tx tool is used for creating and modifying bitcoin transactions.
.PP

View File

@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-UTIL "1" "January 2026" "bitcoin-util v30.2.0" "User Commands"
.TH BITCOIN-UTIL "1" "June 2026" "bitcoin-util v30.3.0rc1" "User Commands"
.SH NAME
bitcoin-util \- manual page for bitcoin-util v30.2.0
bitcoin-util \- manual page for bitcoin-util v30.3.0rc1
.SH SYNOPSIS
.B bitcoin-util
[\fI\,options\/\fR] [\fI\,command\/\fR]
@@ -9,7 +9,7 @@ bitcoin-util \- manual page for bitcoin-util v30.2.0
.B bitcoin-util
[\fI\,options\/\fR] \fI\,grind <hex-block-header>\/\fR
.SH DESCRIPTION
Bitcoin Core bitcoin\-util utility version v30.2.0
Bitcoin Core bitcoin\-util utility version v30.3.0rc1
.PP
The bitcoin\-util tool provides bitcoin related functionality that does not rely on the ability to access a running node. Available [commands] are listed below.
.SH OPTIONS

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-WALLET "1" "January 2026" "bitcoin-wallet v30.2.0" "User Commands"
.TH BITCOIN-WALLET "1" "June 2026" "bitcoin-wallet v30.3.0rc1" "User Commands"
.SH NAME
bitcoin-wallet \- manual page for bitcoin-wallet v30.2.0
bitcoin-wallet \- manual page for bitcoin-wallet v30.3.0rc1
.SH SYNOPSIS
.B bitcoin-wallet
[\fI\,options\/\fR] \fI\,<command>\/\fR
.SH DESCRIPTION
Bitcoin Core bitcoin\-wallet utility version v30.2.0
Bitcoin Core bitcoin\-wallet utility version v30.3.0rc1
.PP
bitcoin\-wallet is an offline tool for creating and interacting with Bitcoin Core wallet files.
.PP

View File

@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN "1" "January 2026" "bitcoin v30.2.0" "User Commands"
.TH BITCOIN "1" "June 2026" "bitcoin v30.3.0rc1" "User Commands"
.SH NAME
bitcoin \- manual page for bitcoin v30.2.0
bitcoin \- manual page for bitcoin v30.3.0rc1
.SH SYNOPSIS
.B bitcoin
[\fI\,OPTIONS\/\fR] \fI\,COMMAND\/\fR...

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIND "1" "January 2026" "bitcoind v30.2.0" "User Commands"
.TH BITCOIND "1" "June 2026" "bitcoind v30.3.0rc1" "User Commands"
.SH NAME
bitcoind \- manual page for bitcoind v30.2.0
bitcoind \- manual page for bitcoind v30.3.0rc1
.SH SYNOPSIS
.B bitcoind
[\fI\,options\/\fR]
.SH DESCRIPTION
Bitcoin Core daemon version v30.2.0 bitcoind
Bitcoin Core daemon version v30.3.0rc1 bitcoind
.PP
The Bitcoin Core daemon (bitcoind) is a headless program that connects to the Bitcoin network to validate and relay transactions and blocks, as well as relaying addresses.
.PP

View File

@@ -1,9 +1,9 @@
v30.x Release Notes
v30.3rc1 Release Notes
===================
Bitcoin Core version v30.x is now available from:
Bitcoin Core version v30.3rc1 is now available from:
<https://bitcoincore.org/bin/bitcoin-core-30.x/>
<https://bitcoincore.org/bin/bitcoin-core-30.3/test.rc1/>
This release includes new features, various bug fixes and performance
improvements, as well as updated translations.
@@ -40,10 +40,14 @@ unsupported systems.
Notable changes
===============
This release fixes an issue where the chainstate database would repeatedly
rewrite large portions of itself, causing excessive disk reads and writes
during normal operation.
### Validation
- #35209 validation: correct lifetime of precomputed tx data
- #35465 coins: compact chainstate regularly
### Leveldb
@@ -92,6 +96,7 @@ Notable changes
- #34608 test: Fix broken --valgrind handling after bitcoin wrapper
- #34690 test: Add missing timeout_factor to zmq socket
- #34869 tests: applied PYTHON_GIL to the env for every test
- #34918 fuzz: [refactor] Remove unused g_setup pointers
- #35080 test: Add missing self.options.timeout_factor scale in tool_bitcoin_chainstate.py
### Util

View File

@@ -245,7 +245,7 @@ CDBWrapper::CDBWrapper(const DBParams& params)
if (params.options.force_compact) {
LogInfo("Starting database compaction of %s", fs::PathToString(params.path));
DBContext().pdb->CompactRange(nullptr, nullptr);
CompactFull();
LogInfo("Finished database compaction of %s", fs::PathToString(params.path));
}
@@ -291,11 +291,18 @@ bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
return true;
}
std::optional<std::string> CDBWrapper::GetProperty(const std::string& property) const
{
if (std::string value; DBContext().pdb->GetProperty(property, &value)) return value;
return std::nullopt;
}
void CDBWrapper::CompactFull() { DBContext().pdb->CompactRange(nullptr, nullptr); }
size_t CDBWrapper::DynamicMemoryUsage() const
{
std::string memory;
std::optional<size_t> parsed;
if (!DBContext().pdb->GetProperty("leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral<size_t>(memory))) {
if (auto memory{GetProperty("leveldb.approximate-memory-usage")}; !memory || !(parsed = ToIntegral<size_t>(*memory))) {
LogDebug(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n");
return 0;
}

View File

@@ -264,6 +264,12 @@ public:
bool WriteBatch(CDBBatch& batch, bool fSync = false);
//! Perform a blocking full compaction of the underlying LevelDB.
void CompactFull();
//! Return a LevelDB property value, if available.
std::optional<std::string> GetProperty(const std::string& property) const;
// Get an estimate of LevelDB memory usage (in bytes).
size_t DynamicMemoryUsage() const;

View File

@@ -12,6 +12,7 @@
#include <txdb.h>
#include <uint256.h>
#include <undo.h>
#include <util/check.h>
#include <util/strencodings.h>
#include <map>
@@ -1060,6 +1061,30 @@ BOOST_FIXTURE_TEST_CASE(ccoins_flush_behavior, FlushTest)
}
}
BOOST_FIXTURE_TEST_CASE(coins_db_leveldb_layout, FlushTest)
{
auto level2_files{[](CCoinsViewDB& base) {
return *Assert(ToIntegral<int>(*Assert(base.GetDBProperty("leveldb.num-files-at-level2"))));
}};
const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), 0};
const Coin coin{MakeCoin()};
const uint256 block_hash{m_rng.rand256()};
CCoinsViewDB base{{.path = m_args.GetDataDirBase() / "coins_db_leveldb_layout", .cache_bytes = 1_MiB, .wipe_data = true}, {}};
CCoinsViewCache cache{&base};
cache.EmplaceCoinInternalDANGER(COutPoint{outpoint}, Coin{coin});
cache.SetBestBlock(block_hash);
cache.Sync();
BOOST_CHECK_EQUAL(level2_files(base), 0);
WITH_LOCK(::cs_main, return base.CompactFull()).wait();
BOOST_CHECK_EQUAL(level2_files(base), 1);
BOOST_CHECK(*Assert(base.GetCoin(outpoint)) == coin);
BOOST_CHECK_EQUAL(base.GetBestBlock(), block_hash);
}
BOOST_AUTO_TEST_CASE(coins_resource_is_used)
{
CCoinsMapMemoryResource resource;

View File

@@ -36,18 +36,13 @@
using node::SnapshotMetadata;
namespace {
const BasicTestingSetup* g_setup;
} // namespace
void initialize_deserialize()
{
static const auto testing_setup = MakeNoLogFileContext<>();
g_setup = testing_setup.get();
}
#define FUZZ_TARGET_DESERIALIZE(name, code) \
FUZZ_TARGET(name, .init = initialize_deserialize) \
FUZZ_TARGET(name, .init = initialize_deserialize) \
{ \
try { \
code \

View File

@@ -12,10 +12,14 @@
#include <random.h>
#include <serialize.h>
#include <uint256.h>
#include <util/threadnames.h>
#include <util/vector.h>
#include <cassert>
#include <chrono>
#include <cstdlib>
#include <exception>
#include <future>
#include <iterator>
#include <utility>
@@ -51,11 +55,22 @@ CCoinsViewDB::CCoinsViewDB(DBParams db_params, CoinsViewOptions options) :
m_options{std::move(options)},
m_db{std::make_unique<CDBWrapper>(m_db_params)} { }
CCoinsViewDB::~CCoinsViewDB()
{
if (m_compaction.valid()) {
if (m_compaction.wait_for(std::chrono::seconds{0}) != std::future_status::ready) {
LogInfo("Waiting for background chainstate compaction of %s", fs::PathToString(m_db_params.path));
}
m_compaction.wait();
}
}
void CCoinsViewDB::ResizeCache(size_t new_cache_size)
{
// We can't do this operation with an in-memory DB since we'll lose all the coins upon
// reset.
if (!m_db_params.memory_only) {
LOCK(m_db_mutex);
// Have to do a reset first to get the original `m_db` state to release its
// filesystem lock.
m_db.reset();
@@ -159,6 +174,30 @@ size_t CCoinsViewDB::EstimateSize() const
return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
}
std::optional<std::string> CCoinsViewDB::GetDBProperty(const std::string& property)
{
return m_db->GetProperty(property);
}
std::shared_future<void> CCoinsViewDB::CompactFull()
{
AssertLockHeld(::cs_main);
if (m_compaction.valid() && m_compaction.wait_for(std::chrono::seconds{0}) != std::future_status::ready) return m_compaction;
m_compaction = std::async(std::launch::async, [this] {
try {
util::ThreadRename("utxocompact");
LOCK(m_db_mutex);
LogDebug(BCLog::COINDB, "Starting chainstate compaction of %s", fs::PathToString(m_db_params.path));
m_db->CompactFull();
LogDebug(BCLog::COINDB, "Finished chainstate compaction of %s", fs::PathToString(m_db_params.path));
} catch (const std::exception& e) {
LogWarning("Failed chainstate compaction (%s)", e.what());
}
}).share();
return m_compaction;
}
/** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */
class CCoinsViewDBCursor: public CCoinsViewCursor
{

View File

@@ -14,8 +14,10 @@
#include <cstddef>
#include <cstdint>
#include <future>
#include <memory>
#include <optional>
#include <string>
#include <vector>
class COutPoint;
@@ -39,9 +41,13 @@ class CCoinsViewDB final : public CCoinsView
protected:
DBParams m_db_params;
CoinsViewOptions m_options;
//! Prevents CompactFull() from using m_db while ResizeCache() replaces it.
Mutex m_db_mutex;
std::unique_ptr<CDBWrapper> m_db;
std::shared_future<void> m_compaction;
public:
explicit CCoinsViewDB(DBParams db_params, CoinsViewOptions options);
~CCoinsViewDB() override;
std::optional<Coin> GetCoin(const COutPoint& outpoint) const override;
bool HaveCoin(const COutPoint &outpoint) const override;
@@ -55,10 +61,16 @@ public:
size_t EstimateSize() const override;
//! Dynamically alter the underlying leveldb cache size.
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_db_mutex);
//! @returns filesystem path to on-disk storage or std::nullopt if in memory.
std::optional<fs::path> StoragePath() { return m_db->StoragePath(); }
//! Perform a full compaction of the underlying LevelDB on a one-shot background thread.
std::shared_future<void> CompactFull() EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_db_mutex);
//! Return an underlying LevelDB property value, if available.
std::optional<std::string> GetDBProperty(const std::string& property);
};
#endif // BITCOIN_TXDB_H

View File

@@ -113,6 +113,13 @@ const std::vector<std::string> CHECKLEVEL_DOC {
* */
static constexpr int PRUNE_LOCK_BUFFER{10};
// Return whether the completed full flush should compact chainstate
static bool ShouldCompactChainstate(bool in_ibd)
{
static constexpr uint32_t flush_ratio{320}; // Roughly every 2 weeks with hourly flushes
return !in_ibd && FastRandomContext().randrange(flush_ratio) == 0;
}
TRACEPOINT_SEMAPHORE(validation, block_connected);
TRACEPOINT_SEMAPHORE(utxocache, flush);
TRACEPOINT_SEMAPHORE(mempool, replaced);
@@ -2901,9 +2908,19 @@ bool Chainstate::FlushStateToDisk(
m_next_write = FastRandomContext().rand_uniform_delay(NodeClock::now() + DATABASE_WRITE_INTERVAL_MIN, range);
}
}
if (full_flush_completed && m_chainman.m_options.signals) {
// Update best block in wallet (so we can detect restored wallets).
m_chainman.m_options.signals->ChainStateFlushed(this->GetRole(), GetLocator(m_chain.Tip()));
if (full_flush_completed) {
if (m_chainman.m_options.signals) {
// Update best block in wallet (so we can detect restored wallets).
m_chainman.m_options.signals->ChainStateFlushed(this->GetRole(), GetLocator(m_chain.Tip()));
}
if (!m_chainman.m_interrupt && ShouldCompactChainstate(m_chainman.IsInitialBlockDownload())) {
try {
CoinsDB().CompactFull();
} catch (const std::exception& e) {
LogWarning("Failed to start chainstate compaction (%s)", e.what());
}
}
}
} catch (const std::runtime_error& e) {
return FatalError(m_chainman.GetNotifications(), state, strprintf(_("System error while flushing: %s"), e.what()));

View File

@@ -11,11 +11,9 @@
namespace wallet {
namespace {
const TestingSetup* g_setup;
void initialize_crypter()
{
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
}
FUZZ_TARGET(crypter, .init = initialize_crypter)

View File

@@ -210,7 +210,7 @@ fn get_subtrees() -> Vec<&'static str> {
"src/crc32c",
"src/crypto/ctaes",
"src/ipc/libmultiprocess",
"src/leveldb",
//"src/leveldb", No longer a subtree in this release branch, due to direct cherry-picks
"src/minisketch",
"src/secp256k1",
]