From c9fa661131c336a844109a5d8627b7419280bf52 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Wed, 8 Oct 2025 14:47:00 -0700 Subject: [PATCH 01/21] ci: Properly include $FILE_ENV in DEPENDS_HASH $FILE_ENV has a full relative path already, prepending with ci/test/ results in a non-existent path which means that DEPENDS_HASH was not actually committing to the test's environment file. Github-Pull: #33581 Rebased-From: ceeb53adcd0a6a87a65c8ebbb20472c15c502dfd --- .github/actions/configure-environment/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/configure-environment/action.yml b/.github/actions/configure-environment/action.yml index aae5016bdce..e2a26b7184d 100644 --- a/.github/actions/configure-environment/action.yml +++ b/.github/actions/configure-environment/action.yml @@ -17,7 +17,7 @@ runs: - name: Set cache hashes shell: bash run: | - echo "DEPENDS_HASH=$(git ls-tree HEAD depends "ci/test/$FILE_ENV" | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV + echo "DEPENDS_HASH=$(git ls-tree HEAD depends "$FILE_ENV" | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV echo "PREVIOUS_RELEASES_HASH=$(git ls-tree HEAD test/get_previous_releases.py | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV - name: Get container name From 72d1141bd8ded704cc6b881a7d26d9103ec813df Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Tue, 7 Oct 2025 12:23:39 +0200 Subject: [PATCH 02/21] ci: Use native platform for win-cross task Github-Pull: #33558 Rebased-From: fa6fd16f36e1240cda58a46e1717b02e8d3172a3 --- ci/test/00_setup_env_win64.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh index 13e794bd6d1..f929f34c68f 100755 --- a/ci/test/00_setup_env_win64.sh +++ b/ci/test/00_setup_env_win64.sh @@ -8,7 +8,6 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_win64 export CI_IMAGE_NAME_TAG="mirror.gcr.io/ubuntu:24.04" # Check that https://packages.ubuntu.com/noble/g++-mingw-w64-x86-64-posix (version 13.x, similar to guix) can cross-compile -export CI_IMAGE_PLATFORM="linux/amd64" export HOST=x86_64-w64-mingw32 export PACKAGES="g++-mingw-w64-x86-64-posix nsis" export RUN_UNIT_TESTS=false From 73ed57a35e624c6eb4c5dca2687303920fa792bc Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Wed, 8 Oct 2025 13:10:59 -0700 Subject: [PATCH 03/21] depends: Use $(package)_file_name when downloading from the fallback Github-Pull: #33580 Rebased-From: 671b774d1b58c491b53f2b2f6ee42fb6b65a0e71 --- depends/funcs.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/funcs.mk b/depends/funcs.mk index 28baf47147a..9e8d9ddd006 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -38,7 +38,7 @@ endef define fetch_file ( test -f $$($(1)_source_dir)/$(4) || \ ( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \ - $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))) + $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(4),$(4),$(5)))) endef # Shell script to create a source tarball in $(1)_source from local directory From c48d3a6ad8e884bdb595d5608d914f7de688b7af Mon Sep 17 00:00:00 2001 From: willcl-ark Date: Tue, 30 Sep 2025 11:00:26 +0100 Subject: [PATCH 04/21] ci: expose all ACTIONS_* vars When using `docker buildx build` in conjunction with the `gha` backend cache type, it's important to specify the URL and TOKEN needed to authenticate. On Cirrus runners this is working with only `ACTIONS_CACHE_URL` and `ACTIONS_RUNTIME_TOKEN`, but this is not enough for the GitHub backend. Fix this by exporting all `ACTIONS_*` variables. This fixes cache restore/save on forks or where GH-hosted runners are being used. Github-Pull: #33508 Rebased-From: bc706955d740f8a59bec78e44d33e80d1cca373b --- .github/actions/configure-docker/action.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/actions/configure-docker/action.yml b/.github/actions/configure-docker/action.yml index 09a1e6fd3af..9c2ce93f7a6 100644 --- a/.github/actions/configure-docker/action.yml +++ b/.github/actions/configure-docker/action.yml @@ -22,8 +22,12 @@ runs: uses: actions/github-script@v6 with: script: | - core.exportVariable('ACTIONS_CACHE_URL', process.env['ACTIONS_CACHE_URL']) - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env['ACTIONS_RUNTIME_TOKEN']) + Object.keys(process.env).forEach(function (key) { + if (key.startsWith('ACTIONS_')) { + core.info(`Exporting ${key}`); + core.exportVariable(key, process.env[key]); + } + }); - name: Construct docker build cache args shell: bash From 5e389959b9bacae60da64d6e0213ae12242b4c2e Mon Sep 17 00:00:00 2001 From: Eugene Siegel Date: Mon, 13 Oct 2025 11:29:19 -0400 Subject: [PATCH 05/21] test: change log rate limit version gate from 299900 to 290100 Github-Pull: #33612 Rebased-From: 7b544341c0021dd713f05bc439ee190de911930c --- test/functional/test_framework/test_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 1ec2fe8a657..3b55b915efd 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -161,7 +161,7 @@ class TestNode(): self.args.append("-logsourcelocations") if self.version_is_at_least(239000): self.args.append("-loglevel=trace") - if self.version_is_at_least(299900): + if self.version_is_at_least(290100): self.args.append("-nologratelimit") # Default behavior from global -v2transport flag is added to args to persist it over restarts. From f8db6f6ce7d30c1b6db8646eedc9160ded556823 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 1 Oct 2025 14:41:40 +0000 Subject: [PATCH 06/21] multiprocess: update multiprocess EventLoop construction to use options This uses the constructors recently added upstream. Github-Pull: #33517 Rebased-From: 9d068225ee2b79da43e264994cd84279655a2210 --- src/ipc/capnp/protocol.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/ipc/capnp/protocol.cpp b/src/ipc/capnp/protocol.cpp index 4150f9f4664..4263aebd284 100644 --- a/src/ipc/capnp/protocol.cpp +++ b/src/ipc/capnp/protocol.cpp @@ -30,10 +30,10 @@ namespace ipc { namespace capnp { namespace { -void IpcLogFn(bool raise, std::string message) +void IpcLogFn(mp::LogMessage message) { - LogDebug(BCLog::IPC, "%s\n", message); - if (raise) throw Exception(message); + LogDebug(BCLog::IPC, "%s\n", message.message); + if (message.level == mp::Log::Raise) throw Exception(message.message); } class CapnpProtocol : public Protocol @@ -62,7 +62,10 @@ public: { assert(!m_loop); mp::g_thread_context.thread_name = mp::ThreadName(exe_name); - m_loop.emplace(exe_name, &IpcLogFn, &m_context); + mp::LogOptions opts = { + .log_fn = IpcLogFn, + }; + m_loop.emplace(exe_name, std::move(opts), &m_context); if (ready_fn) ready_fn(); mp::ServeStream(*m_loop, fd, init); m_parent_connection = &m_loop->m_incoming_connections.back(); @@ -90,7 +93,10 @@ public: std::promise promise; m_loop_thread = std::thread([&] { util::ThreadRename("capnp-loop"); - m_loop.emplace(exe_name, &IpcLogFn, &m_context); + mp::LogOptions opts = { + .log_fn = IpcLogFn, + }; + m_loop.emplace(exe_name, std::move(opts), &m_context); m_loop_ref.emplace(*m_loop); promise.set_value(); m_loop->loop(); From 729e4c2abd4ab4eda4051579c57410dd64d4e7a9 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 1 Oct 2025 16:14:08 +0000 Subject: [PATCH 07/21] multiprocess: align our logging with libmultiprocess's Without this change, logging (even if unused) may account for a substantial portion of bitcoin-node's and/or client's runtime cpu usage, due to libmultiprocess's expensive message serialization. This (along with some recent upstream changes) avoids the overhead by opting out of log handling for messages that we're not interested in. Info, Warning, and Error are logged unconditionally to match our behavior elsewhere. See BCLog::Logger::GetCategoryLogLevel . Github-Pull: #33517 Rebased-From: 0626b90f507db68610a69feec86deb712dd095a1 --- src/ipc/capnp/protocol.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ipc/capnp/protocol.cpp b/src/ipc/capnp/protocol.cpp index 4263aebd284..27ef73e84e5 100644 --- a/src/ipc/capnp/protocol.cpp +++ b/src/ipc/capnp/protocol.cpp @@ -30,9 +30,35 @@ namespace ipc { namespace capnp { namespace { + +BCLog::Level ConvertIPCLogLevel(mp::Log level) +{ + switch (level) { + case mp::Log::Trace: return BCLog::Level::Trace; + case mp::Log::Debug: return BCLog::Level::Debug; + case mp::Log::Info: return BCLog::Level::Info; + case mp::Log::Warning: return BCLog::Level::Warning; + case mp::Log::Error: return BCLog::Level::Error; + case mp::Log::Raise: return BCLog::Level::Error; + } // no default case, so the compiler can warn about missing cases + + // Be conservative and assume that if MP ever adds a new log level, it + // should only be shown at our most verbose level. + return BCLog::Level::Trace; +} + +mp::Log GetRequestedIPCLogLevel() +{ + if (LogAcceptCategory(BCLog::IPC, BCLog::Level::Trace)) return mp::Log::Trace; + if (LogAcceptCategory(BCLog::IPC, BCLog::Level::Debug)) return mp::Log::Debug; + + // Info, Warning, and Error are logged unconditionally + return mp::Log::Info; +} + void IpcLogFn(mp::LogMessage message) { - LogDebug(BCLog::IPC, "%s\n", message.message); + LogPrintLevel(BCLog::IPC, ConvertIPCLogLevel(message.level), "%s\n", message.message); if (message.level == mp::Log::Raise) throw Exception(message.message); } @@ -64,6 +90,7 @@ public: mp::g_thread_context.thread_name = mp::ThreadName(exe_name); mp::LogOptions opts = { .log_fn = IpcLogFn, + .log_level = GetRequestedIPCLogLevel() }; m_loop.emplace(exe_name, std::move(opts), &m_context); if (ready_fn) ready_fn(); @@ -95,6 +122,7 @@ public: util::ThreadRename("capnp-loop"); mp::LogOptions opts = { .log_fn = IpcLogFn, + .log_level = GetRequestedIPCLogLevel() }; m_loop.emplace(exe_name, std::move(opts), &m_context); m_loop_ref.emplace(*m_loop); From 96110f884604ab85db04170f22e9a4bd936c59d7 Mon Sep 17 00:00:00 2001 From: glozow Date: Tue, 14 Oct 2025 15:59:15 -0400 Subject: [PATCH 08/21] [doc] correct topology requirements in submitpackage helptext Github-Pull: #33630 Rebased-From: 3d222825642bfb052ce40cbc1c69318a0d8835bf --- src/rpc/mempool.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 919c30464dd..286ac5e3537 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -936,8 +936,9 @@ static RPCHelpMan submitpackage() , { {"package", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of raw transactions.\n" - "The package must solely consist of a child transaction and all of its unconfirmed parents, if any. None of the parents may depend on each other.\n" - "The package must be topologically sorted, with the child being the last element in the array.", + "The package must consist of a transaction with (some, all, or none of) its unconfirmed parents. A single transaction is permitted.\n" + "None of the parents may depend on each other. Parents that are already in mempool do not need to be present in the package.\n" + "The package must be topologically sorted, with the child being the last element in the array if there are multiple elements.", { {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""}, }, From 42d4847fdff3e1c3b0644de5f503db80ef3ff2a1 Mon Sep 17 00:00:00 2001 From: Ryan Ofsky Date: Wed, 20 Aug 2025 13:24:35 -0400 Subject: [PATCH 09/21] init: add exe name to bitcoind, bitcoin-node -version output to be able to distinguish these in tests Github-Pull: #33229 Rebased-From: 0972f5504021b482b27523fd3bcb8036cf6b439c --- src/bitcoind.cpp | 11 ++++++++--- src/init/bitcoin-gui.cpp | 1 + src/init/bitcoin-node.cpp | 1 + src/init/bitcoin-qt.cpp | 3 +++ src/init/bitcoind.cpp | 3 +++ src/interfaces/init.h | 1 + 6 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index ceb3c99410c..a4373dafdf2 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -132,11 +132,16 @@ static bool ParseArgs(NodeContext& node, int argc, char* argv[]) return true; } -static bool ProcessInitCommands(ArgsManager& args) +static bool ProcessInitCommands(interfaces::Init& init, ArgsManager& args) { // Process help and version before taking care about datadir if (HelpRequested(args) || args.GetBoolArg("-version", false)) { - std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion() + "\n"; + std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion(); + if (const char* exe_name{init.exeName()}) { + strUsage += " "; + strUsage += exe_name; + } + strUsage += "\n"; if (args.GetBoolArg("-version", false)) { strUsage += FormatParagraph(LicenseInfo()); @@ -277,7 +282,7 @@ MAIN_FUNCTION ArgsManager& args = *Assert(node.args); if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE; // Process early info return commands such as -help or -version - if (ProcessInitCommands(args)) return EXIT_SUCCESS; + if (ProcessInitCommands(*init, args)) return EXIT_SUCCESS; // Start application if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) { diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp index eae30bc995a..aca3fbe1c44 100644 --- a/src/init/bitcoin-gui.cpp +++ b/src/init/bitcoin-gui.cpp @@ -39,6 +39,7 @@ public: // bitcoin-node accepts the option, and bitcoin-gui accepts all bitcoin-node // options and will start the node with those options. bool canListenIpc() override { return true; } + const char* exeName() override { return EXE_NAME; } node::NodeContext m_node; std::unique_ptr m_ipc; }; diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index 3f8c50b8d66..e5f1411fdb5 100644 --- a/src/init/bitcoin-node.cpp +++ b/src/init/bitcoin-node.cpp @@ -38,6 +38,7 @@ public: std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } bool canListenIpc() override { return true; } + const char* exeName() override { return EXE_NAME; } node::NodeContext& m_node; std::unique_ptr m_ipc; }; diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp index 5209c729731..05f3bc32d7d 100644 --- a/src/init/bitcoin-qt.cpp +++ b/src/init/bitcoin-qt.cpp @@ -16,6 +16,8 @@ namespace init { namespace { +const char* EXE_NAME = "bitcoin-qt"; + class BitcoinQtInit : public interfaces::Init { public: @@ -32,6 +34,7 @@ public: return MakeWalletLoader(chain, *Assert(m_node.args)); } std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } + const char* exeName() override { return EXE_NAME; } node::NodeContext m_node; }; } // namespace diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp index 48be8831d25..0b0ab3f8fa8 100644 --- a/src/init/bitcoind.cpp +++ b/src/init/bitcoind.cpp @@ -18,6 +18,8 @@ using node::NodeContext; namespace init { namespace { +const char* EXE_NAME = "bitcoind"; + class BitcoindInit : public interfaces::Init { public: @@ -34,6 +36,7 @@ public: return MakeWalletLoader(chain, *Assert(m_node.args)); } std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } + const char* exeName() override { return EXE_NAME; } NodeContext& m_node; }; } // namespace diff --git a/src/interfaces/init.h b/src/interfaces/init.h index b496ada05f4..030ce306c00 100644 --- a/src/interfaces/init.h +++ b/src/interfaces/init.h @@ -38,6 +38,7 @@ public: virtual std::unique_ptr makeEcho() { return nullptr; } virtual Ipc* ipc() { return nullptr; } virtual bool canListenIpc() { return false; } + virtual const char* exeName() { return nullptr; } }; //! Return implementation of Init interface for the node process. If the argv From cd7937ce2d313715f380eafd15b20d429b65c83c Mon Sep 17 00:00:00 2001 From: Ryan Ofsky Date: Wed, 20 Aug 2025 14:13:17 -0400 Subject: [PATCH 10/21] test: add tool_bitcoin to test bitcoin wrapper behavior Github-Pull: #33229 Rebased-From: 29e836fae660d9a89c54a094ae1a032e6a88c334 --- test/functional/test_runner.py | 1 + test/functional/tool_bitcoin.py | 102 ++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100755 test/functional/tool_bitcoin.py diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index fc86033800e..9d556d1cd7b 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -336,6 +336,7 @@ BASE_SCRIPTS = [ 'p2p_tx_privacy.py', 'rpc_getdescriptoractivity.py', 'rpc_scanblocks.py', + 'tool_bitcoin.py', 'p2p_sendtxrcncl.py', 'rpc_scantxoutset.py', 'feature_unsupported_utxo_db.py', diff --git a/test/functional/tool_bitcoin.py b/test/functional/tool_bitcoin.py new file mode 100755 index 00000000000..dcfdb2d774b --- /dev/null +++ b/test/functional/tool_bitcoin.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# Copyright (c) The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test the bitcoin wrapper tool.""" +from test_framework.test_framework import ( + BitcoinTestFramework, + SkipTest, +) +from test_framework.util import assert_equal + +import platform +import re + + +class ToolBitcoinTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 1 + + def skip_test_if_missing_module(self): + # Skip test on windows because currently when `bitcoin node -version` is + # run on windows, python doesn't capture output from the child + # `bitcoind` and `bitcoin-node` process started with _wexecvp, and + # stdout/stderr are always empty. See + # https://github.com/bitcoin/bitcoin/pull/33229#issuecomment-3265524908 + if platform.system() == "Windows": + raise SkipTest("Test does not currently work on windows") + + def setup_network(self): + """Set up nodes normally, but save a copy of their arguments before starting them.""" + self.add_nodes(self.num_nodes, self.extra_args) + node_argv = self.get_binaries().node_argv() + self.node_options = [node.args[len(node_argv):] for node in self.nodes] + assert all(node.args[:len(node_argv)] == node_argv for node in self.nodes) + + def set_cmd_args(self, node, args): + """Set up node so it will be started through bitcoin wrapper command with specified arguments.""" + node.args = [self.binary_paths.bitcoin_bin] + args + ["node"] + self.node_options[node.index] + + def test_args(self, cmd_args, node_args, expect_exe=None, expect_error=None): + node = self.nodes[0] + self.set_cmd_args(node, cmd_args) + extra_args = node_args + ["-version"] + if expect_error is not None: + node.assert_start_raises_init_error(expected_msg=expect_error, extra_args=extra_args) + else: + assert expect_exe + node.start(extra_args=extra_args) + ret, out, err = get_node_output(node) + try: + assert_equal(get_exe_name(out), expect_exe.encode()) + assert_equal(err, b"") + except Exception as e: + raise RuntimeError(f"Unexpected output from {node.args + extra_args}: {out=!r} {err=!r} {ret=!r}") from e + + def run_test(self): + self.log.info("Ensure bitcoin node command invokes bitcoind by default") + self.test_args([], [], expect_exe="bitcoind") + + self.log.info("Ensure bitcoin command does not accept -ipcbind by default") + self.test_args(["-M"], ["-ipcbind=unix"], expect_error='Error: Error parsing command line arguments: Invalid parameter -ipcbind=unix') + + self.log.info("Ensure bitcoin -M invokes bitcoind") + self.test_args(["-M"], [], expect_exe="bitcoind") + + self.log.info("Ensure bitcoin -M does not accept -ipcbind") + self.test_args(["-M"], ["-ipcbind=unix"], expect_error='Error: Error parsing command line arguments: Invalid parameter -ipcbind=unix') + + if self.is_ipc_compiled(): + self.log.info("Ensure bitcoin -m invokes bitcoin-node") + self.test_args(["-m"], [], expect_exe="bitcoin-node") + + self.log.info("Ensure bitcoin -m does accept -ipcbind") + self.test_args(["-m"], ["-ipcbind=unix"], expect_exe="bitcoin-node") + + +def get_node_output(node): + ret = node.process.wait(timeout=60) + node.stdout.seek(0) + node.stderr.seek(0) + out = node.stdout.read() + err = node.stderr.read() + node.stdout.close() + node.stderr.close() + + # Clean up TestNode state + node.running = False + node.process = None + node.rpc_connected = False + node.rpc = None + + return ret, out, err + + +def get_exe_name(version_str): + """Get exe name from last word of first line of version string.""" + return re.match(rb".*?(\S+)\s*?(?:\n|$)", version_str.strip()).group(1) + + +if __name__ == '__main__': + ToolBitcoinTest(__file__).main() From 23ac752d0966317894ae5279a59a12dd6f9f616a Mon Sep 17 00:00:00 2001 From: Ryan Ofsky Date: Wed, 20 Aug 2025 15:52:21 -0400 Subject: [PATCH 11/21] bitcoin: Make wrapper not require -m Choose the right binary by default if an IPC option is specified Github-Pull: #33229 Rebased-From: 453b0fa286e5dce0af682b7b73684dd6415a50de --- src/CMakeLists.txt | 2 +- src/bitcoin.cpp | 32 +++++++++++++++++++++++++++++--- src/common/args.cpp | 8 +++++++- src/common/args.h | 8 +++++++- test/functional/tool_bitcoin.py | 17 +++++++++++++---- test/lint/check-doc.py | 2 +- 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9abbf9586b8..f9934bb5906 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -292,7 +292,7 @@ if(BUILD_BITCOIN_BIN) add_executable(bitcoin bitcoin.cpp) add_windows_resources(bitcoin bitcoin-res.rc) add_windows_application_manifest(bitcoin) - target_link_libraries(bitcoin core_interface bitcoin_util) + target_link_libraries(bitcoin core_interface bitcoin_common bitcoin_util) install_binary_component(bitcoin HAS_MANPAGE) endif() diff --git a/src/bitcoin.cpp b/src/bitcoin.cpp index c3278274153..c1a5fce33af 100644 --- a/src/bitcoin.cpp +++ b/src/bitcoin.cpp @@ -5,6 +5,7 @@ #include // IWYU pragma: keep #include +#include #include #include #include @@ -47,7 +48,7 @@ Run '%s help' to see additional commands (e.g. for testing and debugging). )"; struct CommandLine { - bool use_multiprocess{false}; + std::optional use_multiprocess; bool show_version{false}; bool show_help{false}; std::string_view command; @@ -55,6 +56,7 @@ struct CommandLine { }; CommandLine ParseCommandLine(int argc, char* argv[]); +bool UseMultiprocess(const CommandLine& cmd); static void ExecCommand(const std::vector& args, std::string_view argv0); int main(int argc, char* argv[]) @@ -78,9 +80,9 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } } else if (cmd.command == "gui") { - args.emplace_back(cmd.use_multiprocess ? "bitcoin-gui" : "bitcoin-qt"); + args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-gui" : "bitcoin-qt"); } else if (cmd.command == "node") { - args.emplace_back(cmd.use_multiprocess ? "bitcoin-node" : "bitcoind"); + args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-node" : "bitcoind"); } else if (cmd.command == "rpc") { args.emplace_back("bitcoin-cli"); // Since "bitcoin rpc" is a new interface that doesn't need to be @@ -143,6 +145,30 @@ CommandLine ParseCommandLine(int argc, char* argv[]) return cmd; } +bool UseMultiprocess(const CommandLine& cmd) +{ + // If -m or -M options were explicitly specified, there is no need to + // further parse arguments to determine which to use. + if (cmd.use_multiprocess) return *cmd.use_multiprocess; + + ArgsManager args; + args.SetDefaultFlags(ArgsManager::ALLOW_ANY); + std::string error_message; + auto argv{cmd.args}; + argv.insert(argv.begin(), nullptr); + if (!args.ParseParameters(argv.size(), argv.data(), error_message)) { + tfm::format(std::cerr, "Warning: failed to parse subcommand command line options: %s\n", error_message); + } + if (!args.ReadConfigFiles(error_message, true)) { + tfm::format(std::cerr, "Warning: failed to parse subcommand config: %s\n", error_message); + } + args.SelectConfigNetwork(args.GetChainTypeString()); + + // If any -ipc* options are set these need to be processed by a + // multiprocess-capable binary. + return args.IsArgSet("-ipcbind") || args.IsArgSet("-ipcconnect") || args.IsArgSet("-ipcfd"); +} + //! Execute the specified bitcoind, bitcoin-qt or other command line in `args` //! using src, bin and libexec directory paths relative to this executable, where //! the path to this executable is specified in `wrapper_argv0`. diff --git a/src/common/args.cpp b/src/common/args.cpp index ff30ec5b8c1..d44cd4319b6 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -266,7 +266,13 @@ std::optional ArgsManager::GetArgFlags(const std::string& name) co return search->second.m_flags; } } - return std::nullopt; + return m_default_flags; +} + +void ArgsManager::SetDefaultFlags(std::optional flags) +{ + LOCK(cs_args); + m_default_flags = flags; } fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const diff --git a/src/common/args.h b/src/common/args.h index da19cbda66f..d907ad7663d 100644 --- a/src/common/args.h +++ b/src/common/args.h @@ -137,6 +137,7 @@ protected: std::string m_network GUARDED_BY(cs_args); std::set m_network_only_args GUARDED_BY(cs_args); std::map> m_available_args GUARDED_BY(cs_args); + std::optional m_default_flags GUARDED_BY(cs_args){}; bool m_accept_any_command GUARDED_BY(cs_args){true}; std::list m_config_sections GUARDED_BY(cs_args); std::optional m_config_path GUARDED_BY(cs_args); @@ -375,10 +376,15 @@ protected: /** * Return Flags for known arg. - * Return nullopt for unknown arg. + * Return default flags for unknown arg. */ std::optional GetArgFlags(const std::string& name) const; + /** + * Set default flags to return for an unknown arg. + */ + void SetDefaultFlags(std::optional); + /** * Get settings file path, or return false if read-write settings were * disabled with -nosettings. diff --git a/test/functional/tool_bitcoin.py b/test/functional/tool_bitcoin.py index dcfdb2d774b..1112e02e090 100755 --- a/test/functional/tool_bitcoin.py +++ b/test/functional/tool_bitcoin.py @@ -7,7 +7,10 @@ from test_framework.test_framework import ( BitcoinTestFramework, SkipTest, ) -from test_framework.util import assert_equal +from test_framework.util import ( + append_config, + assert_equal, +) import platform import re @@ -55,12 +58,11 @@ class ToolBitcoinTest(BitcoinTestFramework): raise RuntimeError(f"Unexpected output from {node.args + extra_args}: {out=!r} {err=!r} {ret=!r}") from e def run_test(self): + node = self.nodes[0] + self.log.info("Ensure bitcoin node command invokes bitcoind by default") self.test_args([], [], expect_exe="bitcoind") - self.log.info("Ensure bitcoin command does not accept -ipcbind by default") - self.test_args(["-M"], ["-ipcbind=unix"], expect_error='Error: Error parsing command line arguments: Invalid parameter -ipcbind=unix') - self.log.info("Ensure bitcoin -M invokes bitcoind") self.test_args(["-M"], [], expect_exe="bitcoind") @@ -74,6 +76,13 @@ class ToolBitcoinTest(BitcoinTestFramework): self.log.info("Ensure bitcoin -m does accept -ipcbind") self.test_args(["-m"], ["-ipcbind=unix"], expect_exe="bitcoin-node") + self.log.info("Ensure bitcoin accepts -ipcbind by default") + self.test_args([], ["-ipcbind=unix"], expect_exe="bitcoin-node") + + self.log.info("Ensure bitcoin recognizes -ipcbind in config file") + append_config(node.datadir_path, ["ipcbind=unix"]) + self.test_args([], [], expect_exe="bitcoin-node") + def get_node_output(node): ret = node.process.wait(timeout=60) diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py index 3e9e5ba230a..e47ff30f31c 100755 --- a/test/lint/check-doc.py +++ b/test/lint/check-doc.py @@ -23,7 +23,7 @@ CMD_GREP_WALLET_ARGS = r"git grep --function-context 'void WalletInit::AddWallet CMD_GREP_WALLET_HIDDEN_ARGS = r"git grep --function-context 'void DummyWalletInit::AddWalletOptions' -- {}".format(CMD_ROOT_DIR) CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR) # list unsupported, deprecated and duplicate args as they need no documentation -SET_DOC_OPTIONAL = set(['-h', '-?', '-dbcrashratio', '-forcecompactdb']) +SET_DOC_OPTIONAL = set(['-h', '-?', '-dbcrashratio', '-forcecompactdb', '-ipcconnect', '-ipcfd']) def lint_missing_argument_documentation(): From 3afd5a9729d78f38d2cac7b34f3ef44c79b4bf9a Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Mon, 13 Oct 2025 18:39:18 +0200 Subject: [PATCH 12/21] miner: fix empty mempool case for waitNext() Block template fees are calculated by looping over new_tmpl->vTxFees and return (early) once the fee_threshold is exceeded. This left an edge case when the mempool is empty, which this commit fixes and adds a test for. It does so by using std::accumulate instead of manual loops. Also update interface_ipc.py to account for the new behavior. Co-authored-by: Raimo33 Github-Pull: #33566 Rebased-From: 8f7673257a1a86717c1d83770dc857fc254df107 --- src/node/miner.cpp | 16 ++++++---------- src/test/miner_tests.cpp | 22 +++++++++++++++++++--- test/functional/interface_ipc.py | 2 ++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/node/miner.cpp b/src/node/miner.cpp index e75bc3a603b..28e9048a4dd 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -29,6 +29,7 @@ #include #include +#include namespace node { @@ -522,18 +523,13 @@ std::unique_ptr WaitAndCreateNewBlock(ChainstateManager& chainma // Calculate the original template total fees if we haven't already if (current_fees == -1) { - current_fees = 0; - for (CAmount fee : block_template->vTxFees) { - current_fees += fee; - } + current_fees = std::accumulate(block_template->vTxFees.begin(), block_template->vTxFees.end(), CAmount{0}); } - CAmount new_fees = 0; - for (CAmount fee : new_tmpl->vTxFees) { - new_fees += fee; - Assume(options.fee_threshold != MAX_MONEY); - if (new_fees >= current_fees + options.fee_threshold) return new_tmpl; - } + // Check if fees increased enough to return the new template + const CAmount new_fees = std::accumulate(new_tmpl->vTxFees.begin(), new_tmpl->vTxFees.end(), CAmount{0}); + Assume(options.fee_threshold != MAX_MONEY); + if (new_fees >= current_fees + options.fee_threshold) return new_tmpl; } now = NodeClock::now(); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 652ec25fe89..94ade598439 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -113,6 +113,22 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const options.coinbase_output_script = scriptPubKey; LOCK(tx_mempool.cs); + BOOST_CHECK(tx_mempool.size() == 0); + + // Block template should only have a coinbase when there's nothing in the mempool + std::unique_ptr block_template = mining->createNewBlock(options); + BOOST_REQUIRE(block_template); + CBlock block{block_template->getBlock()}; + BOOST_REQUIRE_EQUAL(block.vtx.size(), 1U); + + // waitNext() on an empty mempool should return nullptr because there is no better template + auto should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1}); + BOOST_REQUIRE(should_be_nullptr == nullptr); + + // Unless fee_threshold is 0 + block_template = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 0}); + BOOST_REQUIRE(block_template); + // Test the ancestor feerate transaction selection. TestMemPoolEntryHelper entry; @@ -144,9 +160,9 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const const auto high_fee_tx{entry.Fee(50000).Time(Now()).SpendsCoinbase(false).FromTx(tx)}; AddToMempool(tx_mempool, high_fee_tx); - std::unique_ptr block_template = mining->createNewBlock(options); + block_template = mining->createNewBlock(options); BOOST_REQUIRE(block_template); - CBlock block{block_template->getBlock()}; + block = block_template->getBlock(); BOOST_REQUIRE_EQUAL(block.vtx.size(), 4U); BOOST_CHECK(block.vtx[1]->GetHash() == hashParentTx); BOOST_CHECK(block.vtx[2]->GetHash() == hashHighFeeTx); @@ -184,7 +200,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const AddToMempool(tx_mempool, entry.Fee(feeToUse).FromTx(tx)); // waitNext() should return nullptr because there is no better template - auto should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1}); + should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1}); BOOST_REQUIRE(should_be_nullptr == nullptr); block = block_template->getBlock(); diff --git a/test/functional/interface_ipc.py b/test/functional/interface_ipc.py index 4231e95b56a..abcc4d6b5d1 100755 --- a/test/functional/interface_ipc.py +++ b/test/functional/interface_ipc.py @@ -153,6 +153,7 @@ class IPCInterfaceTest(BitcoinTestFramework): self.log.debug("Wait for a new template") waitoptions = self.capnp_modules['mining'].BlockWaitOptions() waitoptions.timeout = timeout + waitoptions.feeThreshold = 1 waitnext = template.result.waitNext(ctx, waitoptions) self.generate(self.nodes[0], 1) template2 = await waitnext @@ -168,6 +169,7 @@ class IPCInterfaceTest(BitcoinTestFramework): block3 = await self.parse_and_deserialize_block(template4, ctx) assert_equal(len(block3.vtx), 2) self.log.debug("Wait again, this should return the same template, since the fee threshold is zero") + waitoptions.feeThreshold = 0 template5 = await template4.result.waitNext(ctx, waitoptions) block4 = await self.parse_and_deserialize_block(template5, ctx) assert_equal(len(block4.vtx), 2) From 049bf100f114db3ec95eebbc56621ab5bce2cabd Mon Sep 17 00:00:00 2001 From: WakeTrainDev <175499942+waketraindev@users.noreply.github.com> Date: Fri, 10 Oct 2025 23:55:06 +0300 Subject: [PATCH 13/21] qt: add createwallet, createwalletdescriptor, and migratewallet to history filter Github-Pull: #gui901 Rebased-From: 4e352efa2ce756c668664486c99d003eef530e0c --- src/qt/rpcconsole.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 958c82fda22..d6d2be7b393 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -72,6 +72,9 @@ namespace { // don't add private key handling cmd's to the history const QStringList historyFilter = QStringList() + << "createwallet" + << "createwalletdescriptor" + << "migratewallet" << "signmessagewithprivkey" << "signrawtransactionwithkey" << "walletpassphrase" From 8f8c7cf7fa957337d9f5715ae28835dbba12698d Mon Sep 17 00:00:00 2001 From: will Date: Thu, 30 Oct 2025 10:36:25 +0000 Subject: [PATCH 14/21] ci: fix lint docker caching Fixes: 33735 Correct runner type selection for the lint job. This was erroneously left-out during refactor of the runner selection mechanism in #33302 causing the lint job to run on GH hosts (and therefore not be able to acces local cirrus caches). Github-Pull: #33744 Rebased-From: 0b3b8a3be1a0db0dfc634acca1d9305dc0fbfae6 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5cae564e4d..c1355c8cf12 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -536,7 +536,7 @@ jobs: lint: name: 'lint' needs: runners - runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-xs' || 'ubuntu-24.04' }} + runs-on: ${{ needs.runners.outputs.provider == 'cirrus' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-xs' || 'ubuntu-24.04' }} if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }} timeout-minutes: 20 env: From 34576c45747214e02b34cac5de71f5139888661f Mon Sep 17 00:00:00 2001 From: will Date: Mon, 3 Nov 2025 14:56:17 +0000 Subject: [PATCH 15/21] ci: fix configure docker action inputs The options used were wrong in two ways: firstly they were not enforced as a "choice" (i.e. invalid input valudes could be provided without error) and one of the options was listed as `gh` when we passed it as `gha` from ci.yml. "Fix" this by removing the choice altogether but sanity-testing the input value against an expected list using a GHA "warning" to notify of unknown inputs. Github-Pull: #33744 Rebased-From: 7632e0ba312a372259897c68fd7c7eb723df3738 --- .github/actions/configure-docker/action.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/actions/configure-docker/action.yml b/.github/actions/configure-docker/action.yml index 9c2ce93f7a6..fc014156590 100644 --- a/.github/actions/configure-docker/action.yml +++ b/.github/actions/configure-docker/action.yml @@ -4,12 +4,21 @@ inputs: cache-provider: description: 'gha or cirrus cache provider' required: true - options: - - gh - - cirrus runs: using: 'composite' steps: + - name: Check inputs + shell: bash + run: | + # We expect only gha or cirrus as inputs to cache-provider + case "${{ inputs.cache-provider }}" in + gha|cirrus) + ;; + *) + echo "::warning title=Unknown input to configure docker action::Provided value was ${{ inputs.cache-provider }}" + ;; + esac + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: From c0d851e6c69ba8fc1d70b89e0660831c8fb9e633 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 8 Oct 2025 18:22:42 +0100 Subject: [PATCH 16/21] qt: Modernize custom filtering In `QSortFilterProxyModel`, `invalidateFilter()` is scheduled for deprecation in Qt 6.13. `beginFilterChange()` was introduced in Qt 6.9. `endFilterChange()` was introduced in Qt 6.10. Github-Pull: gui#899 Rebased-From: e15e8cbadad5ce1de41ebb817b87054f8b5192f2 --- src/qt/transactionfilterproxy.cpp | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 1ad77fd767f..89099260a9c 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -52,32 +52,78 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex & void TransactionFilterProxy::setDateRange(const std::optional& from, const std::optional& to) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + dateFrom = from; dateTo = to; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } void TransactionFilterProxy::setSearchString(const QString &search_string) { if (m_search_string == search_string) return; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + m_search_string = search_string; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } void TransactionFilterProxy::setTypeFilter(quint32 modes) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + this->typeFilter = modes; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } void TransactionFilterProxy::setMinAmount(const CAmount& minimum) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + this->minAmount = minimum; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } void TransactionFilterProxy::setShowInactive(bool _showInactive) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + this->showInactive = _showInactive; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } From e2c71c4fca44e14366653eedb8a15183d6a0444b Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 8 Nov 2025 19:08:25 +0000 Subject: [PATCH 17/21] doc: Correct `pkgin` command usage on NetBSD Github-Pull: #33827 Rebased-From: 0698c6b494de0e28c9b909585905aab5b187286e --- doc/build-netbsd.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md index f2631777221..b3b781521e4 100644 --- a/doc/build-netbsd.md +++ b/doc/build-netbsd.md @@ -34,7 +34,7 @@ cmake -B build SQLite is required for the wallet: ```bash -pkgin sqlite3 +pkgin install sqlite3 ``` To build Bitcoin Core without the wallet, use `-DENABLE_WALLET=OFF`. @@ -42,7 +42,7 @@ To build Bitcoin Core without the wallet, use `-DENABLE_WALLET=OFF`. Cap'n Proto is needed for IPC functionality (see [multiprocess.md](multiprocess.md)): ```bash -pkgin capnproto +pkgin install capnproto ``` Compile with `-DENABLE_IPC=OFF` if you do not need IPC functionality. @@ -84,7 +84,7 @@ Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` Bitcoin Core can provide notifications via ZeroMQ. If the package is installed, support will be compiled in. ```bash -pkgin zeromq +pkgin install zeromq ``` #### Test Suite Dependencies From a0a2b0770164b606780c707d6d0a82a02ff9039f Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 8 Nov 2025 16:47:27 +0000 Subject: [PATCH 18/21] scripted-diff: Remove obsolete comment The removed comment become obsolete after bitcoin/bitcoin#32697 and bitcoin/bitcoin#32881. -BEGIN VERIFY SCRIPT- sed -i "s/ Some tests are disabled if Python 3 is not available.//g" \ $( git grep -l " Some tests are disabled if Python 3 is not available." ./doc/ ) -END VERIFY SCRIPT- Github-Pull: #33826 Rebased-From: 36724205fc1f226d7b5493ed0212c336e7f2ae84 --- doc/build-freebsd.md | 2 +- doc/build-netbsd.md | 2 +- doc/build-openbsd.md | 2 +- doc/build-osx.md | 2 +- doc/build-windows-msvc.md | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index fee20f84ab5..b5940c0f7ce 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -101,5 +101,5 @@ cmake -B build -DENABLE_WALLET=OFF ```bash cmake --build build # Append "-j N" for N parallel jobs. -ctest --test-dir build # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. +ctest --test-dir build # Append "-j N" for N parallel tests. ``` diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md index b3b781521e4..103e62568a4 100644 --- a/doc/build-netbsd.md +++ b/doc/build-netbsd.md @@ -115,5 +115,5 @@ Build and run the tests: ```bash cmake --build build # Append "-j N" for N parallel jobs. -ctest --test-dir build # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. +ctest --test-dir build # Append "-j N" for N parallel tests. ``` diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index 99d4ec25165..fdeafe88d76 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -93,7 +93,7 @@ Run `cmake -B build -LH` to see the full list of available options. ```bash cmake --build build # Append "-j N" for N parallel jobs. -ctest --test-dir build # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. +ctest --test-dir build # Append "-j N" for N parallel tests. ``` ## Resource limits diff --git a/doc/build-osx.md b/doc/build-osx.md index e1bf037490a..001c0188e8a 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -170,7 +170,7 @@ Run the following in your terminal to compile Bitcoin Core: ``` bash cmake --build build # Append "-j N" here for N parallel jobs. -ctest --test-dir build # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. +ctest --test-dir build # Append "-j N" for N parallel tests. ``` ### 3. Deploy (optional) diff --git a/doc/build-windows-msvc.md b/doc/build-windows-msvc.md index 2d85d223e97..712ff8bb57c 100644 --- a/doc/build-windows-msvc.md +++ b/doc/build-windows-msvc.md @@ -55,7 +55,7 @@ In the following instructions, the "Debug" configuration can be specified instea ``` cmake -B build --preset vs2022-static # It might take a while if the vcpkg binary cache is unpopulated or invalidated. cmake --build build --config Release # Append "-j N" for N parallel jobs. -ctest --test-dir build --build-config Release # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. +ctest --test-dir build --build-config Release # Append "-j N" for N parallel tests. cmake --install build --config Release # Optional. ``` @@ -64,7 +64,7 @@ cmake --install build --config Release # Optional. ``` cmake -B build --preset vs2022 -DBUILD_GUI=OFF # It might take a while if the vcpkg binary cache is unpopulated or invalidated. cmake --build build --config Release # Append "-j N" for N parallel jobs. -ctest --test-dir build --build-config Release # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available. +ctest --test-dir build --build-config Release # Append "-j N" for N parallel tests. ``` ### 6. vcpkg-specific Issues and Workarounds From 577ddf6f5d1e7b01c496350206ac8fc33178e416 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 18 Nov 2025 22:35:41 +0000 Subject: [PATCH 19/21] depends: Add patch for Windows11Style plugin Github-Pull: #33906 Rebased-From: 8558902e576e2c2d66f6083b66953dd6cc464de4 --- depends/packages/qt.mk | 2 + .../qt/qtbase_plugins_windows11style.patch | 113 ++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 depends/patches/qt/qtbase_plugins_windows11style.patch diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 9ac4088e81c..608e8cdbff0 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -16,6 +16,7 @@ $(package)_patches += qtbase_avoid_native_float16.patch $(package)_patches += qtbase_avoid_qmain.patch $(package)_patches += qtbase_platformsupport.patch $(package)_patches += qtbase_plugins_cocoa.patch +$(package)_patches += qtbase_plugins_windows11style.patch $(package)_patches += qtbase_skip_tools.patch $(package)_patches += rcc_hardcode_timestamp.patch $(package)_patches += qttools_skip_dependencies.patch @@ -261,6 +262,7 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/qtbase_avoid_qmain.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase_platformsupport.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase_plugins_cocoa.patch && \ + patch -p1 -i $($(package)_patch_dir)/qtbase_plugins_windows11style.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase_skip_tools.patch && \ patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch endef diff --git a/depends/patches/qt/qtbase_plugins_windows11style.patch b/depends/patches/qt/qtbase_plugins_windows11style.patch new file mode 100644 index 00000000000..16d1d3ab5ae --- /dev/null +++ b/depends/patches/qt/qtbase_plugins_windows11style.patch @@ -0,0 +1,113 @@ +QWindows11Style: Calculate Spinbox size based on CommonStyle size +Use the calculation from Commonstyle and add the increased padding and +horizontally layouted buttons to the horizontal size hint. + +Fixes: QTBUG-130288 +Change-Id: I7932b782e7873a0178091a51379f17453eb585fd + +Upstream commits: + - Qt 6.8.1: 9107817eaceaacc968dbc767c24594566d637b8c + - Qt 6.9.0: 96d46cad43517adefa2eb7cb8819a0b2cc9241e6 + +--- a/qtbase/src/plugins/styles/modernwindows/qwindows11style.cpp ++++ b/qtbase/src/plugins/styles/modernwindows/qwindows11style.cpp +@@ -2048,39 +2048,22 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o + } + break; + #endif ++#if QT_CONFIG(spinbox) + case QStyle::CT_SpinBox: { + if (const auto *spinBoxOpt = qstyleoption_cast(option)) { + // Add button + frame widths +- int width = 0; +- +- if (const QDateTimeEdit *spinBox = qobject_cast(widget)) { +- const QSize textSizeMin = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->minimumDateTime().toString(spinBox->displayFormat())); +- const QSize textSizeMax = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->maximumDateTime().toString(spinBox->displayFormat())); +- width = qMax(textSizeMin.width(),textSizeMax.width()); +- } else if (const QSpinBox *spinBox = qobject_cast(widget)) { +- const QSize textSizeMin = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, QString::number(spinBox->minimum())); +- const QSize textSizeMax = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, QString::number(spinBox->maximum())); +- width = qMax(textSizeMin.width(),textSizeMax.width()); +- width += spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->prefix()).width(); +- width += spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->suffix()).width(); +- +- } else if (const QDoubleSpinBox *spinBox = qobject_cast(widget)) { +- const QSize textSizeMin = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, QString::number(spinBox->minimum())); +- const QSize textSizeMax = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, QString::number(spinBox->maximum())); +- width = qMax(textSizeMin.width(),textSizeMax.width()); +- width += spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->prefix()).width(); +- width += spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->suffix()).width(); +- } + const qreal dpi = QStyleHelper::dpi(option); + const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons); +- const int buttonWidth = hasButtons ? 2 * qRound(QStyleHelper::dpiScaled(16, dpi)) : 0; ++ const int margins = 8; ++ const int buttonWidth = hasButtons ? qRound(QStyleHelper::dpiScaled(16, dpi)) : 0; + const int frameWidth = spinBoxOpt->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, + spinBoxOpt, widget) : 0; +- contentSize.setWidth(2 * 12 + width); +- contentSize += QSize(buttonWidth + 2 * frameWidth, 2 * frameWidth); ++ ++ contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth); + } + break; + } ++#endif + default: + contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget); + break; + + +Windows11Style: don't set minimum width for QAbstractSpinBox + +There is no need to set a minimum width for QAbstractSpinBox in +QWindows11Style::polish() as this might override the user preferences. +Also the minimum size handling is now properly done within +sizeFromContents(). + +Change-Id: Ibc1fd7a6f862fc85e3739025b9de581aa235d74c + +Upstream commits: + - Qt 6.8.3: f86da3d3f853adb1a5b823c1cc7be6db4a0265f3 + - Qt 6.9.0: b93a8dfdfe6900cb542fdc587dd2682007a6ac53 + - Qt 6.10.0: 2ec4c28470de115c16944653a5d4f6209452d56c + +--- a/qtbase/src/plugins/styles/modernwindows/qwindows11style.cpp ++++ b/qtbase/src/plugins/styles/modernwindows/qwindows11style.cpp +@@ -29,7 +29,6 @@ QT_BEGIN_NAMESPACE + + const static int topLevelRoundingRadius = 8; //Radius for toplevel items like popups for round corners + const static int secondLevelRoundingRadius = 4; //Radius for second level items like hovered menu item round corners +-constexpr QLatin1StringView originalWidthProperty("_q_windows11_style_original_width"); + + enum WINUI3Color { + subtleHighlightColor, //Subtle highlight based on alpha used for hovered elements +@@ -2140,13 +2139,6 @@ void QWindows11Style::polish(QWidget* widget) + pal.setColor(QPalette::ButtonText, pal.text().color()); + pal.setColor(QPalette::BrightText, pal.text().color()); + widget->setPalette(pal); +- } else if (widget->inherits("QAbstractSpinBox")) { +- const int minWidth = 2 * 24 + 40; +- const int originalWidth = widget->size().width(); +- if (originalWidth < minWidth) { +- widget->resize(minWidth, widget->size().height()); +- widget->setProperty(originalWidthProperty.constData(), originalWidth); +- } + } else if (widget->inherits("QAbstractButton") || widget->inherits("QToolButton")) { + widget->setAutoFillBackground(false); + auto pal = widget->palette(); +@@ -2191,13 +2183,6 @@ void QWindows11Style::unpolish(QWidget *widget) + scrollarea->viewport()->setPalette(pal); + scrollarea->viewport()->setProperty("_q_original_background_palette", QVariant()); + } +- if (widget->inherits("QAbstractSpinBox")) { +- const QVariant originalWidth = widget->property(originalWidthProperty.constData()); +- if (originalWidth.isValid()) { +- widget->resize(originalWidth.toInt(), widget->size().height()); +- widget->setProperty(originalWidthProperty.constData(), QVariant()); +- } +- } + } + + /* From 39d53dd8bf2a19dfdc6976e9d8e9c562065adc1d Mon Sep 17 00:00:00 2001 From: ismaelsadeeq Date: Wed, 22 Oct 2025 12:02:12 +0200 Subject: [PATCH 20/21] interfaces: add interruptWait method - This method can be used to cancel a running waitNext(). - This commit also adds a test case for interruptWait method Github-Pull: #33676 Rebased-From: dcb56fd4cb59e6857c110dd87019459989dc1ec3 --- src/interfaces/mining.h | 5 +++++ src/ipc/capnp/mining.capnp | 1 + src/node/interfaces.cpp | 8 +++++++- src/node/miner.cpp | 16 ++++++++++++++-- src/node/miner.h | 6 +++++- test/functional/interface_ipc.py | 22 ++++++++++++++++++++++ 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 150295e5b7b..a30c4afb526 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -72,6 +72,11 @@ public: * the tip is more than 20 minutes old. */ virtual std::unique_ptr waitNext(const node::BlockWaitOptions options = {}) = 0; + + /** + * Interrupts the current wait for the next block template. + */ + virtual void interruptWait() = 0; }; //! Interface giving clients (RPC, Stratum v2 Template Provider in the future) diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp index 8ee4745b858..ed01e44a32a 100644 --- a/src/ipc/capnp/mining.capnp +++ b/src/ipc/capnp/mining.capnp @@ -33,6 +33,7 @@ interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { getCoinbaseMerklePath @8 (context: Proxy.Context) -> (result: List(Data)); submitSolution @9 (context: Proxy.Context, version: UInt32, timestamp: UInt32, nonce: UInt32, coinbase :Data) -> (result: Bool); waitNext @10 (context: Proxy.Context, options: BlockWaitOptions) -> (result: BlockTemplate); + interruptWait @11() -> (); } struct BlockCreateOptions $Proxy.wrap("node::BlockCreateOptions") { diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index fd3fa226cae..509528d9c06 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -918,15 +918,21 @@ public: std::unique_ptr waitNext(BlockWaitOptions options) override { - auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options); + auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options, m_interrupt_wait); if (new_template) return std::make_unique(m_assemble_options, std::move(new_template), m_node); return nullptr; } + void interruptWait() override + { + InterruptWait(notifications(), m_interrupt_wait); + } + const BlockAssembler::Options m_assemble_options; const std::unique_ptr m_block_template; + bool m_interrupt_wait{false}; ChainstateManager& chainman() { return *Assert(m_node.chainman); } KernelNotifications& notifications() { return *Assert(m_node.notifications); } NodeContext& m_node; diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 28e9048a4dd..39f0879ce2c 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -454,12 +454,20 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t block.hashMerkleRoot = BlockMerkleRoot(block); } +void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait) +{ + LOCK(kernel_notifications.m_tip_block_mutex); + interrupt_wait = true; + kernel_notifications.m_tip_block_cv.notify_all(); +} + std::unique_ptr WaitAndCreateNewBlock(ChainstateManager& chainman, KernelNotifications& kernel_notifications, CTxMemPool* mempool, const std::unique_ptr& block_template, const BlockWaitOptions& options, - const BlockAssembler::Options& assemble_options) + const BlockAssembler::Options& assemble_options, + bool& interrupt_wait) { // Delay calculating the current template fees, just in case a new block // comes in before the next tick. @@ -484,8 +492,12 @@ std::unique_ptr WaitAndCreateNewBlock(ChainstateManager& chainma // method on BlockTemplate and no template could have been // generated before a tip exists. tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock; - return tip_changed || chainman.m_interrupt; + return tip_changed || chainman.m_interrupt || interrupt_wait; }); + if (interrupt_wait) { + interrupt_wait = false; + return nullptr; + } } if (chainman.m_interrupt) return nullptr; diff --git a/src/node/miner.h b/src/node/miner.h index a9a88b39cf2..0790835d8f1 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -238,6 +238,9 @@ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& opti /* Compute the block's merkle root, insert or replace the coinbase transaction and the merkle root into the block */ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce); + +/* Interrupt the current wait for the next block template. */ +void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait); /** * Return a new block template when fees rise to a certain threshold or after a * new tip; return nullopt if timeout is reached. @@ -247,7 +250,8 @@ std::unique_ptr WaitAndCreateNewBlock(ChainstateManager& chainma CTxMemPool* mempool, const std::unique_ptr& block_template, const BlockWaitOptions& options, - const BlockAssembler::Options& assemble_options); + const BlockAssembler::Options& assemble_options, + bool& interrupt_wait); /* Locks cs_main and returns the block hash and block height of the active chain if it exists; otherwise, returns nullopt.*/ std::optional GetTip(ChainstateManager& chainman); diff --git a/test/functional/interface_ipc.py b/test/functional/interface_ipc.py index abcc4d6b5d1..2c9a0022442 100755 --- a/test/functional/interface_ipc.py +++ b/test/functional/interface_ipc.py @@ -184,6 +184,28 @@ class IPCInterfaceTest(BitcoinTestFramework): template7 = await template6.result.waitNext(ctx, waitoptions) assert_equal(template7.to_dict(), {}) + self.log.debug("interruptWait should abort the current wait") + wait_started = asyncio.Event() + async def wait_for_block(): + new_waitoptions = self.capnp_modules['mining'].BlockWaitOptions() + new_waitoptions.timeout = waitoptions.timeout * 60 # 1 minute wait + new_waitoptions.feeThreshold = 1 + wait_started.set() + return await template6.result.waitNext(ctx, new_waitoptions) + + async def interrupt_wait(): + await wait_started.wait() # Wait for confirmation wait started + await asyncio.sleep(0.1) # Minimal buffer + template6.result.interruptWait() + miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0]) + + wait_task = asyncio.create_task(wait_for_block()) + interrupt_task = asyncio.create_task(interrupt_wait()) + + result = await wait_task + await interrupt_task + assert_equal(result.to_dict(), {}) + current_block_height = self.nodes[0].getchaintips()[0]["height"] check_opts = self.capnp_modules['mining'].BlockCheckOptions() template = await mining.result.createNewBlock(opts) From b2cb203af05743ea5c130913afa7549c02d1bae5 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 13 Oct 2025 15:14:21 +0100 Subject: [PATCH 21/21] doc: update release notes for 30.x --- doc/release-notes.md | 396 +++---------------------------------------- 1 file changed, 27 insertions(+), 369 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index a855d10cc98..43aff7ec531 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,9 +1,9 @@ -v30.0 Release Notes +v30.x Release Notes =================== -Bitcoin Core version v30.0 is now available from: +Bitcoin Core version v30.x is now available from: - + This release includes new features, various bug fixes and performance improvements, as well as updated translations. @@ -40,399 +40,57 @@ unsupported systems. Notable changes =============== -Policy ------- +### Build -- The maximum number of potentially executed legacy signature operations in a - single standard transaction is now limited to 2500. Signature operations in all - previous output scripts, in all input scripts, as well as all P2SH redeem - scripts (if there are any) are counted toward the limit. The new limit is - assumed to not affect any known typically formed standard transactions. The - change was done to prepare for a possible BIP54 deployment in the future. (#32521) +- #33580 depends: Use `$(package)_file_name` when downloading from the fallback +- #33906 depends: Add patch for Windows11Style plugin -- `-datacarriersize` is increased to 100,000 by default, which effectively uncaps - the limit (as the maximum transaction size limit will be hit first). It can be - overridden with `-datacarriersize=83` to revert to the limit enforced in previous - versions. (#32406) +### IPC -- Multiple data carrier (OP_RETURN) outputs in a transaction are now permitted for - relay and mining. The `-datacarriersize` limit applies to the aggregate size of - the scriptPubKeys across all such outputs in a transaction, not including the - scriptPubKey size itself. (#32406) +- #33229 multiprocess: Don't require bitcoin -m argument when IPC options are used +- #33517 multiprocess: Fix high overhead from message logging +- #33519 Update libmultiprocess subtree in 30.x branch +- #33566 miner: fix empty mempool case for waitNext() +- #33676 interfaces: enable cancelling running waitNext calls -- The minimum block feerate (`-blockmintxfee`) has been changed to 0.001 satoshi per - vB. It can still be changed using the configuration option. This option can be used - by miners to set a minimum feerate on packages added to block templates. (#33106) +### GUI -- The default minimum relay feerate (`-minrelaytxfee`) and incremental relay feerate - (`-incrementalrelayfee`) have been changed to 0.1 satoshis per vB. They can still - be changed using their respective configuration options, but it is recommended to - change both together if you decide to do so. (#33106) +- gui#899 qt: Modernize custom filtering +- gui#901 Add createwallet, createwalletdescriptor, and migratewallet to history filter - Other minimum feerates (e.g. the dust feerate, the minimum returned by the fee - estimator, and all feerates used by the wallet) remain unchanged. The mempool minimum - feerate still changes in response to high volume. +### Test - Note that unless these lower defaults are widely adopted across the network, transactions - created with lower fee rates are not guaranteed to propagate or confirm. The wallet - feerates remain unchanged; `-mintxfee` must be changed before attempting to create - transactions with lower feerates using the wallet. (#33106) +- #33612 test: change log rate limit version gate -P2P and network changes ------------------------ +### Doc -- Opportunistic 1-parent-1-child package relay has been improved to handle - situations when the child already has unconfirmed parent(s) in the mempool. - This means that 1p1c packages can be accepted and propagate, even if they are - connected to broader topologies: multi-parent-1-child (where only 1 parent - requires fee-bumping), grandparent-parent-child (where only parent requires - fee-bumping) etc. (#31385) +- #33630 doc: correct topology requirements in submitpackage helptext +- #33826 scripted-diff: Remove obsolete comment +- #33827 doc: Correct pkgin command usage on NetBSD -- The transaction orphanage, which holds transactions with missing inputs temporarily - while the node attempts to fetch its parents, now has improved Denial of Service protections. - Previously, it enforced a maximum number of unique transactions (default 100, - configurable using `-maxorphantx`). Now, its limits are as follows: the number of - entries (unique by wtxid and peer), plus each unique transaction's input count divided - by 10, must not exceed 3,000. The total weight of unique transactions must not exceed - `404,000` Wu multiplied by the number of peers. (#31829) +### Misc -- The `-maxorphantx` option no longer has any effect, since the orphanage no longer - limits the number of unique transactions. Users should remove this configuration - option if they were using it, as the setting will cause an error in future versions - when it is no longer recognized. (#31829) - -New `bitcoin` command ---------------------- - -- A new `bitcoin` command line tool has been added to make features more discoverable - and convenient to use. The `bitcoin` tool just calls other executables and does not - implement any functionality on its own. Specifically `bitcoin node` is a synonym for - `bitcoind`, `bitcoin gui` is a synonym for `bitcoin-qt`, and `bitcoin rpc` is a synonym - for `bitcoin-cli -named`. Other commands and options can be listed with `bitcoin help`. - The new `bitcoin` command is an alternative to calling other commands directly, but it - doesn't replace them, and there are no plans to deprecate existing commands. (#31375) - -External Signing ----------------- - -- Support for external signing on Windows has been re-enabled. (#29868) - -IPC Mining Interface --------------------- - -- The new `bitcoin` command does support one new feature: an (experimental) IPC Mining - Interface that allows the node to work with Stratum v2 or other mining client software, - see (#31098). When the node is started with `bitcoin -m node -ipcbind=unix` it will - listen on a unix socket for IPC client connections, allowing clients to request block - templates and submit mined blocks. The `-m` option launches a new internal binary - (`bitcoin-node` instead of `bitcoind`) and is currently required but will become optional - in the future (with [#33229](https://github.com/bitcoin/bitcoin/pull/33229)). - -- IPC connectivity introduces new dependencies (see [multiprocess.md](https://github.com/bitcoin/bitcoin/blob/master/doc/multiprocess.md)), - which can be turned off with the `-DENABLE_IPC=OFF` build option if you do not intend - to use IPC. (#31802) - -Install changes ---------------- - -- The `test_bitcoin` executable is now installed in `libexec/` instead of `bin/`. - It can still be executed directly, or accessed through the new `bitcoin` command - as `bitcoin test`. The `libexec/` directory also contains new `bitcoin-node` and - `bitcoin-gui` binaries which support IPC features and are called through the - `bitcoin` tool. In source builds only, `test_bitcoin-qt`, `bench_bitcoin`, and - `bitcoin-chainstate` are also now installed to `libexec/` instead of `bin/` and - can be accessed through the new `bitcoin` command. See `bitcoin help` output for - details. (#31679) - -- On Windows, the installer no longer adds a “(64-bit)” suffix to entries in the - Start Menu (#32132), and it now automatically removes obsolete artifacts during - upgrades (#33422). - -Indexes -------- - -- The implementation of coinstatsindex was changed to prevent an overflow bug that - could already be observed on the default Signet. The new version of the index will - need to be synced from scratch when starting the upgraded node for the first time. - - The new version is stored in `/indexes/coinstatsindex/` in contrast to the old version - which was stored at `/indexes/coinstats/`. The old version of the index is not deleted - by the upgraded node in case the user chooses to downgrade their node in the future. - If the user does not plan to downgrade it is safe for them to remove `/indexes/coinstats/` - from their datadir. A future release of Bitcoin Core may remove the old version of the - index automatically. (#30469) - -Logging -------- -- Unconditional logging to disk is now rate limited by giving each source location - a quota of 1MiB per hour. Unconditional logging is any logging with a log level - higher than debug, that is `info`, `warning`, and `error`. All logs will be - prefixed with `[*]` if there is at least one source location that is currently - being suppressed. (#32604) - -- When `-logsourcelocations` is enabled, the log output now contains the entire - function signature instead of just the function name. (#32604) - -Updated RPCs ------------- - -- The `-paytxfee` startup option and the `settxfee` RPC are now deprecated and - will be removed in Bitcoin Core 31.0. They allowed the user to set a static fee - rate for wallet transactions, which could potentially lead to overpaying or underpaying. - Users should instead rely on fee estimation or specify a fee rate per transaction - using the `fee_rate` argument in RPCs such as `fundrawtransaction`, `sendtoaddress`, - `send`, `sendall`, and `sendmany`. (#31278) - -- Any RPC in which one of the parameters is a descriptor will throw an error - if the provided descriptor contains a whitespace at the beginning or the end - of the public key within a fragment - e.g. `pk( KEY)` or `pk(KEY )`. (#31603) - -- The `submitpackage` RPC, which allows submissions of child-with-parents - packages, no longer requires that all unconfirmed parents be present. The - package may contain other in-mempool ancestors as well. (#31385) - -- The `waitfornewblock` RPC now takes an optional `current_tip` argument. It - is also no longer hidden. (#30635) - -- The `waitforblock` and `waitforblockheight` RPCs are no longer hidden. (#30635) - -- The `psbtbumpfee` and `bumpfee` RPCs allow a replacement under fullrbf and no - longer require BIP-125 signalling. (#31953) - -- Transaction Script validation errors used to return the reason for the error - prefixed by either `mandatory-script-verify-flag-failed` if it was a consensus - error, or `non-mandatory-script-verify-flag` (without "-failed") if it was a - standardness error. This has been changed to `block-script-verify-flag-failed` - and `mempool-script-verify-flag-failed` for all block and mempool errors - respectively. (#33183) - -- The `getmininginfo` RPC now returns "blockmintxfee" result specifying the value of - `-blockmintxfee` configuration. (#33189) - -- The `getmempoolinfo` RPC now returns an additional "permitbaremultisig" and - "maxdatacarriersize" field, reflecting the `-permitbaremultisig` and `-datacarriersize` - config values. (#29954) - -Changes to wallet-related RPCs can be found in the Wallet section below. - -New RPCs --------- - -- A new REST API endpoint (`/rest/spenttxouts/BLOCKHASH`) has been introduced for - efficiently fetching spent transaction outputs using the block's undo data (#32540). - -Build System ------------- - -Updated settings ----------------- - -- The `-maxmempool` and `-dbcache` startup parameters are now capped on 32-bit systems - to 500MB and 1GiB respectively. (#32530) - -- The `-natpmp` option is now set to `1` by default. This means nodes with `-listen` - enabled (the default) but running behind a firewall, such as a local network router, - will be reachable if the firewall/router supports any of the `PCP` or `NAT-PMP` - protocols. (#33004) - -- The `-upnp` setting has now been fully removed. Use `-natpmp` instead. (#32500) - -- Previously, `-proxy` specified the proxy for all networks (except I2P which - uses `-i2psam`) and only the Tor proxy could have been specified separately - via `-onion`. Now, the syntax of `-proxy` has been extended and it is possible - to specify separately the proxy for IPv4, IPv6, Tor and CJDNS by appending `=` - followed by the network name, for example `-proxy=127.0.0.1:5555=ipv6` - configures a proxy only for IPv6. The `-proxy` option can be used multiple - times to define different proxies for different networks, such as - `-proxy=127.0.0.1:4444=ipv4 -proxy=10.0.0.1:6666=ipv6`. Later settings - override earlier ones for the same network; this can be used to remove an - earlier all-networks proxy and use direct connections only for a given - network, for example `-proxy=127.0.0.1:5555 -proxy=0=cjdns`. (#32425) - -- The `-blockmaxweight` startup option has been updated to be debug-only. - It is still available to users, but now hidden from the default `-help` text - and shown only in `-help-debug` (#32654). - -Changes to GUI or wallet related settings can be found in the GUI or Wallet section below. - -Wallet ------- - -- BDB legacy wallets can no longer be created or loaded. They can be migrated - to the new descriptor wallet format. Refer to the `migratewallet` RPC for more - details. - -- The legacy wallet removal drops redundant options in the bitcoin-wallet tool, - such as `-withinternalbdb`, `-legacy`, and `-descriptors`. Moreover, the - legacy-only RPCs `addmultisigaddress`, `dumpprivkey`, `dumpwallet`, - `importaddress`, `importmulti`, `importprivkey`, `importpubkey`, - `importwallet`, `newkeypool`, `sethdseed`, and `upgradewallet`, are removed. - (#32944, #28710, #32438, #31250) - -- Support has been added for spending TRUC transactions received by the - wallet, as well as creating TRUC transactions. The wallet ensures that - TRUC policy rules are being met. The wallet will throw an error if the - user is trying to spend TRUC utxos with utxos of other versions. - Additionally, the wallet will treat unconfirmed TRUC sibling - transactions as mempool conflicts. The wallet will also ensure that - transactions spending TRUC utxos meet the required size restrictions. (#32896) - -- Since descriptor wallets do not allow mixing watchonly and non-watchonly descriptors, - the `include_watchonly` option (and its variants in naming) are removed from all RPCs - that had it. (#32618) - -- The `iswatchonly` field is removed from any RPCs that returned it. (#32618) - -- `unloadwallet` - Return RPC_INVALID_PARAMETER when both the RPC wallet endpoint - and wallet_name parameters are unspecified. Previously the RPC failed with a JSON - parsing error. (#32845) - -- `getdescriptoractivity` - Mark blockhashes and scanobjects arguments as required, - so the user receives a clear help message when either is missing. As in `unloadwallet`, - previously the RPC failed with a JSON parsing error. (#32845) - -- `getwalletinfo` - Removes the fields `balance`, `immature_balance` and - `unconfirmed_balance`. (#32721) - -- `getunconfirmedbalance` - Removes this RPC command. You can query the `getbalances` - RPC and inspect the `["mine"]["untrusted_pending"]` entry within the JSON - response. (#32721) - -- The following RPCs now contain a `version` parameter that allows - the user to create transactions of any standard version number (1-3): - - `createrawtransaction` - - `createpsbt` - - `send` - - `sendall` - - `walletcreatefundedpsbt` - (#32896) - -GUI changes ------------ - -- The GUI has been migrated from Qt 5 to Qt 6. On Windows, dark mode is now supported. - On macOS, the Metal backend is now used. (#30997) - -- A transaction's fee bump is allowed under fullrbf and no longer requires - BIP-125 signalling. (#31953) - -- Custom column widths in the Transactions tab are reset as a side-effect of legacy - wallet removal. (#32459) - -Low-level changes -================= - -- Logs now include which peer sent us a header. Additionally there are fewer - redundant header log messages. A side-effect of this change is that for - some untypical cases new headers aren't logged anymore, e.g. a direct - `BLOCK` message with a previously unknown header and `submitheader` RPC. (#27826) +- #33508 ci: fix buildx gha cache authentication on forks +- #33558 ci: Use native platform for win-cross task +- #33581 ci: Properly include $FILE_ENV in DEPENDS_HASH +- #33744 ci: Fix lint runner selection (and docker cache) Credits ======= Thanks to everyone who directly contributed to this release: -- 0xb10c -- amisha -- Andrew Toth -- Anthony Towns -- Antoine Poinsot - Ava Chow -- benthecarman -- Brandon Odiwuor -- brunoerg -- Bue-von-hon -- Bufo -- Chandra Pratap -- Chris Stewart - Cory Fields -- Daniel Pfeifer -- Daniela Brozzoni -- David Gumberg -- deadmanoz -- dennsikl -- dergoegge -- enoch -- Ethan Heilman - Eugene Siegel -- Eunovo -- Eval EXEC -- Fabian Jahr -- fanquake -- Florian Schmaus -- fuder.eth -- furszy - glozow -- Greg Sanders -- Hao Xu -- Haoran Peng -- Haowen Liu - Hennadii Stepanov -- Hodlinator -- hoffman -- ishaanam - ismaelsadeeq -- Jameson Lopp -- janb84 -- Jiri Jakes -- John Bampton -- Jon Atack -- josibake -- jurraca -- kevkevin -- kevkevinpal -- kilavvy -- Kristaps Kaupe -- l0rinc -- laanwj -- leopardracer -- Lőrinc -- Luis Schwab -- Luke Dashjr - MarcoFalke -- marcofleon -- Martin Zumsande -- Matt Corallo -- Matthew Zipkin -- Max Edwards -- monlovesmango -- Murch -- naiyoma -- nervana21 -- Nicola Leonardo Susca -- Novo -- pablomartin4btc -- Peter Todd -- Pieter Wuille -- Pol Espinasa -- Prabhat Verma -- rkrux -- Roman Zeyde - Ryan Ofsky -- Saikiran -- Salvatore Ingala -- Sebastian Falbesoner -- Sergi Delgado Segura -- Shunsuke Shimizu - Sjors Provoost -- stickies-v -- stratospher -- stringintech -- strmfos -- stutxo -- tdb3 -- TheCharlatan -- Tomás Andróil -- UdjinM6 -- Vasil Dimov -- VolodymyrBg -- w0xlt -- will +- WakeTrainDev - willcl-ark -- William Casarin -- woltx -- yancy -- zaidmstrr As well as to everyone that helped with translations on [Transifex](https://explore.transifex.com/bitcoin/bitcoin/).