aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorglozow <gloriajzhao@gmail.com>2024-01-09 14:34:38 +0000
committerglozow <gloriajzhao@gmail.com>2024-01-09 15:39:19 +0000
commit04edf9f5862c3ca2d1aed6b7a0f24b8d2914f96c (patch)
tree79e01917350b320055904918a33f09d41198044f
parent44d8b13c81e5276eb610c99f227a4d090cc532f6 (diff)
parent7b79e54474b86864c81148c74824bfe4b732412d (diff)
Merge bitcoin/bitcoin#29011: [26.x] Backports
7b79e54474b86864c81148c74824bfe4b732412d doc: update release notes for 26.x (fanquake) ccf00b1e6eb811a3af2c22518a832dd9a51f8aa4 wallet: Fix use-after-free in WalletBatch::EraseRecords (MarcoFalke) 40252e184eb188c4af767adb4918f729015910e8 ci: Set `HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK` to avoid failures (Hennadii Stepanov) b06b14e68d81f8be091d32db162c8d85b9d29e4c rpc: getwalletinfo, return wallet 'birthtime' (furszy) 12834012c2a31f7c33e3410d67edba1eaec53ae9 test: coverage for wallet birth time interaction with -reindex (furszy) 0fa47e2569a40e74db701f16421b8638a486ebd3 wallet: fix legacy spkm default birth time (furszy) 84f4a6c14587344652ef34dbf944364580417a87 wallet: birth time update during tx scanning (furszy) 074296dd60ef49bf6b28b191472f45ea4f995b4b refactor: rename FirstKeyTimeChanged to MaybeUpdateBirthTime (furszy) 35039ac3cc1c2318762907961aee412a7239ce9b fuzz: disable BnB when SFFO is enabled (furszy) 903b4623d369d86925093fdce08d18019e5266e1 test: add coverage for BnB-SFFO restriction (furszy) 05d0576d3c03ae3797c91ac51bff4e2a18d6a993 wallet: create tx, log resulting coin selection info (furszy) 5493ebbe7428f95e41d5c7a64aea9e7f33190579 wallet: skip BnB when SFFO is active (Murch) b15e2e2cec596662275e790449fd250b6be75076 test: add regression test for the getrawtransaction segfault (Martin Zumsande) 5097bb3389fe3add504851302918692b3f05db70 rpc: fix getrawtransaction segfault (Martin Zumsande) 81e744a9a6a55cb5c2b88cd6eeb9dd6523f3a438 ci: Use Ubuntu 24.04 Noble for asan (MarcoFalke) 69e53d1e47613efb831d01e446b790d21c35ba4b ci: Use Ubuntu 24.04 Noble for tsan,tidy,fuzz (MarcoFalke) d2c80b6f52f255c8d9237177bf0bd1b160409b81 doc: Missing additions to 26.0 release notes (fanquake) 8dc2c753ff3b89c3afefdc791fff38ac590488da doc: add historical release notes for 26.0 (fanquake) Pull request description: Backports for `26.x`. Currently: * https://github.com/bitcoin/bitcoin/pull/28920 * https://github.com/bitcoin/bitcoin/pull/28992 * https://github.com/bitcoin/bitcoin/pull/28994 * https://github.com/bitcoin/bitcoin/pull/29003 * https://github.com/bitcoin/bitcoin/pull/29023 * https://github.com/bitcoin/bitcoin/pull/29080 * https://github.com/bitcoin/bitcoin/pull/29176 ACKs for top commit: TheCharlatan: ACK 7b79e54474b86864c81148c74824bfe4b732412d glozow: ACK 7b79e54474b86864c81148c74824bfe4b732412d, matches mine Tree-SHA512: 898aec76ed3ad35e0edd0980af5bcc21bd60003bbf69e0b4f473ed2aa38c4e3b360b930bc3747cf798195906a8f9fe66417524f5e5ef40fa68f1c1aaceebdeb0
-rw-r--r--.cirrus.yml4
-rw-r--r--.github/workflows/ci.yml2
-rwxr-xr-xci/test/00_setup_env_native_asan.sh2
-rwxr-xr-xci/test/00_setup_env_native_fuzz.sh2
-rwxr-xr-xci/test/00_setup_env_native_tidy.sh2
-rwxr-xr-xci/test/00_setup_env_native_tsan.sh2
-rw-r--r--doc/release-notes.md288
-rw-r--r--doc/release-notes/release-notes-26.0.md357
-rw-r--r--src/rpc/rawtransaction.cpp5
-rw-r--r--src/wallet/rpc/wallet.cpp4
-rw-r--r--src/wallet/scriptpubkeyman.cpp2
-rw-r--r--src/wallet/scriptpubkeyman.h6
-rw-r--r--src/wallet/spend.cpp10
-rw-r--r--src/wallet/test/coinselector_tests.cpp76
-rw-r--r--src/wallet/test/fuzz/coinselection.cpp3
-rw-r--r--src/wallet/wallet.cpp21
-rw-r--r--src/wallet/wallet.h7
-rw-r--r--src/wallet/walletdb.cpp4
-rwxr-xr-xtest/functional/rpc_rawtransaction.py13
-rwxr-xr-xtest/functional/test_runner.py2
-rwxr-xr-xtest/functional/wallet_reindex.py108
21 files changed, 601 insertions, 319 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 3f52adde8a..3669d168c1 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -43,7 +43,7 @@ env: # Global defaults
# The following specific types should exist, with the following requirements:
# - small: For an x86_64 machine, recommended to have 2 CPUs and 8 GB of memory.
# - medium: For an x86_64 machine, recommended to have 4 CPUs and 16 GB of memory.
-# - mantic: For a machine running the Linux kernel shipped with exaclty Ubuntu Mantic 23.10. The machine is recommended to have 4 CPUs and 16 GB of memory.
+# - noble: For a machine running the Linux kernel shipped with exaclty Ubuntu Noble 24.04. The machine is recommended to have 4 CPUs and 16 GB of memory.
# - arm64: For an aarch64 machine, recommended to have 2 CPUs and 8 GB of memory.
# https://cirrus-ci.org/guide/tips-and-tricks/#sharing-configuration-between-tasks
@@ -165,7 +165,7 @@ task:
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
- type: mantic # Must use this specific worker (needed for USDT functional tests)
+ type: noble # Must use this specific worker (needed for USDT functional tests)
env:
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e8564c3a28..07a88b2969 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -92,6 +92,8 @@ jobs:
run: clang --version
- name: Install Homebrew packages
+ env:
+ HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
run: brew install automake libtool pkg-config gnu-getopt ccache boost libevent miniupnpc libnatpmp zeromq qt@5 qrencode
- name: Set Ccache directory
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index 93d84bf17e..60486f8f61 100755
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -6,6 +6,7 @@
export LC_ALL=C.UTF-8
+export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04"
# Only install BCC tracing packages in Cirrus CI.
if [[ "${CIRRUS_CI}" == "true" ]]; then
BPFCC_PACKAGE="bpfcc-tools linux-headers-$(uname --kernel-release)"
@@ -17,7 +18,6 @@ fi
export CONTAINER_NAME=ci_native_asan
export PACKAGES="systemtap-sdt-dev clang-17 llvm-17 libclang-rt-17-dev python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}"
-export CI_IMAGE_NAME_TAG="docker.io/ubuntu:23.10" # This version will reach EOL in Jul 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version).
export NO_DEPENDS=1
export GOAL="install"
export BITCOIN_CONFIG="--enable-c++20 --enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 \
diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh
index 122f044b58..c13ee0cbe9 100755
--- a/ci/test/00_setup_env_native_fuzz.sh
+++ b/ci/test/00_setup_env_native_fuzz.sh
@@ -6,7 +6,7 @@
export LC_ALL=C.UTF-8
-export CI_IMAGE_NAME_TAG="docker.io/ubuntu:23.10" # This version will reach EOL in Jul 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version).
+export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04"
export CONTAINER_NAME=ci_native_fuzz
export PACKAGES="clang-17 llvm-17 libclang-rt-17-dev libevent-dev libboost-dev libsqlite3-dev"
export NO_DEPENDS=1
diff --git a/ci/test/00_setup_env_native_tidy.sh b/ci/test/00_setup_env_native_tidy.sh
index 6b0c708f19..c03392af06 100755
--- a/ci/test/00_setup_env_native_tidy.sh
+++ b/ci/test/00_setup_env_native_tidy.sh
@@ -6,7 +6,7 @@
export LC_ALL=C.UTF-8
-export CI_IMAGE_NAME_TAG="docker.io/ubuntu:23.10" # This version will reach EOL in Jul 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version).
+export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04"
export CONTAINER_NAME=ci_native_tidy
export TIDY_LLVM_V="17"
export PACKAGES="clang-${TIDY_LLVM_V} libclang-${TIDY_LLVM_V}-dev llvm-${TIDY_LLVM_V}-dev libomp-${TIDY_LLVM_V}-dev clang-tidy-${TIDY_LLVM_V} jq bear cmake libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev"
diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh
index 67c29d4bc8..aa23bad809 100755
--- a/ci/test/00_setup_env_native_tsan.sh
+++ b/ci/test/00_setup_env_native_tsan.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_tsan
-export CI_IMAGE_NAME_TAG="docker.io/ubuntu:23.10" # This version will reach EOL in Jul 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version).
+export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04"
export PACKAGES="clang-17 llvm-17 libclang-rt-17-dev libc++abi-17-dev libc++-17-dev python3-zmq"
export DEP_OPTS="CC=clang-17 CXX='clang++-17 -stdlib=libc++'"
export GOAL="install"
diff --git a/doc/release-notes.md b/doc/release-notes.md
index b30dadf62b..f55c72ab9a 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,9 +1,9 @@
-26.0 Release Notes
+26.x Release Notes
==================
-Bitcoin Core version 26.0 is now available from:
+Bitcoin Core version 26.x is now available from:
- <https://bitcoincore.org/bin/bitcoin-core-26.0/>
+ <https://bitcoincore.org/bin/bitcoin-core-26.x/>
This release includes new features, various bug fixes and performance
improvements, as well as updated translations.
@@ -40,296 +40,32 @@ unsupported systems.
Notable changes
===============
-P2P and network changes
------------------------
+### Wallet
-- Experimental support for the v2 transport protocol defined in
- [BIP324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki) was added.
- It is off by default, but when enabled using `-v2transport` it will be negotiated
- on a per-connection basis with other peers that support it too. The existing
- v1 transport protocol remains fully supported.
+- #28994 wallet: skip BnB when SFFO is enabled
+- #28920 wallet: birth time update during tx scanning
+- #29176 wallet: Fix use-after-free in WalletBatch::EraseRecords
-- Nodes with multiple reachable networks will actively try to have at least one
- outbound connection to each network. This improves individual resistance to
- eclipse attacks and network level resistance to partition attacks. Users no
- longer need to perform active measures to ensure being connected to multiple
- enabled networks. (#27213)
+### RPC
-Pruning
--------
+- #29003 rpc: fix getrawtransaction segfault
-- When using assumeutxo with `-prune`, the prune budget may be exceeded if it is set
- lower than 1100MB (i.e. `MIN_DISK_SPACE_FOR_BLOCK_FILES * 2`). Prune budget is normally
- split evenly across each chainstate, unless the resulting prune budget per chainstate
- is beneath `MIN_DISK_SPACE_FOR_BLOCK_FILES` in which case that value will be used. (#27596)
+### CI
-Updated RPCs
-------------
-
-- Setting `-rpcserialversion=0` is deprecated and will be removed in
- a future release. It can currently still be used by also adding
- the `-deprecatedrpc=serialversion` option. (#28448)
-
-- The `hash_serialized_2` value has been removed from `gettxoutsetinfo` since the value it
- calculated contained a bug and did not take all data into account. It is superseded by
- `hash_serialized_3` which provides the same functionality but serves the correctly calculated hash. (#28685)
-
-- New fields `transport_protocol_type` and `session_id` were added to the `getpeerinfo` RPC to indicate
- whether the v2 transport protocol is in use, and if so, what the session id is.
-
-- A new argument `v2transport` was added to the `addnode` RPC to indicate whether a v2 transaction connection
- is to be attempted with the peer.
-
-- [Miniscript](https://bitcoin.sipa.be/miniscript/) expressions can now be used in Taproot descriptors for all RPCs working with descriptors. (#27255)
-
-- `finalizepsbt` is now able to finalize a PSBT with inputs spending [Miniscript](https://bitcoin.sipa.be/miniscript/)-compatible Taproot leaves. (#27255)
-
-Changes to wallet related RPCs can be found in the Wallet section below.
-
-New RPCs
---------
-
-- `loadtxoutset` has been added, which allows loading a UTXO snapshot of the format
- generated by `dumptxoutset`. Once this snapshot is loaded, its contents will be
- deserialized into a second chainstate data structure, which is then used to sync to
- the network's tip.
-
- Meanwhile, the original chainstate will complete the initial block download process in
- the background, eventually validating up to the block that the snapshot is based upon.
-
- The result is a usable bitcoind instance that is current with the network tip in a
- matter of minutes rather than hours. UTXO snapshot are typically obtained via
- third-party sources (HTTP, torrent, etc.) which is reasonable since their contents
- are always checked by hash.
-
- You can find more information on this process in the `assumeutxo` design
- document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).
-
- `getchainstates` has been added to aid in monitoring the assumeutxo sync process.
-
-- A new `getprioritisedtransactions` RPC has been added. It returns a map of all fee deltas created by the
- user with prioritisetransaction, indexed by txid. The map also indicates whether each transaction is
- present in the mempool. (#27501)
-
-- A new RPC, `submitpackage`, has been added. It can be used to submit a list of raw hex
-transactions to the mempool to be evaluated as a package using consensus and mempool policy rules.
-These policies include package CPFP, allowing a child with high fees to bump a parent below the
-mempool minimum feerate (but not minimum relay feerate). (#27609)
-
- - Warning: successful submission does not mean the transactions will propagate throughout the
- network, as package relay is not supported.
-
- - Not all features are available. The package is limited to a child with all of its
- unconfirmed parents, and no parent may spend the output of another parent. Also, package
- RBF is not supported. Refer to doc/policy/packages.md for more details on package policies
- and limitations.
-
- - This RPC is experimental. Its interface may change.
-
-- A new RPC `getaddrmaninfo` has been added to view the distribution of addresses in the new and tried table of the
- node's address manager across different networks(ipv4, ipv6, onion, i2p, cjdns). The RPC returns count of addresses
- in new and tried table as well as their sum for all networks. (#27511)
-
-- A new `importmempool` RPC has been added. It loads a valid `mempool.dat` file and attempts to
- add its contents to the mempool. This can be useful to import mempool data from another node
- without having to modify the datadir contents and without having to restart the node. (#27460)
- - Warning: Importing untrusted files is dangerous, especially if metadata from the file is taken over.
- - If you want to apply fee deltas, it is recommended to use the `getprioritisedtransactions` and
- `prioritisetransaction` RPCs instead of the `apply_fee_delta_priority` option to avoid
- double-prioritising any already-prioritised transactions in the mempool.
-
-Updated settings
-----------------
-
-- `bitcoind` and `bitcoin-qt` will now raise an error on startup
- if a datadir that is being used contains a bitcoin.conf file that
- will be ignored, which can happen when a datadir= line is used in
- a bitcoin.conf file. The error message is just a diagnostic intended
- to prevent accidental misconfiguration, and it can be disabled to
- restore the previous behavior of using the datadir while ignoring
- the bitcoin.conf contained in it. (#27302)
-
-- Passing an invalid `-debug`, `-debugexclude`, or `-loglevel` logging configuration
- option now raises an error, rather than logging an easily missed warning. (#27632)
-
-Changes to GUI or wallet related settings can be found in the GUI or Wallet section below.
-
-New settings
-------------
-
-Tools and Utilities
--------------------
-
-- A new `bitcoinconsensus_verify_script_with_spent_outputs` function is available in libconsensus which optionally accepts the spent outputs of the transaction being verified.
-- A new `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT` flag is available in libconsensus that will verify scripts with the Taproot spending rules.
-
-Wallet
-------
-
-- Wallet loading has changed in this release. Wallets with some corrupted records that could be
- previously loaded (with warnings) may no longer load. For example, wallets with corrupted
- address book entries may no longer load. If this happens, it is recommended
- load the wallet in a previous version of Bitcoin Core and import the data into a new wallet.
- Please also report an issue to help improve the software and make wallet loading more robust
- in these cases. (#24914)
-
-- The `gettransaction`, `listtransactions`, `listsinceblock` RPCs now return
- the `abandoned` field for all transactions. Previously, the "abandoned" field
- was only returned for sent transactions. (#25158)
-
-- The `listdescriptors`, `decodepsbt` and similar RPC methods now show `h` rather than apostrophe (`'`) to indicate
- hardened derivation. This does not apply when using the `private` parameter, which
- matches the marker used when descriptor was generated or imported. Newly created
- wallets use `h`. This change makes it easier to handle descriptor strings manually.
- E.g. the `importdescriptors` RPC call is easiest to use `h` as the marker: `'["desc": ".../0h/..."]'`.
- With this change `listdescriptors` will use `h`, so you can copy-paste the result,
- without having to add escape characters or switch `'` to 'h' manually.
- Note that this changes the descriptor checksum.
- For legacy wallets the `hdkeypath` field in `getaddressinfo` is unchanged,
- nor is the serialization format of wallet dumps. (#26076)
-
-- The `getbalances` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
- hash and height at the time the balances were calculated. This result shouldn't be cached because importing new keys could invalidate it. (#26094)
-
-- The `gettransaction` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
- hash and height at the time the transaction information was generated. (#26094)
-
-- The `getwalletinfo` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
- hash and height at the time the wallet information was generated. (#26094)
-
-- Coin selection and transaction building now accounts for unconfirmed low-feerate ancestor transactions. When it is necessary to spend unconfirmed outputs, the wallet will add fees to ensure that the new transaction with its ancestors will achieve a mining score equal to the feerate requested by the user. (#26152)
-
-- For RPC methods which accept `options` parameters ((`importmulti`, `listunspent`,
- `fundrawtransaction`, `bumpfee`, `send`, `sendall`, `walletcreatefundedpsbt`,
- `simulaterawtransaction`), it is now possible to pass the options as named
- parameters without the need for a nested object. (#26485)
-
-This means it is possible make calls like:
-
-```sh
-src/bitcoin-cli -named bumpfee txid fee_rate=100
-```
-
-instead of
-
-```sh
-src/bitcoin-cli -named bumpfee txid options='{"fee_rate": 100}'
-```
-
-- The `deprecatedrpc=walletwarningfield` configuration option has been removed.
- The `createwallet`, `loadwallet`, `restorewallet` and `unloadwallet` RPCs no
- longer return the "warning" string field. The same information is provided
- through the "warnings" field added in v25.0, which returns a JSON array of
- strings. The "warning" string field was deprecated also in v25.0. (#27757)
-
-- The `signrawtransactionwithkey`, `signrawtransactionwithwallet`,
- `walletprocesspsbt` and `descriptorprocesspsbt` calls now return the more
- specific RPC_INVALID_PARAMETER error instead of RPC_MISC_ERROR if their
- sighashtype argument is malformed. (#28113)
-
-- RPC `walletprocesspsbt`, and `descriptorprocesspsbt` return
- object now includes field `hex` (if the transaction
- is complete) containing the serialized transaction
- suitable for RPC `sendrawtransaction`. (#28414)
-
-- It's now possible to use [Miniscript](https://bitcoin.sipa.be/miniscript/) inside Taproot leaves for descriptor wallets. (#27255)
-
-GUI changes
------------
-
-- The transaction list in the GUI no longer provides a special category for "payment to yourself". Now transactions that have both inputs and outputs that affect the wallet are displayed on separate lines for spending and receiving. (gui#119)
-
-- A new menu option allows migrating a legacy wallet based on keys and implied output script types stored in BerkeleyDB (BDB) to a modern wallet that uses descriptors stored in SQLite. (gui#738)
-
-- The PSBT operations dialog marks outputs paying your own wallet with "own address". (gui#740)
-
-- The ability to create legacy wallets is being removed. (gui#764)
-
-Low-level changes
-=================
-
-Tests
------
-
-- Non-standard transactions are now disabled by default on testnet
- for relay and mempool acceptance. The previous behaviour can be
- re-enabled by setting `-acceptnonstdtxn=1`. (#28354)
+- #28992 ci: Use Ubuntu 24.04 Noble for asan,tsan,tidy,fuzz
+- #29080 ci: Set HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK to avoid unrelated failures
Credits
=======
Thanks to everyone who directly contributed to this release:
-- 0xb10c
-- Amiti Uttarwar
- Andrew Chow
-- Andrew Toth
-- Anthony Towns
-- Antoine Poinsot
-- Antoine Riard
-- Ari
-- Aurèle Oulès
-- Ayush Singh
-- Ben Woosley
-- Brandon Odiwuor
-- Brotcrunsher
-- brunoerg
-- Bufo
-- Carl Dong
-- Casey Carter
-- Cory Fields
-- David Álvarez Rosa
-- dergoegge
-- dhruv
-- dimitaracev
-- Erik Arvstedt
-- Erik McKelvey
-- Fabian Jahr
- furszy
-- glozow
-- Greg Sanders
-- Harris
- Hennadii Stepanov
-- Hernan Marino
-- ishaanam
-- ismaelsadeeq
-- Jake Rawsthorne
-- James O'Beirne
-- John Moffett
-- Jon Atack
-- josibake
-- kevkevin
-- Kiminuo
-- Larry Ruane
-- Luke Dashjr
- MarcoFalke
-- Marnix
-- Martin Leitner-Ankerl
- Martin Zumsande
-- Matthew Zipkin
-- Michael Ford
-- Michael Tidwell
-- mruddy
- Murch
-- ns-xvrn
-- pablomartin4btc
-- Pieter Wuille
-- Reese Russell
-- Rhythm Garg
-- Ryan Ofsky
-- Sebastian Falbesoner
-- Sjors Provoost
-- stickies-v
-- stratospher
-- Suhas Daftuar
-- TheCharlatan
-- Tim Neubauer
-- Tim Ruffing
-- Vasil Dimov
-- virtu
-- vuittont60
-- willcl-ark
-- Yusuf Sahin HAMZA
As well as to everyone that helped with translations on
[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-notes/release-notes-26.0.md b/doc/release-notes/release-notes-26.0.md
new file mode 100644
index 0000000000..b7c7c35f65
--- /dev/null
+++ b/doc/release-notes/release-notes-26.0.md
@@ -0,0 +1,357 @@
+26.0 Release Notes
+==================
+
+Bitcoin Core version 26.0 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-26.0/>
+
+This release includes new features, various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 11.0+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+Notable changes
+===============
+
+P2P and network changes
+-----------------------
+
+- Experimental support for the v2 transport protocol defined in
+ [BIP324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki) was added.
+ It is off by default, but when enabled using `-v2transport` it will be negotiated
+ on a per-connection basis with other peers that support it too. The existing
+ v1 transport protocol remains fully supported.
+
+- Nodes with multiple reachable networks will actively try to have at least one
+ outbound connection to each network. This improves individual resistance to
+ eclipse attacks and network level resistance to partition attacks. Users no
+ longer need to perform active measures to ensure being connected to multiple
+ enabled networks. (#27213)
+
+Pruning
+-------
+
+- When using assumeutxo with `-prune`, the prune budget may be exceeded if it is set
+ lower than 1100MB (i.e. `MIN_DISK_SPACE_FOR_BLOCK_FILES * 2`). Prune budget is normally
+ split evenly across each chainstate, unless the resulting prune budget per chainstate
+ is beneath `MIN_DISK_SPACE_FOR_BLOCK_FILES` in which case that value will be used. (#27596)
+
+Updated RPCs
+------------
+
+- Setting `-rpcserialversion=0` is deprecated and will be removed in
+ a future release. It can currently still be used by also adding
+ the `-deprecatedrpc=serialversion` option. (#28448)
+
+- The `hash_serialized_2` value has been removed from `gettxoutsetinfo` since the value it
+ calculated contained a bug and did not take all data into account. It is superseded by
+ `hash_serialized_3` which provides the same functionality but serves the correctly calculated hash. (#28685)
+
+- New fields `transport_protocol_type` and `session_id` were added to the `getpeerinfo` RPC to indicate
+ whether the v2 transport protocol is in use, and if so, what the session id is.
+
+- A new argument `v2transport` was added to the `addnode` RPC to indicate whether a v2 transaction connection
+ is to be attempted with the peer.
+
+- [Miniscript](https://bitcoin.sipa.be/miniscript/) expressions can now be used in Taproot descriptors for all RPCs working with descriptors. (#27255)
+
+- `finalizepsbt` is now able to finalize a PSBT with inputs spending [Miniscript](https://bitcoin.sipa.be/miniscript/)-compatible Taproot leaves. (#27255)
+
+Changes to wallet related RPCs can be found in the Wallet section below.
+
+New RPCs
+--------
+
+- `loadtxoutset` has been added, which allows loading a UTXO snapshot of the format
+ generated by `dumptxoutset`. Once this snapshot is loaded, its contents will be
+ deserialized into a second chainstate data structure, which is then used to sync to
+ the network's tip.
+
+ Meanwhile, the original chainstate will complete the initial block download process in
+ the background, eventually validating up to the block that the snapshot is based upon.
+
+ The result is a usable bitcoind instance that is current with the network tip in a
+ matter of minutes rather than hours. UTXO snapshot are typically obtained via
+ third-party sources (HTTP, torrent, etc.) which is reasonable since their contents
+ are always checked by hash.
+
+ You can find more information on this process in the `assumeutxo` design
+ document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).
+
+ `getchainstates` has been added to aid in monitoring the assumeutxo sync process.
+
+- A new `getprioritisedtransactions` RPC has been added. It returns a map of all fee deltas created by the
+ user with prioritisetransaction, indexed by txid. The map also indicates whether each transaction is
+ present in the mempool. (#27501)
+
+- A new RPC, `submitpackage`, has been added. It can be used to submit a list of raw hex
+transactions to the mempool to be evaluated as a package using consensus and mempool policy rules.
+These policies include package CPFP, allowing a child with high fees to bump a parent below the
+mempool minimum feerate (but not minimum relay feerate). (#27609)
+
+ - Warning: successful submission does not mean the transactions will propagate throughout the
+ network, as package relay is not supported.
+
+ - Not all features are available. The package is limited to a child with all of its
+ unconfirmed parents, and no parent may spend the output of another parent. Also, package
+ RBF is not supported. Refer to doc/policy/packages.md for more details on package policies
+ and limitations.
+
+ - This RPC is experimental. Its interface may change.
+
+- A new RPC `getaddrmaninfo` has been added to view the distribution of addresses in the new and tried table of the
+ node's address manager across different networks(ipv4, ipv6, onion, i2p, cjdns). The RPC returns count of addresses
+ in new and tried table as well as their sum for all networks. (#27511)
+
+- A new `importmempool` RPC has been added. It loads a valid `mempool.dat` file and attempts to
+ add its contents to the mempool. This can be useful to import mempool data from another node
+ without having to modify the datadir contents and without having to restart the node. (#27460)
+ - Warning: Importing untrusted files is dangerous, especially if metadata from the file is taken over.
+ - If you want to apply fee deltas, it is recommended to use the `getprioritisedtransactions` and
+ `prioritisetransaction` RPCs instead of the `apply_fee_delta_priority` option to avoid
+ double-prioritising any already-prioritised transactions in the mempool.
+
+Updated settings
+----------------
+
+- `bitcoind` and `bitcoin-qt` will now raise an error on startup
+ if a datadir that is being used contains a bitcoin.conf file that
+ will be ignored, which can happen when a datadir= line is used in
+ a bitcoin.conf file. The error message is just a diagnostic intended
+ to prevent accidental misconfiguration, and it can be disabled to
+ restore the previous behavior of using the datadir while ignoring
+ the bitcoin.conf contained in it. (#27302)
+
+- Passing an invalid `-debug`, `-debugexclude`, or `-loglevel` logging configuration
+ option now raises an error, rather than logging an easily missed warning. (#27632)
+
+Changes to GUI or wallet related settings can be found in the GUI or Wallet section below.
+
+New settings
+------------
+
+Tools and Utilities
+-------------------
+
+- A new `bitcoinconsensus_verify_script_with_spent_outputs` function is available in libconsensus which optionally accepts the spent outputs of the transaction being verified.
+- A new `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT` flag is available in libconsensus that will verify scripts with the Taproot spending rules.
+
+Wallet
+------
+
+- Wallet loading has changed in this release. Wallets with some corrupted records that could be
+ previously loaded (with warnings) may no longer load. For example, wallets with corrupted
+ address book entries may no longer load. If this happens, it is recommended
+ load the wallet in a previous version of Bitcoin Core and import the data into a new wallet.
+ Please also report an issue to help improve the software and make wallet loading more robust
+ in these cases. (#24914)
+
+- The `createwallet` RPC will no longer create legacy (BDB) wallets when
+ setting `descriptors=false` without also providing the
+ `-deprecatedrpc=create_bdb` option. This is because the legacy wallet is
+ being deprecated in a future release. (#28597)
+
+- The `gettransaction`, `listtransactions`, `listsinceblock` RPCs now return
+ the `abandoned` field for all transactions. Previously, the "abandoned" field
+ was only returned for sent transactions. (#25158)
+
+- The `listdescriptors`, `decodepsbt` and similar RPC methods now show `h` rather than apostrophe (`'`) to indicate
+ hardened derivation. This does not apply when using the `private` parameter, which
+ matches the marker used when descriptor was generated or imported. Newly created
+ wallets use `h`. This change makes it easier to handle descriptor strings manually.
+ E.g. the `importdescriptors` RPC call is easiest to use `h` as the marker: `'["desc": ".../0h/..."]'`.
+ With this change `listdescriptors` will use `h`, so you can copy-paste the result,
+ without having to add escape characters or switch `'` to 'h' manually.
+ Note that this changes the descriptor checksum.
+ For legacy wallets the `hdkeypath` field in `getaddressinfo` is unchanged,
+ nor is the serialization format of wallet dumps. (#26076)
+
+- The `getbalances` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
+ hash and height at the time the balances were calculated. This result shouldn't be cached because importing new keys could invalidate it. (#26094)
+
+- The `gettransaction` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
+ hash and height at the time the transaction information was generated. (#26094)
+
+- The `getwalletinfo` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
+ hash and height at the time the wallet information was generated. (#26094)
+
+- Coin selection and transaction building now accounts for unconfirmed low-feerate ancestor transactions. When it is necessary to spend unconfirmed outputs, the wallet will add fees to ensure that the new transaction with its ancestors will achieve a mining score equal to the feerate requested by the user. (#26152)
+
+- For RPC methods which accept `options` parameters ((`importmulti`, `listunspent`,
+ `fundrawtransaction`, `bumpfee`, `send`, `sendall`, `walletcreatefundedpsbt`,
+ `simulaterawtransaction`), it is now possible to pass the options as named
+ parameters without the need for a nested object. (#26485)
+
+This means it is possible make calls like:
+
+```sh
+src/bitcoin-cli -named bumpfee txid fee_rate=100
+```
+
+instead of
+
+```sh
+src/bitcoin-cli -named bumpfee txid options='{"fee_rate": 100}'
+```
+
+- The `deprecatedrpc=walletwarningfield` configuration option has been removed.
+ The `createwallet`, `loadwallet`, `restorewallet` and `unloadwallet` RPCs no
+ longer return the "warning" string field. The same information is provided
+ through the "warnings" field added in v25.0, which returns a JSON array of
+ strings. The "warning" string field was deprecated also in v25.0. (#27757)
+
+- The `signrawtransactionwithkey`, `signrawtransactionwithwallet`,
+ `walletprocesspsbt` and `descriptorprocesspsbt` calls now return the more
+ specific RPC_INVALID_PARAMETER error instead of RPC_MISC_ERROR if their
+ sighashtype argument is malformed. (#28113)
+
+- RPC `walletprocesspsbt`, and `descriptorprocesspsbt` return
+ object now includes field `hex` (if the transaction
+ is complete) containing the serialized transaction
+ suitable for RPC `sendrawtransaction`. (#28414)
+
+- It's now possible to use [Miniscript](https://bitcoin.sipa.be/miniscript/) inside Taproot leaves for descriptor wallets. (#27255)
+
+Descriptors
+-----------
+
+- The usage of hybrid public keys in output descriptors has been removed. Hybrid
+ public keys are an exotic public key encoding not supported by output descriptors
+ (as specified in BIP380 and documented in doc/descriptors.md). Bitcoin Core would
+ previously incorrectly accept descriptors containing such hybrid keys. (#28587)
+
+GUI changes
+-----------
+
+- The transaction list in the GUI no longer provides a special category for "payment to yourself". Now transactions that have both inputs and outputs that affect the wallet are displayed on separate lines for spending and receiving. (gui#119)
+
+- A new menu option allows migrating a legacy wallet based on keys and implied output script types stored in BerkeleyDB (BDB) to a modern wallet that uses descriptors stored in SQLite. (gui#738)
+
+- The PSBT operations dialog marks outputs paying your own wallet with "own address". (gui#740)
+
+- The ability to create legacy wallets is being removed. (gui#764)
+
+Contrib
+-------
+
+- Bash completion files have been renamed from `bitcoin*.bash-completion` to
+ `bitcoin*.bash`. This means completions can be automatically loaded on demand
+ based on invoked commands' names when they are put into the completion
+ directory (found with `pkg-config --variable=completionsdir
+ bash-completion`) without requiring renaming. (#28507)
+
+Low-level changes
+=================
+
+Tests
+-----
+
+- Non-standard transactions are now disabled by default on testnet
+ for relay and mempool acceptance. The previous behaviour can be
+ re-enabled by setting `-acceptnonstdtxn=1`. (#28354)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- 0xb10c
+- Amiti Uttarwar
+- Andrew Chow
+- Andrew Toth
+- Anthony Towns
+- Antoine Poinsot
+- Antoine Riard
+- Ari
+- Aurèle Oulès
+- Ayush Singh
+- Ben Woosley
+- Brandon Odiwuor
+- Brotcrunsher
+- brunoerg
+- Bufo
+- Carl Dong
+- Casey Carter
+- Cory Fields
+- David Álvarez Rosa
+- dergoegge
+- dhruv
+- dimitaracev
+- Erik Arvstedt
+- Erik McKelvey
+- Fabian Jahr
+- furszy
+- glozow
+- Greg Sanders
+- Harris
+- Hennadii Stepanov
+- Hernan Marino
+- ishaanam
+- ismaelsadeeq
+- Jake Rawsthorne
+- James O'Beirne
+- John Moffett
+- Jon Atack
+- josibake
+- kevkevin
+- Kiminuo
+- Larry Ruane
+- Luke Dashjr
+- MarcoFalke
+- Marnix
+- Martin Leitner-Ankerl
+- Martin Zumsande
+- Matthew Zipkin
+- Michael Ford
+- Michael Tidwell
+- mruddy
+- Murch
+- ns-xvrn
+- pablomartin4btc
+- Pieter Wuille
+- Reese Russell
+- Rhythm Garg
+- Ryan Ofsky
+- Sebastian Falbesoner
+- Sjors Provoost
+- stickies-v
+- stratospher
+- Suhas Daftuar
+- TheCharlatan
+- Tim Neubauer
+- Tim Ruffing
+- Vasil Dimov
+- virtu
+- vuittont60
+- willcl-ark
+- Yusuf Sahin HAMZA
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 16705b3ce2..b30b0bbfeb 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -396,7 +396,7 @@ static RPCHelpMan getrawtransaction()
LOCK(cs_main);
blockindex = chainman.m_blockman.LookupBlockIndex(hash_block);
}
- if (verbosity == 1) {
+ if (verbosity == 1 || !blockindex) {
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
return result;
}
@@ -405,8 +405,7 @@ static RPCHelpMan getrawtransaction()
CBlock block;
const bool is_block_pruned{WITH_LOCK(cs_main, return chainman.m_blockman.IsBlockPruned(blockindex))};
- if (tx->IsCoinBase() ||
- !blockindex || is_block_pruned ||
+ if (tx->IsCoinBase() || is_block_pruned ||
!(chainman.m_blockman.UndoReadFromDisk(blockUndo, *blockindex) && chainman.m_blockman.ReadBlockFromDisk(block, *blockindex))) {
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
return result;
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 164ce9afed..c635093344 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -69,6 +69,7 @@ static RPCHelpMan getwalletinfo()
{RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
{RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
{RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
+ {RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},
RESULT_LAST_PROCESSED_BLOCK,
}},
},
@@ -132,6 +133,9 @@ static RPCHelpMan getwalletinfo()
obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
+ if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {
+ obj.pushKV("birthtime", birthtime);
+ }
AppendLastProcessedBlock(obj, *pwallet);
return obj;
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index bc3327cdb2..f5f3a17ae7 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -709,7 +709,7 @@ void LegacyScriptPubKeyMan::UpdateTimeFirstKey(int64_t nCreateTime)
// Cannot determine birthday information, so set the wallet birthday to
// the beginning of time.
nTimeFirstKey = 1;
- } else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) {
+ } else if (nTimeFirstKey == UNKNOWN_TIME || nCreateTime < nTimeFirstKey) {
nTimeFirstKey = nCreateTime;
}
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index 7c0eca1475..7231486df0 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -51,6 +51,9 @@ public:
virtual bool IsLocked() const = 0;
};
+//! Constant representing an unknown spkm creation time
+static constexpr int64_t UNKNOWN_TIME = std::numeric_limits<int64_t>::max();
+
//! Default for -keypool
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
@@ -286,7 +289,8 @@ private:
WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
- int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = 0;
+ // By default, do not scan any block until keys/scripts are generated/imported
+ int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = UNKNOWN_TIME;
//! Number of pre-generated keys/scripts (part of the look-ahead process, used to detect payments)
int64_t m_keypool_size GUARDED_BY(cs_KeyStore){DEFAULT_KEYPOOL_SIZE};
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 8314a2ddfa..e473c5a093 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -693,9 +693,12 @@ util::Result<SelectionResult> ChooseSelectionResult(interfaces::Chain& chain, co
// Maximum allowed weight
int max_inputs_weight = MAX_STANDARD_TX_WEIGHT - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR);
- if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change, max_inputs_weight)}) {
- results.push_back(*bnb_result);
- } else append_error(bnb_result);
+ // SFFO frequently causes issues in the context of changeless input sets: skip BnB when SFFO is active
+ if (!coin_selection_params.m_subtract_fee_outputs) {
+ if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change, max_inputs_weight)}) {
+ results.push_back(*bnb_result);
+ } else append_error(bnb_result);
+ }
// As Knapsack and SRD can create change, also deduce change weight.
max_inputs_weight -= (coin_selection_params.change_output_size * WITNESS_SCALE_FACTOR);
@@ -1260,6 +1263,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
// accidental re-use.
reservedest.KeepDestination();
+ wallet.WalletLogPrintf("Coin Selection: Algorithm:%s, Waste Metric Score:%d\n", GetAlgorithmName(result.GetAlgo()), result.GetWaste());
wallet.WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
current_fee, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
feeCalc.est.pass.start, feeCalc.est.pass.end,
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 9569210ba0..2b7ae888d8 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -320,7 +320,6 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_change_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_output_size);
coin_selection_params_bnb.m_cost_of_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size) + coin_selection_params_bnb.m_change_fee;
coin_selection_params_bnb.min_viable_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size);
- coin_selection_params_bnb.m_subtract_fee_outputs = true;
{
std::unique_ptr<CWallet> wallet = NewWallet(m_node);
@@ -345,6 +344,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
CoinsResult available_coins;
+ coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
add_coin(available_coins, *wallet, 5 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
add_coin(available_coins, *wallet, 3 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
add_coin(available_coins, *wallet, 2 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
@@ -355,7 +355,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
PreSelectedInputs selected_input;
selected_input.Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs);
available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint});
- coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
+
LOCK(wallet->cs_wallet);
const auto result10 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(result10);
@@ -370,12 +370,14 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ CAmount input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(10 * CENT, 2, expected_result);
+ add_coin(10 * CENT + input_fee, 2, expected_result);
CCoinControl coin_control;
const auto result11 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result11));
@@ -385,13 +387,15 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(3000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(5000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(9 * CENT, 2, expected_result);
- add_coin(1 * CENT, 2, expected_result);
+ add_coin(9 * CENT + input_fee, 2, expected_result);
+ add_coin(1 * CENT + input_fee, 2, expected_result);
const auto result12 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result12));
available_coins.Clear();
@@ -400,13 +404,15 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(9 * CENT, 2, expected_result);
- add_coin(1 * CENT, 2, expected_result);
+ add_coin(9 * CENT + input_fee, 2, expected_result);
+ add_coin(1 * CENT + input_fee, 2, expected_result);
coin_control.m_allow_other_inputs = true;
COutput select_coin = available_coins.All().at(1); // pre select 9 coin
coin_control.Select(select_coin.outpoint);
@@ -449,6 +455,44 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
}
}
+BOOST_AUTO_TEST_CASE(bnb_sffo_restriction)
+{
+ // Verify the coin selection process does not produce a BnB solution when SFFO is enabled.
+ // This is currently problematic because it could require a change output. And BnB is specialized on changeless solutions.
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
+ WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(300, uint256{})); // set a high block so internal UTXOs are selectable
+
+ FastRandomContext rand{};
+ CoinSelectionParams params{
+ rand,
+ /*change_output_size=*/ 31, // unused value, p2wpkh output size (wallet default change type)
+ /*change_spend_size=*/ 68, // unused value, p2wpkh input size (high-r signature)
+ /*min_change_target=*/ 0, // dummy, set later
+ /*effective_feerate=*/ CFeeRate(3000),
+ /*long_term_feerate=*/ CFeeRate(1000),
+ /*discard_feerate=*/ CFeeRate(1000),
+ /*tx_noinputs_size=*/ 0,
+ /*avoid_partial=*/ false,
+ };
+ params.m_subtract_fee_outputs = true;
+ params.m_change_fee = params.m_effective_feerate.GetFee(params.change_output_size);
+ params.m_cost_of_change = params.m_discard_feerate.GetFee(params.change_spend_size) + params.m_change_fee;
+ params.m_min_change_target = params.m_cost_of_change + 1;
+ // Add spendable coin at the BnB selection upper bound
+ CoinsResult available_coins;
+ add_coin(available_coins, *wallet, COIN + params.m_cost_of_change, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ add_coin(available_coins, *wallet, 0.5 * COIN + params.m_cost_of_change, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ add_coin(available_coins, *wallet, 0.5 * COIN, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ // Knapsack will only find a changeless solution on an exact match to the satoshi, SRD doesn’t look for changeless
+ // If BnB were run, it would produce a single input solution with the best waste score
+ auto result = WITH_LOCK(wallet->cs_wallet, return SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, COIN, /*coin_control=*/{}, params));
+ BOOST_CHECK(result.has_value());
+ BOOST_CHECK_NE(result->GetAlgo(), SelectionAlgorithm::BNB);
+ BOOST_CHECK(result->GetInputSet().size() == 2);
+ // We have only considered BnB, SRD, and Knapsack. Test needs to be reevaluated if new algo is added
+ BOOST_CHECK(result->GetAlgo() == SelectionAlgorithm::SRD || result->GetAlgo() == SelectionAlgorithm::KNAPSACK);
+}
+
BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{
FastRandomContext rand{};
diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp
index 4caf96b18d..ade3ec3f60 100644
--- a/src/wallet/test/fuzz/coinselection.cpp
+++ b/src/wallet/test/fuzz/coinselection.cpp
@@ -116,7 +116,8 @@ FUZZ_TARGET(coinselection)
}
// Run coinselection algorithms
- auto result_bnb = SelectCoinsBnB(group_pos, target, coin_params.m_cost_of_change, MAX_STANDARD_TX_WEIGHT);
+ auto result_bnb = coin_params.m_subtract_fee_outputs ? util::Error{Untranslated("BnB disabled when SFFO is enabled")} :
+ SelectCoinsBnB(group_pos, target, coin_params.m_cost_of_change, MAX_STANDARD_TX_WEIGHT);
if (result_bnb) {
assert(result_bnb->GetChange(coin_params.m_cost_of_change, CAmount{0}) == 0);
assert(result_bnb->GetSelectedValue() >= target);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 162d7f9ec7..78febb8195 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1080,6 +1080,9 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block);
AddToSpends(wtx, &batch);
+
+ // Update birth time when tx time is older than it.
+ MaybeUpdateBirthTime(wtx.GetTxTime());
}
if (!fInsertedNew)
@@ -1215,6 +1218,10 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
}
}
}
+
+ // Update birth time when tx time is older than it.
+ MaybeUpdateBirthTime(wtx.GetTxTime());
+
return true;
}
@@ -1763,11 +1770,11 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri
return true;
}
-void CWallet::FirstKeyTimeChanged(const ScriptPubKeyMan* spkm, int64_t new_birth_time)
+void CWallet::MaybeUpdateBirthTime(int64_t time)
{
int64_t birthtime = m_birth_time.load();
- if (new_birth_time < birthtime) {
- m_birth_time = new_birth_time;
+ if (time < birthtime) {
+ m_birth_time = time;
}
}
@@ -3103,7 +3110,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
int64_t time = spk_man->GetTimeFirstKey();
if (!time_first_key || time < *time_first_key) time_first_key = time;
}
- if (time_first_key) walletInstance->m_birth_time = *time_first_key;
+ if (time_first_key) walletInstance->MaybeUpdateBirthTime(*time_first_key);
if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {
return nullptr;
@@ -3494,10 +3501,12 @@ LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
void CWallet::AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man)
{
+ // Add spkm_man to m_spk_managers before calling any method
+ // that might access it.
const auto& spkm = m_spk_managers[id] = std::move(spkm_man);
// Update birth time if needed
- FirstKeyTimeChanged(spkm.get(), spkm->GetTimeFirstKey());
+ MaybeUpdateBirthTime(spkm->GetTimeFirstKey());
}
void CWallet::SetupLegacyScriptPubKeyMan()
@@ -3530,7 +3539,7 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
for (const auto& spk_man : GetActiveScriptPubKeyMans()) {
spk_man->NotifyWatchonlyChanged.connect(NotifyWatchonlyChanged);
spk_man->NotifyCanGetAddressesChanged.connect(NotifyCanGetAddressesChanged);
- spk_man->NotifyFirstKeyTimeChanged.connect(std::bind(&CWallet::FirstKeyTimeChanged, this, std::placeholders::_1, std::placeholders::_2));
+ spk_man->NotifyFirstKeyTimeChanged.connect(std::bind(&CWallet::MaybeUpdateBirthTime, this, std::placeholders::_2));
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 9333493a6e..c7cd3b3959 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -678,8 +678,8 @@ public:
bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- /** Updates wallet birth time if 'new_birth_time' is below it */
- void FirstKeyTimeChanged(const ScriptPubKeyMan* spkm, int64_t new_birth_time);
+ /** Updates wallet birth time if 'time' is below it */
+ void MaybeUpdateBirthTime(int64_t time);
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
@@ -877,6 +877,9 @@ public:
/* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */
bool CanGetAddresses(bool internal = false) const;
+ /* Returns the time of the first created key or, in case of an import, it could be the time of the first received transaction */
+ int64_t GetBirthTime() const { return m_birth_time; }
+
/**
* Blocks until the wallet state is up-to-date to /at least/ the current
* chain at the time this function is entered
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 92eca46f05..3a40b7a34f 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1401,13 +1401,13 @@ bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
}
// Make a copy of key to avoid data being deleted by the following read of the type
- Span key_data{key};
+ const SerializeData key_data{key.begin(), key.end()};
std::string type;
key >> type;
if (types.count(type) > 0) {
- if (!m_batch->Erase(key_data)) {
+ if (!m_batch->Erase(Span{key_data})) {
cursor.reset(nullptr);
m_batch->TxnAbort();
return false; // erase failed
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 2395935620..c12865b5e3 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -32,6 +32,7 @@ from test_framework.script import (
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ assert_greater_than,
assert_raises_rpc_error,
)
from test_framework.wallet import (
@@ -70,7 +71,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.extra_args = [
["-txindex"],
["-txindex"],
- [],
+ ["-fastprune", "-prune=1"],
]
# whitelist all peers to speed up tx relay / mempool sync
for args in self.extra_args:
@@ -85,7 +86,6 @@ class RawTransactionsTest(BitcoinTestFramework):
self.wallet = MiniWallet(self.nodes[0])
self.getrawtransaction_tests()
- self.getrawtransaction_verbosity_tests()
self.createrawtransaction_tests()
self.sendrawtransaction_tests()
self.sendrawtransaction_testmempoolaccept_tests()
@@ -94,6 +94,8 @@ class RawTransactionsTest(BitcoinTestFramework):
if self.is_specified_wallet_compiled() and not self.options.descriptors:
self.import_deterministic_coinbase_privkeys()
self.raw_multisig_transaction_legacy_tests()
+ self.getrawtransaction_verbosity_tests()
+
def getrawtransaction_tests(self):
tx = self.wallet.send_self_transfer(from_node=self.nodes[0])
@@ -243,6 +245,13 @@ class RawTransactionsTest(BitcoinTestFramework):
coin_base = self.nodes[1].getblock(block1)['tx'][0]
gottx = self.nodes[1].getrawtransaction(txid=coin_base, verbosity=2, blockhash=block1)
assert 'fee' not in gottx
+ # check that verbosity 2 for a mempool tx will fallback to verbosity 1
+ # Do this with a pruned chain, as a regression test for https://github.com/bitcoin/bitcoin/pull/29003
+ self.generate(self.nodes[2], 400)
+ assert_greater_than(self.nodes[2].pruneblockchain(250), 0)
+ mempool_tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid']
+ gottx = self.nodes[2].getrawtransaction(txid=mempool_tx, verbosity=2)
+ assert 'fee' not in gottx
def createrawtransaction_tests(self):
self.log.info("Test createrawtransaction")
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index fbf48a0e4d..148902032f 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -203,6 +203,8 @@ BASE_SCRIPTS = [
'wallet_createwallet.py --descriptors',
'wallet_watchonly.py --legacy-wallet',
'wallet_watchonly.py --usecli --legacy-wallet',
+ 'wallet_reindex.py --legacy-wallet',
+ 'wallet_reindex.py --descriptors',
'wallet_reorgsrestore.py',
'wallet_conflicts.py --legacy-wallet',
'wallet_conflicts.py --descriptors',
diff --git a/test/functional/wallet_reindex.py b/test/functional/wallet_reindex.py
new file mode 100755
index 0000000000..5388de4b71
--- /dev/null
+++ b/test/functional/wallet_reindex.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023-present The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+"""Test wallet-reindex interaction"""
+
+import time
+
+from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+)
+BLOCK_TIME = 60 * 10
+
+class WalletReindexTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def advance_time(self, node, secs):
+ self.node_time += secs
+ node.setmocktime(self.node_time)
+
+ # Verify the wallet updates the birth time accordingly when it detects a transaction
+ # with a time older than the oldest descriptor timestamp.
+ # This could happen when the user blindly imports a descriptor with 'timestamp=now'.
+ def birthtime_test(self, node, miner_wallet):
+ self.log.info("Test birth time update during tx scanning")
+ # Fund address to test
+ wallet_addr = miner_wallet.getnewaddress()
+ tx_id = miner_wallet.sendtoaddress(wallet_addr, 2)
+
+ # Generate 50 blocks, one every 10 min to surpass the 2 hours rescan window the wallet has
+ for _ in range(50):
+ self.generate(node, 1)
+ self.advance_time(node, BLOCK_TIME)
+
+ # Now create a new wallet, and import the descriptor
+ node.createwallet(wallet_name='watch_only', disable_private_keys=True, load_on_startup=True)
+ wallet_watch_only = node.get_wallet_rpc('watch_only')
+ # Blank wallets don't have a birth time
+ assert 'birthtime' not in wallet_watch_only.getwalletinfo()
+
+ # For a descriptors wallet: Import address with timestamp=now.
+ # For legacy wallet: There is no way of importing a script/address with a custom time. The wallet always imports it with birthtime=1.
+ # In both cases, disable rescan to not detect the transaction.
+ wallet_watch_only.importaddress(wallet_addr, rescan=False)
+ assert_equal(len(wallet_watch_only.listtransactions()), 0)
+
+ # Depending on the wallet type, the birth time changes.
+ wallet_birthtime = wallet_watch_only.getwalletinfo()['birthtime']
+ if self.options.descriptors:
+ # As blocks were generated every 10 min, the chain MTP timestamp is node_time - 60 min.
+ assert_equal(self.node_time - BLOCK_TIME * 6, wallet_birthtime)
+ else:
+ # No way of importing scripts/addresses with a custom time on a legacy wallet.
+ # It's always set to the beginning of time.
+ assert_equal(wallet_birthtime, 1)
+
+ # Rescan the wallet to detect the missing transaction
+ wallet_watch_only.rescanblockchain()
+ assert_equal(wallet_watch_only.gettransaction(tx_id)['confirmations'], 50)
+ assert_equal(wallet_watch_only.getbalances()['mine' if self.options.descriptors else 'watchonly']['trusted'], 2)
+
+ # Reindex and wait for it to finish
+ with node.assert_debug_log(expected_msgs=["initload thread exit"]):
+ self.restart_node(0, extra_args=['-reindex=1', f'-mocktime={self.node_time}'])
+ node.syncwithvalidationinterfacequeue()
+
+ # Verify the transaction is still 'confirmed' after reindex
+ wallet_watch_only = node.get_wallet_rpc('watch_only')
+ tx_info = wallet_watch_only.gettransaction(tx_id)
+ assert_equal(tx_info['confirmations'], 50)
+
+ # Depending on the wallet type, the birth time changes.
+ if self.options.descriptors:
+ # For descriptors, verify the wallet updated the birth time to the transaction time
+ assert_equal(tx_info['time'], wallet_watch_only.getwalletinfo()['birthtime'])
+ else:
+ # For legacy, as the birth time was set to the beginning of time, verify it did not change
+ assert_equal(wallet_birthtime, 1)
+
+ wallet_watch_only.unloadwallet()
+
+ def run_test(self):
+ node = self.nodes[0]
+ self.node_time = int(time.time())
+ node.setmocktime(self.node_time)
+
+ # Fund miner
+ node.createwallet(wallet_name='miner', load_on_startup=True)
+ miner_wallet = node.get_wallet_rpc('miner')
+ self.generatetoaddress(node, COINBASE_MATURITY + 10, miner_wallet.getnewaddress())
+
+ # Tests
+ self.birthtime_test(node, miner_wallet)
+
+
+if __name__ == '__main__':
+ WalletReindexTest().main()