diff --git a/.editorconfig b/.editorconfig index c5f3028c5036..d7fe7ad5e244 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,7 +13,7 @@ trim_trailing_whitespace = true [*.{h,cpp,rs,py,sh}] indent_size = 4 -# .cirrus.yml, etc. +# ci.yml, etc. [*.yml] indent_size = 2 diff --git a/.github/actions/configure-docker/action.yml b/.github/actions/configure-docker/action.yml index 9bf970ee78f3..af667f0fdb51 100644 --- a/.github/actions/configure-docker/action.yml +++ b/.github/actions/configure-docker/action.yml @@ -1,7 +1,7 @@ name: 'Configure Docker' description: 'Set up Docker build driver and configure build cache args' inputs: - use-cirrus: + use-warp: description: 'Use cirrus cache' required: true runs: @@ -35,12 +35,7 @@ runs: # Docker will check for variables $ACTIONS_CACHE_URL, $ACTIONS_RESULTS_URL and $ACTIONS_RUNTIME_TOKEN # which are set automatically when running on GitHub infra: https://docs.docker.com/build/cache/backends/gha/#synopsis - # Use cirrus cache host - if [[ ${{ inputs.use-cirrus }} == 'true' ]]; then - url_args="url=${CIRRUS_CACHE_HOST},url_v2=${CIRRUS_CACHE_HOST}" - else - url_args="" - fi + url_args="" # Always optimistically --cache‑from in case a cache blob exists args=(--cache-from "type=gha${url_args:+,${url_args}},scope=${CONTAINER_NAME}") diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0af3eb95fe1..2a6839706141 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,29 +19,29 @@ concurrency: env: CI_FAILFAST_TEST_LEAVE_DANGLING: 1 # GHA does not care about dangling processes and setting this variable avoids killing the CI script itself on error - CIRRUS_CACHE_HOST: http://127.0.0.1:12321/ # When using Cirrus Runners this host can be used by the docker `gha` build cache type. - REPO_USE_CIRRUS_RUNNERS: 'bitcoin/bitcoin' # Use cirrus runners and cache for this repo, instead of falling back to the slow GHA runners + REPO_USE_WARP_RUNNERS: 'bitcoin/bitcoin' # Use warp runners for this repo, instead of falling back to the slow GHA runners jobs: runners: name: 'determine runners' runs-on: ubuntu-latest outputs: - use-cirrus-runners: ${{ steps.runners.outputs.use-cirrus-runners }} + use-warp-runners: ${{ steps.runners.outputs.use-warp-runners }} steps: - id: runners run: | - if [[ "${REPO_USE_CIRRUS_RUNNERS}" == "${{ github.repository }}" ]]; then - echo "use-cirrus-runners=true" >> "$GITHUB_OUTPUT" - echo "::notice title=Runner Selection::Using Cirrus Runners" + if [[ "${REPO_USE_WARP_RUNNERS}" == "${{ github.repository }}" ]]; then + echo "provider=warp" >> "$GITHUB_OUTPUT" + echo "::notice title=Runner Selection::Using Warp Runners" else - echo "use-cirrus-runners=false" >> "$GITHUB_OUTPUT" + echo "use-warp-runners=false" >> "$GITHUB_OUTPUT" echo "::notice title=Runner Selection::Using GitHub-hosted runners" fi test-each-commit: name: 'test each commit' - runs-on: ubuntu-24.04 + needs: runners + runs-on: ${{ needs.runners.outputs.provider == 'warp' && 'warp-ubuntu-latest-x64-8x' || 'ubuntu-latest' }} if: github.event_name == 'pull_request' && github.event.pull_request.commits != 1 timeout-minutes: 360 # Use maximum time, see https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes. Assuming a worst case time of 1 hour per commit, this leads to a --max-count=6 below. env: @@ -292,7 +292,7 @@ jobs: ci-matrix: name: ${{ matrix.name }} needs: runners - runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && matrix.cirrus-runner || matrix.fallback-runner }} + runs-on: ${{ needs.runners.outputs.provider == 'warp' && matrix.warp-runner || matrix.fallback-runner }} if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }} timeout-minutes: ${{ matrix.timeout-minutes }} @@ -305,74 +305,74 @@ jobs: matrix: include: - name: '32 bit ARM, unit tests, no functional tests' - cirrus-runner: 'ubuntu-24.04-arm' # Cirrus' Arm runners are Apple (with virtual Linux aarch64), which doesn't support 32-bit mode + warp-runner: 'ubuntu-24.04-arm' # Warp's Arm runners don't support 32-bit mode currently fallback-runner: 'ubuntu-24.04-arm' timeout-minutes: 120 file-env: './ci/test/00_setup_env_arm.sh' - name: 'win64 Cross' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-4x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_win64.sh' - name: 'ASan + LSan + UBSan + integer, no depends, USDT' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' # has to match container in ci/test/00_setup_env_native_asan.sh for tracing tools - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-2404-x64-8x' # has to match container in ci/test/00_setup_env_native_asan.sh for tracing tools + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_native_asan.sh' - name: 'macOS-cross, gui, no tests' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-4x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_mac_cross.sh' - name: 'No wallet, libbitcoinkernel' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-4x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh' - name: 'i686, multiprocess, DEBUG' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-8x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_i686_multiprocess.sh' - name: 'fuzzer,address,undefined,integer, no depends' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-16x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 240 file-env: './ci/test/00_setup_env_native_fuzz.sh' - name: 'previous releases, depends DEBUG' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-8x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_native_previous_releases.sh' - name: 'CentOS, depends, gui' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-16x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_native_centos.sh' - name: 'tidy' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-8x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_native_tidy.sh' - name: 'TSan, depends, no gui' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-8x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_native_tsan.sh' - name: 'MSan, depends' - cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg' - fallback-runner: 'ubuntu-24.04' + warp-runner: 'warp-ubuntu-latest-x64-16x' + fallback-runner: 'ubuntu-latest' timeout-minutes: 120 file-env: './ci/test/00_setup_env_native_msan.sh' @@ -389,7 +389,7 @@ jobs: - name: Configure Docker uses: ./.github/actions/configure-docker with: - use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }} + use-warp: ${{ needs.runners.outputs.use-warp-runners }} - name: Enable bpfcc script if: ${{ env.CONTAINER_NAME == 'ci_native_asan' }} @@ -411,7 +411,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 == 'warp' && 'warp-ubuntu-latest-x64-2x' || 'ubuntu-latest' }} if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }} timeout-minutes: 20 env: @@ -426,7 +426,7 @@ jobs: - name: Configure Docker uses: ./.github/actions/configure-docker with: - use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }} + use-warp: ${{ needs.runners.outputs.use-warp-runners }} - name: CI script run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index ed59b307cd7b..46980b32db89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,9 +28,9 @@ get_directory_property(precious_variables CACHE_VARIABLES) #============================= set(CLIENT_NAME "Bitcoin Core") set(CLIENT_VERSION_MAJOR 29) -set(CLIENT_VERSION_MINOR 3) +set(CLIENT_VERSION_MINOR 4) set(CLIENT_VERSION_BUILD 0) -set(CLIENT_VERSION_RC 2) +set(CLIENT_VERSION_RC 0) set(CLIENT_VERSION_IS_RELEASE "true") set(COPYRIGHT_YEAR "2025") @@ -111,8 +111,12 @@ if(WITH_SQLITE) if(VCPKG_TARGET_TRIPLET) # Use of the `unofficial::` namespace is a vcpkg package manager convention. find_package(unofficial-sqlite3 CONFIG REQUIRED) + add_library(SQLite3::SQLite3 ALIAS unofficial::sqlite3::sqlite3) else() find_package(SQLite3 3.7.17 REQUIRED) + if(NOT TARGET SQLite3::SQLite3) # CMake < 4.3 + add_library(SQLite3::SQLite3 ALIAS SQLite::SQLite3) + endif() endif() set(USE_SQLITE ON) endif() diff --git a/ci/README.md b/ci/README.md index 81e048ce687c..a73c8df5e753 100644 --- a/ci/README.md +++ b/ci/README.md @@ -61,13 +61,11 @@ trigger cache-invalidation and rebuilds as necessary. To configure the primary repository, follow these steps: -1. Register with [Cirrus Runners](https://cirrus-runners.app/) and purchase runners. -2. Install the Cirrus Runners GitHub app against the GitHub organization. +1. Register with [WarpBuild](https://www.warpbuild.com/) and purchase runners. +2. Install the WarpBuild GitHub app against the GitHub organization. 3. Enable organisation-level runners to be used in public repositories: 1. `Org settings -> Actions -> Runner Groups -> Default -> Allow public repos` 4. Permit the following actions to run: - 1. cirruslabs/cache/restore@\* - 1. cirruslabs/cache/save@\* 1. docker/setup-buildx-action@\* 1. actions/github-script@\* @@ -76,5 +74,5 @@ To configure the primary repository, follow these steps: When used in a fork the CI will run on GitHub's free hosted runners by default. In this case, due to GitHub's 10GB-per-repo cache size limitations caches will be frequently evicted and missed, but the workflows will run (slowly). -It is also possible to use your own Cirrus Runners in your own fork with an appropriate patch to the `REPO_USE_CIRRUS_RUNNERS` variable in ../.github/workflows/ci.yml -NB that Cirrus Runners only work at an organisation level, therefore in order to use your own Cirrus Runners, *the fork must be within your own organisation*. +It is also possible to use your own WarpBuild Runners in your own fork with an appropriate patch to the `REPO_USE_WARP_RUNNERS` variable in ../.github/workflows/ci.yml +NB that WarpBuild Runners only work at an organisation level, therefore in order to use your own WarpBuild Runners, *the fork must be within your own organisation*. diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh index d7c8e3ef1b91..44bc38e319cb 100755 --- a/ci/test/00_setup_env_i686_multiprocess.sh +++ b/ci/test/00_setup_env_i686_multiprocess.sh @@ -10,6 +10,7 @@ export HOST=i686-pc-linux-gnu export CONTAINER_NAME=ci_i686_multiprocess export CI_IMAGE_NAME_TAG="mirror.gcr.io/ubuntu:24.04" export CI_IMAGE_PLATFORM="linux/amd64" +export CI_CONTAINER_CAP="--security-opt seccomp=unconfined" export PACKAGES="llvm clang g++-multilib" export DEP_OPTS="DEBUG=1 MULTIPROCESS=1" export GOAL="install" diff --git a/contrib/guix/INSTALL.md b/contrib/guix/INSTALL.md index 910f8f25460f..df2728332af7 100644 --- a/contrib/guix/INSTALL.md +++ b/contrib/guix/INSTALL.md @@ -71,13 +71,13 @@ https://repology.org/project/guix/versions ### Debian / Ubuntu -Guix is available as a distribution package in [Debian -](https://packages.debian.org/search?keywords=guix) and [Ubuntu -](https://packages.ubuntu.com/search?keywords=guix). +Currently, the `guix` package is no longer present in recent Debian or Ubuntu +repositories. Any other installation option mentioned in this document may be +used. -To install: +If you previously installed `guix` via `apt`, you can remove it with: ```sh -sudo apt install guix +sudo apt purge guix ``` ### Arch Linux diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md index 252053e7b875..192182e17d68 100644 --- a/contrib/tracing/README.md +++ b/contrib/tracing/README.md @@ -22,7 +22,7 @@ corresponding packages. See [installing bpftrace] and [installing BCC] for more information. For development there exist a [bpftrace Reference Guide], a [BCC Reference Guide], and a [bcc Python Developer Tutorial]. -[installing bpftrace]: https://github.com/iovisor/bpftrace/blob/master/INSTALL.md +[installing bpftrace]: https://github.com/bpftrace/bpftrace/blob/master/README.md#quick-start [installing BCC]: https://github.com/iovisor/bcc/blob/master/INSTALL.md [bpftrace Reference Guide]: https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md [BCC Reference Guide]: https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md diff --git a/depends/gen_id b/depends/gen_id index fe6d163547ae..ab5b6fb58c6a 100755 --- a/depends/gen_id +++ b/depends/gen_id @@ -28,6 +28,10 @@ # Redirect stderr to stdout exec 2>&1 + # Unset SOURCE_DATE_EPOCH to prevent it from leaking into tool + # outputs and to maximize reuse of the built package cache. + unset SOURCE_DATE_EPOCH + echo "BEGIN ALL" # Include any ID salts supplied via command line diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index 549d189e7d14..63318840119a 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -86,7 +86,7 @@ Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` #### Notifications ###### ZeroMQ -Bitcoin Core can provide notifications via ZeroMQ. If the package is installed, support will be compiled in. +Bitcoin Core can provide notifications via ZeroMQ. To compile ZMQ support, install the following dependency and pass `-DWITH_ZMQ=ON` when configuring. ```bash pkg install libzmq4 ``` diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md index 05b80eb74760..5b01d7b912c8 100644 --- a/doc/build-netbsd.md +++ b/doc/build-netbsd.md @@ -86,7 +86,7 @@ Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` #### Notifications ###### ZeroMQ -Bitcoin Core can provide notifications via ZeroMQ. If the package is installed, support will be compiled in. +Bitcoin Core can provide notifications via ZeroMQ. To compile ZMQ support, install the following dependency and pass `-DWITH_ZMQ=ON` when configuring. ```bash pkgin zeromq ``` diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index 7ab51054ad2e..e2a15f67c867 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -80,7 +80,7 @@ Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` #### Notifications ###### ZeroMQ -Bitcoin Core can provide notifications via ZeroMQ. If the package is installed, support will be compiled in. +Bitcoin Core can provide notifications via ZeroMQ. To compile ZMQ support, install the following dependency and pass `-DWITH_ZMQ=ON` when configuring. ```bash pkg_add zeromq ``` diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1 index e762c0fa39db..d88916809acc 100644 --- a/doc/man/bitcoin-cli.1 +++ b/doc/man/bitcoin-cli.1 @@ -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 v29.3.0rc2" "User Commands" +.TH BITCOIN-CLI "1" "July 2026" "bitcoin-cli v29.4.0" "User Commands" .SH NAME -bitcoin-cli \- manual page for bitcoin-cli v29.3.0rc2 +bitcoin-cli \- manual page for bitcoin-cli v29.4.0 .SH SYNOPSIS .B bitcoin-cli [\fI\,options\/\fR] \fI\, \/\fR[\fI\,params\/\fR] @@ -15,7 +15,7 @@ bitcoin-cli \- manual page for bitcoin-cli v29.3.0rc2 .B bitcoin-cli [\fI\,options\/\fR] \fI\,help \/\fR .SH DESCRIPTION -Bitcoin Core RPC client version v29.3.0rc2 +Bitcoin Core RPC client version v29.4.0 .PP The bitcoin\-cli utility provides a command line interface to interact with a Bitcoin Core RPC server. .PP diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1 index 4a990e8082b8..4610681e31fa 100644 --- a/doc/man/bitcoin-qt.1 +++ b/doc/man/bitcoin-qt.1 @@ -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 v29.3.0rc2" "User Commands" +.TH BITCOIN-QT "1" "July 2026" "bitcoin-qt v29.4.0" "User Commands" .SH NAME -bitcoin-qt \- manual page for bitcoin-qt v29.3.0rc2 +bitcoin-qt \- manual page for bitcoin-qt v29.4.0 .SH SYNOPSIS .B bitcoin-qt [\fI\,options\/\fR] [\fI\,URI\/\fR] .SH DESCRIPTION -Bitcoin Core version v29.3.0rc2 +Bitcoin Core version v29.4.0 .PP The bitcoin\-qt application provides a graphical interface for interacting with Bitcoin Core. .PP diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1 index 7b3b996afd89..b2fc2b14093f 100644 --- a/doc/man/bitcoin-tx.1 +++ b/doc/man/bitcoin-tx.1 @@ -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 v29.3.0rc2" "User Commands" +.TH BITCOIN-TX "1" "July 2026" "bitcoin-tx v29.4.0" "User Commands" .SH NAME -bitcoin-tx \- manual page for bitcoin-tx v29.3.0rc2 +bitcoin-tx \- manual page for bitcoin-tx v29.4.0 .SH SYNOPSIS .B bitcoin-tx [\fI\,options\/\fR] \fI\, \/\fR[\fI\,commands\/\fR] @@ -9,7 +9,7 @@ bitcoin-tx \- manual page for bitcoin-tx v29.3.0rc2 .B bitcoin-tx [\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR] .SH DESCRIPTION -Bitcoin Core bitcoin\-tx utility version v29.3.0rc2 +Bitcoin Core bitcoin\-tx utility version v29.4.0 .PP The bitcoin\-tx tool is used for creating and modifying bitcoin transactions. .PP diff --git a/doc/man/bitcoin-util.1 b/doc/man/bitcoin-util.1 index d10f4b48b35b..a4e2543cbb09 100644 --- a/doc/man/bitcoin-util.1 +++ b/doc/man/bitcoin-util.1 @@ -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 v29.3.0rc2" "User Commands" +.TH BITCOIN-UTIL "1" "July 2026" "bitcoin-util v29.4.0" "User Commands" .SH NAME -bitcoin-util \- manual page for bitcoin-util v29.3.0rc2 +bitcoin-util \- manual page for bitcoin-util v29.4.0 .SH SYNOPSIS .B bitcoin-util [\fI\,options\/\fR] [\fI\,command\/\fR] @@ -9,7 +9,7 @@ bitcoin-util \- manual page for bitcoin-util v29.3.0rc2 .B bitcoin-util [\fI\,options\/\fR] \fI\,grind \/\fR .SH DESCRIPTION -Bitcoin Core bitcoin\-util utility version v29.3.0rc2 +Bitcoin Core bitcoin\-util utility version v29.4.0 .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 diff --git a/doc/man/bitcoin-wallet.1 b/doc/man/bitcoin-wallet.1 index c8737d7989cd..daabe2c3bf53 100644 --- a/doc/man/bitcoin-wallet.1 +++ b/doc/man/bitcoin-wallet.1 @@ -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 v29.3.0rc2" "User Commands" +.TH BITCOIN-WALLET "1" "July 2026" "bitcoin-wallet v29.4.0" "User Commands" .SH NAME -bitcoin-wallet \- manual page for bitcoin-wallet v29.3.0rc2 +bitcoin-wallet \- manual page for bitcoin-wallet v29.4.0 .SH SYNOPSIS .B bitcoin-wallet [\fI\,options\/\fR] \fI\,\/\fR .SH DESCRIPTION -Bitcoin Core bitcoin\-wallet utility version v29.3.0rc2 +Bitcoin Core bitcoin\-wallet utility version v29.4.0 .PP bitcoin\-wallet is an offline tool for creating and interacting with Bitcoin Core wallet files. .PP diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1 index bcf235445212..10b9e6d8377a 100644 --- a/doc/man/bitcoind.1 +++ b/doc/man/bitcoind.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH BITCOIND "1" "January 2026" "bitcoind v29.3.0rc2" "User Commands" +.TH BITCOIND "1" "July 2026" "bitcoind v29.4.0" "User Commands" .SH NAME -bitcoind \- manual page for bitcoind v29.3.0rc2 +bitcoind \- manual page for bitcoind v29.4.0 .SH SYNOPSIS .B bitcoind [\fI\,options\/\fR] .SH DESCRIPTION -Bitcoin Core daemon version v29.3.0rc2 +Bitcoin Core daemon version v29.4.0 .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 diff --git a/doc/release-notes.md b/doc/release-notes.md index 4aebc143d7dc..3ff905db0573 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,6 +1,6 @@ -Bitcoin Core version 29.3rc2 is now available from: +Bitcoin Core version 29.4 is now available from: - + This release includes various bug fixes and performance improvements, as well as updated translations. @@ -37,68 +37,70 @@ unsupported systems. Notable changes =============== -### P2P - -- #33050 net, validation: don't punish peers for consensus-invalid txs -- #33723 chainparams: remove dnsseed.bitcoin.dashjr-list-of-p2p-nodes.us +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 -- #32473 Introduce per-txin sighash midstate cache for legacy/p2sh/segwitv0 scripts -- #33105 validation: detect witness stripping without re-running Script checks +- #35209 validation: correct lifetime of precomputed tx data +- #35465 coins: compact chainstate regularly -### Wallet +### Leveldb -- #33268 wallet: Identify transactions spending 0-value outputs, and add tests for anchor outputs in a wallet -- #34156 wallet: fix unnamed legacy wallet migration failure -- #34226 wallet: test: Relative wallet failed migration cleanup -- #34123 wallet: migration, avoid creating spendable wallet from a watch-only legacy wallet -- #34215 wallettool: fix unnamed createfromdump failure walletsdir deletion -- #34370 wallet: Additional cleanups for migration, and fixes for createfromdump with BDB +- #61(bitcoin-core/leveldb): Disable seek compaction -### Mining +### Net -- #33475 bugfix: miner: fix `addPackageTxs` unsigned integer overflow +- #34093 netif: fix compilation warning in QueryDefaultGatewayImpl() -### Build +### Wallet -- #34227 guix: Fix `osslsigncode` tests +- #35228 wallet: use outpoint when estimating input size -### Documentation +### Build -- #33623 doc: document capnproto and libmultiprocess deps in 29.x +- #34228 depends: Unset SOURCE_DATE_EPOCH in gen_id script +- #34848 cmake: Migrate away from deprecated SQLite3 target ### Test -- #33612 test: change log rate limit version gate +- #34918 fuzz: [refactor] Remove unused g_setup pointers + +### Doc + +- #34510 doc: fix broken bpftrace installation link +- #34561 wallet: rpc: manpage: fix example missing `fee_rate` argument +- #34671 doc: Update Guix install for Debian/Ubuntu +- #35283 doc: mention -DWITH_ZMQ=ON in BSD build guides + +### CI + +- #35202 ci: restore sockets in i686, no IPC job +- #35378 ci: switch runners from cirrus to warpbuild +- #35408 ci: 35378 followups ### Misc -- #32513 ci: remove 3rd party js from windows dll gha job -- #33508 ci: fix buildx gha cache authentication on forks -- #33581 ci: Properly include $FILE_ENV in DEPENDS_HASH -- #34344 ci: update GitHub Actions versions +- #35175 multi_index: fix compilation failure with boost >= 1.91 Credits ======= Thanks to everyone who directly contributed to this release: -- Anthony Towns -- Antoine Poinsot -- Ava Chow -- David Gumberg -- Eugene Siegel +- andrewtoth +- Cory Fields +- Daniel Pfeifer +- darosior - fanquake -- furszy - Hennadii Stepanov -- ismaelsadeeq -- luke-jr -- m3dwards -- Padraic Slattery -- Pieter Wuille -- SatsAndSports -- sedited +- jayvaliya +- junbyjun1238 +- Lőrinc +- MarcoFalke +- SomberNight +- ToRyVand - willcl-ark As well as to everyone that helped with translations on diff --git a/src/common/netif.cpp b/src/common/netif.cpp index 7424f977c7ef..276be8e2f6a3 100644 --- a/src/common/netif.cpp +++ b/src/common/netif.cpp @@ -29,6 +29,8 @@ #include #endif +#include + namespace { // Linux and FreeBSD 14.0+. For FreeBSD 13.2 the code can be compiled but @@ -93,7 +95,9 @@ std::optional QueryDefaultGatewayImpl(sa_family_t family) return std::nullopt; } - for (nlmsghdr* hdr = (nlmsghdr*)response; NLMSG_OK(hdr, recv_result); hdr = NLMSG_NEXT(hdr, recv_result)) { + using recv_result_t = std::conditional_t, int64_t, decltype(NLMSG_HDRLEN)>; + + for (nlmsghdr* hdr = (nlmsghdr*)response; NLMSG_OK(hdr, static_cast(recv_result)); hdr = NLMSG_NEXT(hdr, recv_result)) { rtmsg* r = (rtmsg*)NLMSG_DATA(hdr); int remaining_len = RTM_PAYLOAD(hdr); diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 8fb366515aff..2341545b631d 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -251,7 +251,7 @@ CDBWrapper::CDBWrapper(const DBParams& params) if (params.options.force_compact) { LogPrintf("Starting database compaction of %s\n", fs::PathToString(params.path)); - DBContext().pdb->CompactRange(nullptr, nullptr); + CompactFull(); LogPrintf("Finished database compaction of %s\n", fs::PathToString(params.path)); } @@ -306,11 +306,18 @@ bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) return true; } +std::optional 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 parsed; - if (!DBContext().pdb->GetProperty("leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral(memory))) { + if (auto memory{GetProperty("leveldb.approximate-memory-usage")}; !memory || !(parsed = ToIntegral(*memory))) { LogDebug(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n"); return 0; } diff --git a/src/dbwrapper.h b/src/dbwrapper.h index dd5daa7a1fca..08081c1a0d4c 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -273,6 +273,12 @@ class CDBWrapper 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 GetProperty(const std::string& property) const; + // Get an estimate of LevelDB memory usage (in bytes). size_t DynamicMemoryUsage() const; diff --git a/src/leveldb/db/autocompact_test.cc b/src/leveldb/db/autocompact_test.cc index e6c97a05a6b7..f6e714c65240 100644 --- a/src/leveldb/db/autocompact_test.cc +++ b/src/leveldb/db/autocompact_test.cc @@ -54,8 +54,8 @@ static const int kValueSize = 200 * 1024; static const int kTotalSize = 100 * 1024 * 1024; static const int kCount = kTotalSize / kValueSize; -// Read through the first n keys repeatedly and check that they get -// compacted (verified by checking the size of the key space). +// Read through the first n keys repeatedly and check that reads do NOT +// trigger compaction (seek compaction is disabled in this fork). void AutoCompactTest::DoReads(int n) { std::string value(kValueSize, 'x'); DBImpl* dbi = reinterpret_cast(db_); @@ -76,25 +76,23 @@ void AutoCompactTest::DoReads(int n) { const int64_t initial_size = Size(Key(0), Key(n)); const int64_t initial_other_size = Size(Key(n), Key(kCount)); - // Read until size drops significantly. + // Read repeatedly. The size of the read range must NOT shrink: with + // seek compaction disabled, reads never schedule a compaction. std::string limit_key = Key(n); - for (int read = 0; true; read++) { - ASSERT_LT(read, 100) << "Taking too long to compact"; + for (int read = 0; read < 100; read++) { Iterator* iter = db_->NewIterator(ReadOptions()); for (iter->SeekToFirst(); iter->Valid() && iter->key().ToString() < limit_key; iter->Next()) { // Drop data } delete iter; - // Wait a little bit to allow any triggered compactions to complete. - Env::Default()->SleepForMicroseconds(1000000); uint64_t size = Size(Key(0), Key(n)); fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", read + 1, size / 1048576.0, Size(Key(n), Key(kCount)) / 1048576.0); - if (size <= initial_size / 10) { - break; - } } + // Give any background work a chance to run, even though none should. + Env::Default()->SleepForMicroseconds(1000000); + ASSERT_EQ(Size(Key(0), Key(n)), static_cast(initial_size)); // Verify that the size of the key space not touched by the reads // is pretty much unchanged. diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc index beb1d3bdef61..81fb9e94ebfe 100644 --- a/src/leveldb/db/db_test.cc +++ b/src/leveldb/db/db_test.cc @@ -735,15 +735,14 @@ TEST(DBTest, GetPicksCorrectFile) { } while (ChangeOptions()); } -TEST(DBTest, GetEncountersEmptyLevel) { +TEST(DBTest, GetDoesNotTriggerSeekCompaction) { do { // Arrange for the following to happen: // * sstable A in level 0 // * nothing in level 1 // * sstable B in level 2 - // Then do enough Get() calls to arrange for an automatic compaction - // of sstable A. A bug would cause the compaction to be marked as - // occurring at level 1 (instead of the correct level 0). + // Seek compaction is disabled in this fork, so repeated reads must + // not change the level layout. A manual compaction must still work. // Step 1: First place sstables in levels 0 and 2 int compaction_count = 0; @@ -761,14 +760,17 @@ TEST(DBTest, GetEncountersEmptyLevel) { ASSERT_EQ(NumTableFilesAtLevel(1), 0); ASSERT_EQ(NumTableFilesAtLevel(2), 1); - // Step 3: read a bunch of times + // Step 3: many read misses must not schedule any compaction. for (int i = 0; i < 1000; i++) { ASSERT_EQ("NOT_FOUND", Get("missing")); } - - // Step 4: Wait for compaction to finish DelayMilliseconds(1000); + ASSERT_EQ(NumTableFilesAtLevel(0), 1); + ASSERT_EQ(NumTableFilesAtLevel(1), 0); + ASSERT_EQ(NumTableFilesAtLevel(2), 1); + // Step 4: a manual compaction still moves the L0 file down. + dbfull()->TEST_CompactRange(0, nullptr, nullptr); ASSERT_EQ(NumTableFilesAtLevel(0), 0); } while (ChangeOptions()); } diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc index cd07346ea8a0..8dc73295b84c 100644 --- a/src/leveldb/db/version_set.cc +++ b/src/leveldb/db/version_set.cc @@ -400,16 +400,11 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, return state.found ? state.s : Status::NotFound(Slice()); } -bool Version::UpdateStats(const GetStats& stats) { - FileMetaData* f = stats.seek_file; - if (f != nullptr) { - f->allowed_seeks--; - if (f->allowed_seeks <= 0 && file_to_compact_ == nullptr) { - file_to_compact_ = f; - file_to_compact_level_ = stats.seek_file_level; - return true; - } - } +bool Version::UpdateStats(const GetStats& /*stats*/) { + // Disable automatic compactions triggered by read seek counters. + // The heuristic was tuned for expensive random seeks and can create + // severe write amplification on large random-key databases. + // Size and manual compactions still run. return false; } @@ -661,6 +656,8 @@ class VersionSet::Builder { // same as the compaction of 40KB of data. We are a little // conservative and allow approximately one seek for every 16KB // of data before triggering a compaction. + // + // Note: seek compactions are disabled. See Version::UpdateStats. f->allowed_seeks = static_cast((f->file_size / 16384U)); if (f->allowed_seeks < 100) f->allowed_seeks = 100; diff --git a/src/node/miner.h b/src/node/miner.h index 56101561b110..c45c97100d87 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -102,7 +102,9 @@ struct CompareTxIterByAncestorCount { }; -struct CTxMemPoolModifiedEntry_Indices final : boost::multi_index::indexed_by< +using indexed_modified_transaction_set = boost::multi_index_container< + CTxMemPoolModifiedEntry, + boost::multi_index::indexed_by< boost::multi_index::ordered_unique< modifiedentry_iter, CompareCTxMemPoolIter @@ -115,12 +117,7 @@ struct CTxMemPoolModifiedEntry_Indices final : boost::multi_index::indexed_by< CompareTxMemPoolEntryByAncestorFee > > -{}; - -typedef boost::multi_index_container< - CTxMemPoolModifiedEntry, - CTxMemPoolModifiedEntry_Indices -> indexed_modified_transaction_set; +>; typedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter; typedef indexed_modified_transaction_set::index::type::iterator modtxscoreiter; diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index c46144b34b4a..1780e97e6573 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -1049,6 +1050,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(*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; diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index 270d546c3940..e34690ea6e05 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -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 \ diff --git a/src/txdb.cpp b/src/txdb.cpp index 1622039d63b5..11b0724a9afc 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -12,10 +12,14 @@ #include #include #include +#include #include #include +#include #include +#include +#include #include #include @@ -51,11 +55,22 @@ CCoinsViewDB::CCoinsViewDB(DBParams db_params, CoinsViewOptions options) : m_options{std::move(options)}, m_db{std::make_unique(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(); @@ -156,6 +171,30 @@ size_t CCoinsViewDB::EstimateSize() const return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1)); } +std::optional CCoinsViewDB::GetDBProperty(const std::string& property) +{ + return m_db->GetProperty(property); +} + +std::shared_future 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 { diff --git a/src/txdb.h b/src/txdb.h index 968b7c278102..8944fbc1accd 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -14,8 +14,10 @@ #include #include +#include #include #include +#include #include 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 m_db; + std::shared_future m_compaction; public: explicit CCoinsViewDB(DBParams db_params, CoinsViewOptions options); + ~CCoinsViewDB() override; std::optional GetCoin(const COutPoint& outpoint) const override; bool HaveCoin(const COutPoint &outpoint) const override; @@ -55,10 +61,16 @@ class CCoinsViewDB final : public CCoinsView 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 StoragePath() { return m_db->StoragePath(); } + + //! Perform a full compaction of the underlying LevelDB on a one-shot background thread. + std::shared_future CompactFull() EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_db_mutex); + + //! Return an underlying LevelDB property value, if available. + std::optional GetDBProperty(const std::string& property); }; #endif // BITCOIN_TXDB_H diff --git a/src/txmempool.h b/src/txmempool.h index 10acb2aa22f4..acc52aef1d95 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -329,7 +329,9 @@ class CTxMemPool static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; // public only for testing - struct CTxMemPoolEntry_Indices final : boost::multi_index::indexed_by< + using indexed_transaction_set = boost::multi_index_container< + CTxMemPoolEntry, + boost::multi_index::indexed_by< // sorted by txid boost::multi_index::hashed_unique, // sorted by wtxid @@ -357,11 +359,7 @@ class CTxMemPool CompareTxMemPoolEntryByAncestorFee > > - {}; - typedef boost::multi_index_container< - CTxMemPoolEntry, - CTxMemPoolEntry_Indices - > indexed_transaction_set; + >; /** * This mutex needs to be locked when accessing `mapTx` or other members diff --git a/src/txrequest.cpp b/src/txrequest.cpp index 5909146427b7..521ddec901d5 100644 --- a/src/txrequest.cpp +++ b/src/txrequest.cpp @@ -212,17 +212,15 @@ struct ByTimeViewExtractor } }; -struct Announcement_Indices final : boost::multi_index::indexed_by< - boost::multi_index::ordered_unique, ByPeerViewExtractor>, - boost::multi_index::ordered_non_unique, ByTxHashViewExtractor>, - boost::multi_index::ordered_non_unique, ByTimeViewExtractor> -> -{}; /** Data type for the main data structure (Announcement objects with ByPeer/ByTxHash/ByTime indexes). */ using Index = boost::multi_index_container< Announcement, - Announcement_Indices + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique, ByPeerViewExtractor>, + boost::multi_index::ordered_non_unique, ByTxHashViewExtractor>, + boost::multi_index::ordered_non_unique, ByTimeViewExtractor> + > >; /** Helper type to simplify syntax of iterator types. */ diff --git a/src/validation.cpp b/src/validation.cpp index 3d6ebd30e5b1..ff281bc1a6f8 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -111,6 +111,13 @@ const std::vector 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); @@ -2615,8 +2622,8 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, // in multiple threads). Preallocate the vector size so a new allocation // doesn't invalidate pointers into the vector, and keep txsdata in scope // for as long as `control`. - CCheckQueueControl control(fScriptChecks && parallel_script_checks ? &m_chainman.GetCheckQueue() : nullptr); std::vector txsdata(block.vtx.size()); + CCheckQueueControl control(fScriptChecks && parallel_script_checks ? &m_chainman.GetCheckQueue() : nullptr); std::vector prevheights; CAmount nFees = 0; @@ -2938,9 +2945,20 @@ bool Chainstate::FlushStateToDisk( (bool)fFlushForPrune); } } - 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(), m_chain.GetLocator()); + + 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(), m_chain.GetLocator()); + } + + 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())); diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 121e6e3c8373..ee81c6b17a24 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -49,8 +49,7 @@ if(USE_SQLITE) target_sources(bitcoin_wallet PRIVATE sqlite.cpp) target_link_libraries(bitcoin_wallet PRIVATE - $ - $ + SQLite3::SQLite3 ) endif() if(USE_BDB) diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 5c0b1db23e65..53692f851148 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -1279,7 +1279,7 @@ RPCHelpMan send() "Send 0.3 BTC with a fee rate of 25 " + CURRENCY_ATOM + "/vB using named arguments\n" + HelpExampleCli("-named send", "outputs='{\"" + EXAMPLE_ADDRESS[0] + "\": 0.3}' fee_rate=25\n") + "Create a transaction that should confirm the next block, with a specific input, and return result without adding to wallet or broadcasting to the network\n" - + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 economical '{\"add_to_wallet\": false, \"inputs\": [{\"txid\":\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\", \"vout\":1}]}'") + + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 economical null '{\"add_to_wallet\": false, \"inputs\": [{\"txid\":\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\", \"vout\":1}]}'") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index f45db1c16f30..26924d635265 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -92,7 +92,7 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoin if (!provider) return -1; if (const auto desc = InferDescriptor(txout.scriptPubKey, *provider)) { - if (const auto weight = MaxInputWeight(*desc, {}, coin_control, true, can_grind_r)) { + if (const auto weight = MaxInputWeight(*desc, CTxIn{outpoint}, coin_control, true, can_grind_r)) { return static_cast(GetVirtualTransactionSize(*weight, 0, 0)); } } diff --git a/src/wallet/test/fuzz/crypter.cpp b/src/wallet/test/fuzz/crypter.cpp index 7869f5f39c8c..733a5cd32f0d 100644 --- a/src/wallet/test/fuzz/crypter.cpp +++ b/src/wallet/test/fuzz/crypter.cpp @@ -11,11 +11,9 @@ namespace wallet { namespace { -const TestingSetup* g_setup; void initialize_crypter() { static const auto testing_setup = MakeNoLogFileContext(); - g_setup = testing_setup.get(); } FUZZ_TARGET(crypter, .init = initialize_crypter) diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp index 963c0f838b1e..ac76fe4dda00 100644 --- a/src/wallet/test/spend_tests.cpp +++ b/src/wallet/test/spend_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include