diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4 index aa00168fce..859ddaabbb 100644 --- a/build-aux/m4/l_atomic.m4 +++ b/build-aux/m4/l_atomic.m4 @@ -7,7 +7,7 @@ dnl warranty. # Clang, when building for 32-bit, # and linking against libstdc++, requires linking with # -latomic if using the C++ atomic library. -# Can be tested with: clang++ test.cpp -m32 +# Can be tested with: clang++ -std=c++20 test.cpp -m32 # # Sourced from http://bugs.debian.org/797228 @@ -27,8 +27,11 @@ m4_define([_CHECK_ATOMIC_testbody], [[ auto t1 = t.load(); t.compare_exchange_strong(t1, 3s); - std::atomic a{}; + std::atomic d{}; + d.store(3.14); + auto d1 = d.load(); + std::atomic a{}; int64_t v = 5; int64_t r = a.fetch_add(v); return static_cast(r); diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh index 4f80d7ed42..bf4d1573e3 100755 --- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh +++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh @@ -6,15 +6,14 @@ export LC_ALL=C.UTF-8 -export CI_IMAGE_NAME_TAG="docker.io/debian:bookworm" +export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04" export CONTAINER_NAME=ci_native_fuzz_valgrind -export PACKAGES="clang llvm libclang-rt-dev libevent-dev libboost-dev libsqlite3-dev valgrind" +export PACKAGES="clang-16 llvm-16 libclang-rt-16-dev libevent-dev libboost-dev libsqlite3-dev valgrind" export NO_DEPENDS=1 export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=true export FUZZ_TESTS_CONFIG="--valgrind" export GOAL="install" -# Temporarily pin dwarf 4, until using Valgrind 3.20 or later -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang CXX=clang++ CFLAGS=-gdwarf-4 CXXFLAGS=-gdwarf-4" +export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang-16 CXX=clang++-16" export CCACHE_MAXSIZE=200M diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh index 9bdb2b7860..720e522a6a 100755 --- a/ci/test/00_setup_env_native_valgrind.sh +++ b/ci/test/00_setup_env_native_valgrind.sh @@ -6,12 +6,11 @@ export LC_ALL=C.UTF-8 -export CI_IMAGE_NAME_TAG="docker.io/debian:bookworm" +export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04" export CONTAINER_NAME=ci_native_valgrind -export PACKAGES="valgrind clang llvm libclang-rt-dev python3-zmq libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev" +export PACKAGES="valgrind clang-16 llvm-16 libclang-rt-16-dev python3-zmq libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev" export USE_VALGRIND=1 export NO_DEPENDS=1 -export TEST_RUNNER_EXTRA="--exclude feature_init,rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547 +export TEST_RUNNER_EXTRA="--exclude rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547 export GOAL="install" -# Temporarily pin dwarf 4, until using Valgrind 3.20 or later -export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang CXX=clang++ CFLAGS=-gdwarf-4 CXXFLAGS=-gdwarf-4" # TODO enable GUI +export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang-16 CXX=clang++-16" # TODO enable GUI diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 9624221880..1e9b682f3f 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -75,9 +75,8 @@ export OBJC_INCLUDE_PATH="${NATIVE_GCC}/include" export OBJCPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include" case "$HOST" in - *darwin*) - export LIBRARY_PATH="${NATIVE_GCC}/lib" - ;; + *darwin*) export LIBRARY_PATH="${NATIVE_GCC}/lib" ;; + *mingw*) export LIBRARY_PATH="${NATIVE_GCC}/lib" ;; *) NATIVE_GCC_STATIC="$(store_path gcc-toolchain static)" export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC_STATIC}/lib" diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 87dcf49bcb..8f13c642d3 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -110,12 +110,15 @@ desirable for building Bitcoin Core release binaries." (define (gcc-mingw-patches gcc) (package-with-extra-patches gcc - (search-our-patches "gcc-remap-guix-store.patch" - "vmov-alignment.patch"))) + (search-our-patches "gcc-remap-guix-store.patch"))) + +(define (binutils-mingw-patches binutils) + (package-with-extra-patches binutils + (search-our-patches "binutils-unaligned-default.patch"))) (define (make-mingw-pthreads-cross-toolchain target) "Create a cross-compilation toolchain package for TARGET" - (let* ((xbinutils (cross-binutils target)) + (let* ((xbinutils (binutils-mingw-patches (cross-binutils target))) (pthreads-xlibc mingw-w64-x86_64-winpthreads) (pthreads-xgcc (cross-gcc target #:xgcc (gcc-mingw-patches mingw-w64-base-gcc) @@ -517,7 +520,6 @@ inspecting signatures in Mach-O binaries.") (cond ((string-suffix? "-mingw32" target) (list ;; Native GCC 12 toolchain gcc-toolchain-12 - (list gcc-toolchain-12 "static") zip (make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32") nsis-x86_64 diff --git a/contrib/guix/patches/binutils-unaligned-default.patch b/contrib/guix/patches/binutils-unaligned-default.patch new file mode 100644 index 0000000000..d1bc71aee1 --- /dev/null +++ b/contrib/guix/patches/binutils-unaligned-default.patch @@ -0,0 +1,22 @@ +commit 6537181f59ed186a341db621812a6bc35e22eaf6 +Author: fanquake +Date: Wed Apr 10 12:15:52 2024 +0200 + + build: turn on -muse-unaligned-vector-move by default + + This allows us to avoid (more invasively) patching GCC, to avoid + unaligned instruction use. + +diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c +index e0632681477..14a9653abdf 100644 +--- a/gas/config/tc-i386.c ++++ b/gas/config/tc-i386.c +@@ -801,7 +801,7 @@ static unsigned int no_cond_jump_promotion = 0; + static unsigned int sse2avx; + + /* Encode aligned vector move as unaligned vector move. */ +-static unsigned int use_unaligned_vector_move; ++static unsigned int use_unaligned_vector_move = 1; + + /* Encode scalar AVX instructions with specific vector length. */ + static enum diff --git a/contrib/guix/patches/vmov-alignment.patch b/contrib/guix/patches/vmov-alignment.patch deleted file mode 100644 index 96e1cb7cd1..0000000000 --- a/contrib/guix/patches/vmov-alignment.patch +++ /dev/null @@ -1,288 +0,0 @@ -Description: Use unaligned VMOV instructions -Author: Stephen Kitt -Bug-Debian: https://bugs.debian.org/939559 -See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412 - -Based on a patch originally by Claude Heiland-Allen - ---- a/gcc/config/i386/sse.md -+++ b/gcc/config/i386/sse.md -@@ -1058,17 +1058,11 @@ - { - if (FLOAT_MODE_P (GET_MODE_INNER (mode))) - { -- if (misaligned_operand (operands[1], mode)) -- return "vmovu\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}"; -- else -- return "vmova\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}"; -+ return "vmovu\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}"; - } - else - { -- if (misaligned_operand (operands[1], mode)) -- return "vmovdqu\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}"; -- else -- return "vmovdqa\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}"; -+ return "vmovdqu\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}"; - } - } - [(set_attr "type" "ssemov") -@@ -1184,17 +1178,11 @@ - { - if (FLOAT_MODE_P (GET_MODE_INNER (mode))) - { -- if (misaligned_operand (operands[0], mode)) -- return "vmovu\t{%1, %0%{%2%}|%0%{%2%}, %1}"; -- else -- return "vmova\t{%1, %0%{%2%}|%0%{%2%}, %1}"; -+ return "vmovu\t{%1, %0%{%2%}|%0%{%2%}, %1}"; - } - else - { -- if (misaligned_operand (operands[0], mode)) -- return "vmovdqu\t{%1, %0%{%2%}|%0%{%2%}, %1}"; -- else -- return "vmovdqa\t{%1, %0%{%2%}|%0%{%2%}, %1}"; -+ return "vmovdqu\t{%1, %0%{%2%}|%0%{%2%}, %1}"; - } - } - [(set_attr "type" "ssemov") -@@ -7806,7 +7794,7 @@ - "TARGET_SSE && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "@ - %vmovlps\t{%1, %0|%q0, %1} -- %vmovaps\t{%1, %0|%0, %1} -+ %vmovups\t{%1, %0|%0, %1} - %vmovlps\t{%1, %d0|%d0, %q1}" - [(set_attr "type" "ssemov") - (set_attr "prefix" "maybe_vex") -@@ -13997,29 +13985,15 @@ - switch (mode) - { - case E_V8DFmode: -- if (misaligned_operand (operands[2], mode)) -- return "vmovupd\t{%2, %x0|%x0, %2}"; -- else -- return "vmovapd\t{%2, %x0|%x0, %2}"; -+ return "vmovupd\t{%2, %x0|%x0, %2}"; - case E_V16SFmode: -- if (misaligned_operand (operands[2], mode)) -- return "vmovups\t{%2, %x0|%x0, %2}"; -- else -- return "vmovaps\t{%2, %x0|%x0, %2}"; -+ return "vmovups\t{%2, %x0|%x0, %2}"; - case E_V8DImode: -- if (misaligned_operand (operands[2], mode)) -- return which_alternative == 2 ? "vmovdqu64\t{%2, %x0|%x0, %2}" -+ return which_alternative == 2 ? "vmovdqu64\t{%2, %x0|%x0, %2}" - : "vmovdqu\t{%2, %x0|%x0, %2}"; -- else -- return which_alternative == 2 ? "vmovdqa64\t{%2, %x0|%x0, %2}" -- : "vmovdqa\t{%2, %x0|%x0, %2}"; - case E_V16SImode: -- if (misaligned_operand (operands[2], mode)) -- return which_alternative == 2 ? "vmovdqu32\t{%2, %x0|%x0, %2}" -+ return which_alternative == 2 ? "vmovdqu32\t{%2, %x0|%x0, %2}" - : "vmovdqu\t{%2, %x0|%x0, %2}"; -- else -- return which_alternative == 2 ? "vmovdqa32\t{%2, %x0|%x0, %2}" -- : "vmovdqa\t{%2, %x0|%x0, %2}"; - default: - gcc_unreachable (); - } -@@ -21225,63 +21199,27 @@ - switch (get_attr_mode (insn)) - { - case MODE_V16SF: -- if (misaligned_operand (operands[1], mode)) -- return "vmovups\t{%1, %t0|%t0, %1}"; -- else -- return "vmovaps\t{%1, %t0|%t0, %1}"; -+ return "vmovups\t{%1, %t0|%t0, %1}"; - case MODE_V8DF: -- if (misaligned_operand (operands[1], mode)) -- return "vmovupd\t{%1, %t0|%t0, %1}"; -- else -- return "vmovapd\t{%1, %t0|%t0, %1}"; -+ return "vmovupd\t{%1, %t0|%t0, %1}"; - case MODE_V8SF: -- if (misaligned_operand (operands[1], mode)) -- return "vmovups\t{%1, %x0|%x0, %1}"; -- else -- return "vmovaps\t{%1, %x0|%x0, %1}"; -+ return "vmovups\t{%1, %x0|%x0, %1}"; - case MODE_V4DF: -- if (misaligned_operand (operands[1], mode)) -- return "vmovupd\t{%1, %x0|%x0, %1}"; -- else -- return "vmovapd\t{%1, %x0|%x0, %1}"; -+ return "vmovupd\t{%1, %x0|%x0, %1}"; - case MODE_XI: -- if (misaligned_operand (operands[1], mode)) -- { -- if (which_alternative == 2) -- return "vmovdqu\t{%1, %t0|%t0, %1}"; -- else if (GET_MODE_SIZE (mode) == 8) -- return "vmovdqu64\t{%1, %t0|%t0, %1}"; -- else -- return "vmovdqu32\t{%1, %t0|%t0, %1}"; -- } -+ if (which_alternative == 2) -+ return "vmovdqu\t{%1, %t0|%t0, %1}"; -+ else if (GET_MODE_SIZE (mode) == 8) -+ return "vmovdqu64\t{%1, %t0|%t0, %1}"; - else -- { -- if (which_alternative == 2) -- return "vmovdqa\t{%1, %t0|%t0, %1}"; -- else if (GET_MODE_SIZE (mode) == 8) -- return "vmovdqa64\t{%1, %t0|%t0, %1}"; -- else -- return "vmovdqa32\t{%1, %t0|%t0, %1}"; -- } -+ return "vmovdqu32\t{%1, %t0|%t0, %1}"; - case MODE_OI: -- if (misaligned_operand (operands[1], mode)) -- { -- if (which_alternative == 2) -- return "vmovdqu\t{%1, %x0|%x0, %1}"; -- else if (GET_MODE_SIZE (mode) == 8) -- return "vmovdqu64\t{%1, %x0|%x0, %1}"; -- else -- return "vmovdqu32\t{%1, %x0|%x0, %1}"; -- } -+ if (which_alternative == 2) -+ return "vmovdqu\t{%1, %x0|%x0, %1}"; -+ else if (GET_MODE_SIZE (mode) == 8) -+ return "vmovdqu64\t{%1, %x0|%x0, %1}"; - else -- { -- if (which_alternative == 2) -- return "vmovdqa\t{%1, %x0|%x0, %1}"; -- else if (GET_MODE_SIZE (mode) == 8) -- return "vmovdqa64\t{%1, %x0|%x0, %1}"; -- else -- return "vmovdqa32\t{%1, %x0|%x0, %1}"; -- } -+ return "vmovdqu32\t{%1, %x0|%x0, %1}"; - default: - gcc_unreachable (); - } ---- a/gcc/config/i386/i386.cc -+++ b/gcc/config/i386/i386.cc -@@ -5418,17 +5418,15 @@ ix86_get_ssemov (rtx *operands, unsigned size, - { - case opcode_int: - if (scalar_mode == E_HFmode) -- opcode = (misaligned_p -- ? (TARGET_AVX512BW ? "vmovdqu16" : "vmovdqu64") -- : "vmovdqa64"); -+ opcode = TARGET_AVX512BW ? "vmovdqu16" : "vmovdqu64"; - else -- opcode = misaligned_p ? "vmovdqu32" : "vmovdqa32"; -+ opcode = "vmovdqu32"; - break; - case opcode_float: -- opcode = misaligned_p ? "vmovups" : "vmovaps"; -+ opcode = "vmovups"; - break; - case opcode_double: -- opcode = misaligned_p ? "vmovupd" : "vmovapd"; -+ opcode = "vmovupd"; - break; - } - } -@@ -5438,29 +5436,21 @@ ix86_get_ssemov (rtx *operands, unsigned size, - { - case E_HFmode: - if (evex_reg_p) -- opcode = (misaligned_p -- ? (TARGET_AVX512BW -- ? "vmovdqu16" -- : "vmovdqu64") -- : "vmovdqa64"); -+ opcode = TARGET_AVX512BW ? "vmovdqu16" : "vmovdqu64"; - else -- opcode = (misaligned_p -- ? (TARGET_AVX512BW -- ? "vmovdqu16" -- : "%vmovdqu") -- : "%vmovdqa"); -+ opcode = TARGET_AVX512BW ? "vmovdqu16" : "%vmovdqu"; - break; - case E_SFmode: -- opcode = misaligned_p ? "%vmovups" : "%vmovaps"; -+ opcode = "%vmovups"; - break; - case E_DFmode: -- opcode = misaligned_p ? "%vmovupd" : "%vmovapd"; -+ opcode = "%vmovupd"; - break; - case E_TFmode: - if (evex_reg_p) -- opcode = misaligned_p ? "vmovdqu64" : "vmovdqa64"; -+ opcode = "vmovdqu64"; - else -- opcode = misaligned_p ? "%vmovdqu" : "%vmovdqa"; -+ opcode = "%vmovdqu"; - break; - default: - gcc_unreachable (); -@@ -5472,48 +5462,32 @@ ix86_get_ssemov (rtx *operands, unsigned size, - { - case E_QImode: - if (evex_reg_p) -- opcode = (misaligned_p -- ? (TARGET_AVX512BW -- ? "vmovdqu8" -- : "vmovdqu64") -- : "vmovdqa64"); -+ opcode = TARGET_AVX512BW ? "vmovdqu8" : "vmovdqu64"; - else -- opcode = (misaligned_p -- ? (TARGET_AVX512BW -- ? "vmovdqu8" -- : "%vmovdqu") -- : "%vmovdqa"); -+ opcode = TARGET_AVX512BW ? "vmovdqu8" : "%vmovdqu"; - break; - case E_HImode: - if (evex_reg_p) -- opcode = (misaligned_p -- ? (TARGET_AVX512BW -- ? "vmovdqu16" -- : "vmovdqu64") -- : "vmovdqa64"); -+ opcode = TARGET_AVX512BW ? "vmovdqu16" : "vmovdqu64"; - else -- opcode = (misaligned_p -- ? (TARGET_AVX512BW -- ? "vmovdqu16" -- : "%vmovdqu") -- : "%vmovdqa"); -+ opcode = TARGET_AVX512BW ? "vmovdqu16" : "%vmovdqu"; - break; - case E_SImode: - if (evex_reg_p) -- opcode = misaligned_p ? "vmovdqu32" : "vmovdqa32"; -+ opcode = "vmovdqu32"; - else -- opcode = misaligned_p ? "%vmovdqu" : "%vmovdqa"; -+ opcode = "%vmovdqu"; - break; - case E_DImode: - case E_TImode: - case E_OImode: - if (evex_reg_p) -- opcode = misaligned_p ? "vmovdqu64" : "vmovdqa64"; -+ opcode = "vmovdqu64"; - else -- opcode = misaligned_p ? "%vmovdqu" : "%vmovdqa"; -+ opcode = "%vmovdqu"; - break; - case E_XImode: -- opcode = misaligned_p ? "vmovdqu64" : "vmovdqa64"; -+ opcode = "vmovdqu64"; - break; - default: - gcc_unreachable (); diff --git a/contrib/init/bitcoind.service b/contrib/init/bitcoind.service index 87da17f955..ade8a05926 100644 --- a/contrib/init/bitcoind.service +++ b/contrib/init/bitcoind.service @@ -81,5 +81,8 @@ PrivateDevices=true # Deny the creation of writable and executable memory mappings. MemoryDenyWriteExecute=true +# Restrict ABIs to help ensure MemoryDenyWriteExecute is enforced +SystemCallArchitectures=native + [Install] WantedBy=multi-user.target diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp index ee91acd5ef..c537f9e7ec 100644 --- a/contrib/valgrind.supp +++ b/contrib/valgrind.supp @@ -13,8 +13,8 @@ # # Note that suppressions may depend on OS and/or library versions. # Tested on: -# * aarch64 (Debian Bookworm system libs, clang, without gui) -# * x86_64 (Debian Bookworm system libs, clang, without gui) +# * aarch64 (Ubuntu Noble system libs, clang, without gui) +# * x86_64 (Ubuntu Noble system libs, clang, without gui) { Suppress libdb warning - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=662917 Memcheck:Cond diff --git a/depends/packages.md b/depends/packages.md index 0ffdc66d48..7a7a42afa1 100644 --- a/depends/packages.md +++ b/depends/packages.md @@ -162,7 +162,7 @@ From the [Gentoo Wiki entry](https://wiki.gentoo.org/wiki/Project:Quality_Assura > creates. This leads to massive overlinking, which is toxic to the Gentoo > ecosystem, as it leads to a massive number of unnecessary rebuilds. -Where possible, packages are built with Position Independant Code. Either using +Where possible, packages are built with Position Independent Code. Either using the Autotools `--with-pic` flag, or `CMAKE_POSITION_INDEPENDENT_CODE` with CMake. ## Secondary dependencies: diff --git a/doc/descriptors.md b/doc/descriptors.md index 1baf652f30..3b94ec03e4 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -243,7 +243,18 @@ Often it is useful to communicate a description of scripts along with the necessary private keys. For this reason, anywhere a public key or xpub is supported, a private key in WIF format or xprv may be provided instead. This is useful when private keys are necessary for hardened derivation -steps, or for dumping wallet descriptors including private key material. +steps, for signing transactions, or for dumping wallet descriptors +including private key material. + +For example, after importing the following 2-of-3 multisig descriptor +into a wallet, one could use `signrawtransactionwithwallet` +to sign a transaction with the first key: +``` +sh(multi(2,xprv.../84'/0'/0'/0/0,xpub1...,xpub2...)) +``` +Note how the first key is an xprv private key with a specific derivation path, +while the other two are public keys. + ### Compatibility with old wallets diff --git a/doc/release-notes/release-notes-27.0.md b/doc/release-notes/release-notes-27.0.md new file mode 100644 index 0000000000..5060068328 --- /dev/null +++ b/doc/release-notes/release-notes-27.0.md @@ -0,0 +1,217 @@ +Bitcoin Core version 27.0 is now available from: + + + +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: + + + +To receive security and update notifications, please subscribe to: + + + +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 3.17+, 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 +=============== + +libbitcoinconsensus +------------------- + +- libbitcoinconsensus is deprecated and will be removed for v28. This library has + existed for nearly 10 years with very little known uptake or impact. It has + become a maintenance burden. + + The underlying functionality does not change between versions, so any users of + the library can continue to use the final release indefinitely, with the + understanding that Taproot is its final consensus update. + + In the future, libbitcoinkernel will provide a much more useful API that is + aware of the UTXO set, and therefore be able to fully validate transactions and + blocks. (#29189) + +mempool.dat compatibility +------------------------- + +- The `mempool.dat` file created by -persistmempool or the savemempool RPC will + be written in a new format. This new format includes the XOR'ing of transaction + contents to mitigate issues where external programs (such as anti-virus) attempt + to interpret and potentially modify the file. + + This new format can not be read by previous software releases. To allow for a + downgrade, a temporary setting `-persistmempoolv1` has been added to fall back + to the legacy format. (#28207) + +P2P and network changes +----------------------- + +- BIP324 v2 transport is now enabled by default. It remains possible to disable v2 + by running with `-v2transport=0`. (#29347) +- Manual connection options (`-connect`, `-addnode` and `-seednode`) will + now follow `-v2transport` to connect with v2 by default. They will retry with + v1 on failure. (#29058) + +- Network-adjusted time has been removed from consensus code. It is replaced + with (unadjusted) system time. The warning for a large median time offset + (70 minutes or more) is kept. This removes the implicit security assumption of + requiring an honest majority of outbound peers, and increases the importance + of the node operator ensuring their system time is (and stays) correct to not + fall out of consensus with the network. (#28956) + +Mempool Policy Changes +---------------------- + +- Opt-in Topologically Restricted Until Confirmation (TRUC) Transactions policy + (aka v3 transaction policy) is available for use on test networks when + `-acceptnonstdtxn=1` is set. By setting the transaction version number to 3, TRUC transactions + request the application of limits on spending of their unconfirmed outputs. These + restrictions simplify the assessment of incentive compatibility of accepting or + replacing TRUC transactions, thus ensuring any replacements are more profitable for + the node and making fee-bumping more reliable. TRUC transactions are currently + nonstandard and can only be used on test networks where the standardness rules are + relaxed or disabled (e.g. with `-acceptnonstdtxn=1`). (#28948) + +External Signing +---------------- + +- Support for external signing on Windows has been disabled. It will be re-enabled + once the underlying dependency (Boost Process), has been replaced with a different + library. (#28967) + +Updated RPCs +------------ + +- The addnode RPC now follows the `-v2transport` option (now on by default, see above) for making connections. + It remains possible to specify the transport type manually with the v2transport argument of addnode. (#29239) + +Build System +------------ + +- A C++20 capable compiler is now required to build Bitcoin Core. (#28349) +- MacOS releases are configured to use the hardened runtime libraries (#29127) + +Wallet +------ + +- The CoinGrinder coin selection algorithm has been introduced to mitigate unnecessary + large input sets and lower transaction costs at high feerates. CoinGrinder + searches for the input set with minimal weight. Solutions found by + CoinGrinder will produce a change output. CoinGrinder is only active at + elevated feerates (default: 30+ sat/vB, based on `-consolidatefeerate`×3). (#27877) +- The Branch And Bound coin selection algorithm will be disabled when the subtract fee + from outputs feature is used. (#28994) +- If the birth time of a descriptor is detected to be later than the first transaction + involving that descriptor, the birth time will be reset to the earlier time. (#28920) + +Low-level changes +================= + +Pruning +------- + +- When pruning during initial block download, more blocks will be pruned at each + flush in order to speed up the syncing of such nodes. (#20827) + +Init +---- + +- Various fixes to prevent issues where subsequent instances of Bitcoin Core would + result in deletion of files in use by an existing instance. (#28784, #28946) +- Improved handling of empty `settings.json` files. (#29144) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- 22388o⚡️ +- Aaron Clauson +- Amiti Uttarwar +- Andrew Toth +- Anthony Towns +- Antoine Poinsot +- Ava Chow +- Brandon Odiwuor +- brunoerg +- Chris Stewart +- Cory Fields +- dergoegge +- djschnei21 +- Fabian Jahr +- fanquake +- furszy +- Gloria Zhao +- Greg Sanders +- Hennadii Stepanov +- Hernan Marino +- iamcarlos94 +- ismaelsadeeq +- Jameson Lopp +- Jesse Barton +- John Moffett +- Jon Atack +- josibake +- jrakibi +- Justin Dhillon +- Kashif Smith +- kevkevin +- Kristaps Kaupe +- L0la L33tz +- Luke Dashjr +- Lőrinc +- marco +- MarcoFalke +- Mark Friedenbach +- Marnix +- Martin Leitner-Ankerl +- Martin Zumsande +- Max Edwards +- Murch +- muxator +- naiyoma +- Nikodemas Tuckus +- ns-xvrn +- pablomartin4btc +- Peter Todd +- Pieter Wuille +- Richard Myers +- Roman Zeyde +- Russell Yanofsky +- Ryan Ofsky +- Sebastian Falbesoner +- Sergi Delgado Segura +- Sjors Provoost +- stickies-v +- stratospher +- Supachai Kheawjuy +- TheCharlatan +- UdjinM6 +- Vasil Dimov +- w0xlt +- willcl-ark + + +As well as to everyone that helped with translations on +[Transifex](https://www.transifex.com/bitcoin/bitcoin/). diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 084b9a6615..1d1a84e375 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -109,22 +109,26 @@ QFont fixedPitchFont(bool use_embedded_font) return QFontDatabase::systemFont(QFontDatabase::FixedFont); } -// Just some dummy data to generate a convincing random-looking (but consistent) address -static const uint8_t dummydata[] = {0xeb,0x15,0x23,0x1d,0xfc,0xeb,0x60,0x92,0x58,0x86,0xb6,0x7d,0x06,0x52,0x99,0x92,0x59,0x15,0xae,0xb1,0x72,0xc0,0x66,0x47}; - -// Generate a dummy address with invalid CRC, starting with the network prefix. +// Return a pre-generated dummy bech32m address (P2TR) with invalid checksum. static std::string DummyAddress(const CChainParams ¶ms) { - std::vector sourcedata = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); - sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata)); - for(int i=0; i<256; ++i) { // Try every trailing byte - std::string s = EncodeBase58(sourcedata); - if (!IsValidDestinationString(s)) { - return s; - } - sourcedata[sourcedata.size()-1] += 1; - } - return ""; + std::string addr; + switch (params.GetChainType()) { + case ChainType::MAIN: + addr = "bc1p35yvjel7srp783ztf8v6jdra7dhfzk5jaun8xz2qp6ws7z80n4tq2jku9f"; + break; + case ChainType::SIGNET: + case ChainType::TESTNET: + addr = "tb1p35yvjel7srp783ztf8v6jdra7dhfzk5jaun8xz2qp6ws7z80n4tqa6qnlg"; + break; + case ChainType::REGTEST: + addr = "bcrt1p35yvjel7srp783ztf8v6jdra7dhfzk5jaun8xz2qp6ws7z80n4tqsr2427"; + break; + } // no default case, so the compiler can warn about missing cases + assert(!addr.empty()); + + if (Assume(!IsValidDestinationString(addr))) return addr; + return {}; } void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent) diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 2021e5f9dc..551c0ffd13 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -112,10 +112,10 @@ FreedesktopImage::FreedesktopImage(const QImage &img): for(unsigned int ptr = 0; ptr < num_pixels; ++ptr) { - image[ptr*BYTES_PER_PIXEL+0] = data[ptr] >> 16; // R - image[ptr*BYTES_PER_PIXEL+1] = data[ptr] >> 8; // G - image[ptr*BYTES_PER_PIXEL+2] = data[ptr]; // B - image[ptr*BYTES_PER_PIXEL+3] = data[ptr] >> 24; // A + image[ptr * BYTES_PER_PIXEL + 0] = char(data[ptr] >> 16); // R + image[ptr * BYTES_PER_PIXEL + 1] = char(data[ptr] >> 8); // G + image[ptr * BYTES_PER_PIXEL + 2] = char(data[ptr]); // B + image[ptr * BYTES_PER_PIXEL + 3] = char(data[ptr] >> 24); // A } } diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 09e0771534..4926d1e80b 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -134,7 +134,7 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int return; QString date = ttm->index(start, TransactionTableModel::Date, parent).data().toString(); - qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent).data(Qt::EditRole).toULongLong(); + qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent).data(Qt::EditRole).toLongLong(); QString type = ttm->index(start, TransactionTableModel::Type, parent).data().toString(); QModelIndex index = ttm->index(start, 0, parent); QString address = ttm->data(index, TransactionTableModel::AddressRole).toString(); diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index b8c0080aef..ffc2ee5ab0 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #ifdef HAVE_MALLOC_INFO @@ -58,9 +59,11 @@ static RPCHelpMan setmocktime() LOCK(cs_main); const int64_t time{request.params[0].getInt()}; - if (time < 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime cannot be negative: %s.", time)); + constexpr int64_t max_time{Ticks(std::chrono::nanoseconds::max())}; + if (time < 0 || time > max_time) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime must be in the range [0, %s], not %s.", max_time, time)); } + SetMockTime(time); const NodeContext& node_context{EnsureAnyNodeContext(request.context)}; for (const auto& chain_client : node_context.chain_clients) { diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 0d2460c606..3a1cb45e8d 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -291,6 +291,7 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1e-8")), COIN/100000000); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.1e-7")), COIN/100000000); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.01e-6")), COIN/100000000); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000000000000000000000000000000001e+30")), 1); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.0000000000000000000000000000000000000000000000000000000000000000000000000001e+68")), COIN/100000000); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("10000000000000000000000000000000000000000000000000000000000000000e-64")), COIN); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000e64")), COIN); diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index 8b90448b36..1c724555f3 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -421,7 +421,7 @@ void univalue_readwrite() // Valid, with leading or trailing whitespace BOOST_CHECK(v.read(" 1.0") && (v.get_real() == 1.0)); BOOST_CHECK(v.read("1.0 ") && (v.get_real() == 1.0)); - BOOST_CHECK(v.read("0.00000000000000000000000000000000000001e+30 ") && v.get_real() == 1e-8); + BOOST_CHECK(v.read("0.00000000000000000000000000000000000001e+30 ")); BOOST_CHECK(!v.read(".19e-6")); //should fail, missing leading 0, therefore invalid JSON // Invalid, initial garbage diff --git a/src/util/subprocess.hpp b/src/util/subprocess.hpp index 0fcc9397ea..e660aa143d 100644 --- a/src/util/subprocess.hpp +++ b/src/util/subprocess.hpp @@ -969,8 +969,8 @@ namespace detail { // Metaprogram for searching a type within // a variadic parameter pack // This is particularly required to do a compile time -// checking of the arguments provided to 'check_ouput' function -// wherein the user is not expected to provide an 'ouput' option. +// checking of the arguments provided to 'check_output' function +// wherein the user is not expected to provide an 'output' option. template struct param_pack{}; @@ -997,7 +997,7 @@ struct has_type> { /*! * A helper class to Popen class for setting * options as provided in the Popen constructor - * or in check_ouput arguments. + * or in check_output arguments. * This design allows us to _not_ have any fixed position * to any arguments and specify them in a way similar to what * can be done in python. diff --git a/src/validation.cpp b/src/validation.cpp index aa57236303..8bce49cb12 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -6208,13 +6208,14 @@ bool ChainstateManager::DeleteSnapshotChainstate() Assert(m_snapshot_chainstate); Assert(m_ibd_chainstate); - fs::path snapshot_datadir = GetSnapshotCoinsDBPath(*m_snapshot_chainstate); + fs::path snapshot_datadir = Assert(node::FindSnapshotChainstateDir(m_options.datadir)).value(); if (!DeleteCoinsDBFromDisk(snapshot_datadir, /*is_snapshot=*/ true)) { LogPrintf("Deletion of %s failed. Please remove it manually to continue reindexing.\n", fs::PathToString(snapshot_datadir)); return false; } m_active_chainstate = m_ibd_chainstate.get(); + m_active_chainstate->m_mempool = m_snapshot_chainstate->m_mempool; m_snapshot_chainstate.reset(); return true; } diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index c71784a589..8f14e2fcd7 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -288,7 +288,7 @@ class WalletImpl : public Wallet if (!res) return util::Error{util::ErrorString(res)}; const auto& txr = *res; fee = txr.fee; - change_pos = txr.change_pos ? *txr.change_pos : -1; + change_pos = txr.change_pos ? int(*txr.change_pos) : -1; return txr.tx; } diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index caf15058a3..5b7868452d 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -11,9 +11,6 @@ ## Possible test improvements -- TODO: test what happens with -reindex and -reindex-chainstate before the - snapshot is validated, and make sure it's deleted successfully. - Interesting test cases could be loading an assumeutxo snapshot file with: - TODO: Valid hash but invalid snapshot file (bad coin height or @@ -380,6 +377,17 @@ def check_tx_counts(final: bool) -> None: assert_equal(loaded['coins_loaded'], SNAPSHOT_BASE_HEIGHT) assert_equal(loaded['base_height'], SNAPSHOT_BASE_HEIGHT) + for reindex_arg in ['-reindex=1', '-reindex-chainstate=1']: + self.log.info(f"Check that restarting with {reindex_arg} will delete the snapshot chainstate") + self.restart_node(2, extra_args=[reindex_arg, *self.extra_args[2]]) + assert_equal(1, len(n2.getchainstates()["chainstates"])) + for i in range(1, 300): + block = n0.getblock(n0.getblockhash(i), 0) + n2.submitheader(block) + loaded = n2.loadtxoutset(dump_output['path']) + assert_equal(loaded['coins_loaded'], SNAPSHOT_BASE_HEIGHT) + assert_equal(loaded['base_height'], SNAPSHOT_BASE_HEIGHT) + normal, snapshot = n2.getchainstates()['chainstates'] assert_equal(normal['blocks'], START_HEIGHT) assert_equal(normal.get('snapshot_blockhash'), None) diff --git a/test/functional/p2p_addrv2_relay.py b/test/functional/p2p_addrv2_relay.py index f9a8c44be2..ea114e7d70 100755 --- a/test/functional/p2p_addrv2_relay.py +++ b/test/functional/p2p_addrv2_relay.py @@ -11,6 +11,7 @@ from test_framework.messages import ( CAddress, msg_addrv2, + msg_sendaddrv2, ) from test_framework.p2p import ( P2PInterface, @@ -75,6 +76,12 @@ def set_test_params(self): self.extra_args = [["-whitelist=addr@127.0.0.1"]] def run_test(self): + self.log.info('Check disconnection when sending sendaddrv2 after verack') + conn = self.nodes[0].add_p2p_connection(P2PInterface()) + with self.nodes[0].assert_debug_log(['sendaddrv2 received after verack from peer=0; disconnecting']): + conn.send_message(msg_sendaddrv2()) + conn.wait_for_disconnect() + self.log.info('Create connection that sends addrv2 messages') addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) msg = msg_addrv2() @@ -89,8 +96,8 @@ def run_test(self): msg.addrs = ADDRS msg_size = calc_addrv2_msg_size(ADDRS) with self.nodes[0].assert_debug_log([ - f'received: addrv2 ({msg_size} bytes) peer=0', - f'sending addrv2 ({msg_size} bytes) peer=1', + f'received: addrv2 ({msg_size} bytes) peer=1', + f'sending addrv2 ({msg_size} bytes) peer=2', ]): addr_source.send_and_ping(msg) self.nodes[0].setmocktime(int(time.time()) + 30 * 60) diff --git a/test/functional/p2p_compactblocks_hb.py b/test/functional/p2p_compactblocks_hb.py index c985a1f98d..023b33ff6d 100755 --- a/test/functional/p2p_compactblocks_hb.py +++ b/test/functional/p2p_compactblocks_hb.py @@ -32,10 +32,15 @@ def relay_block_through(self, peer): self.connect_nodes(peer, 0) self.generate(self.nodes[0], 1) self.disconnect_nodes(peer, 0) - status_to = [self.peer_info(1, i)['bip152_hb_to'] for i in range(2, 6)] - status_from = [self.peer_info(i, 1)['bip152_hb_from'] for i in range(2, 6)] - assert_equal(status_to, status_from) - return status_to + + def status_to(): + return [self.peer_info(1, i)['bip152_hb_to'] for i in range(2, 6)] + + def status_from(): + return [self.peer_info(i, 1)['bip152_hb_from'] for i in range(2, 6)] + + self.wait_until(lambda: status_to() == status_from()) + return status_to() def run_test(self): self.log.info("Testing reserved high-bandwidth mode slot for outbound peer...") diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py index 0e463c5072..ae1edec2f1 100755 --- a/test/functional/p2p_tx_download.py +++ b/test/functional/p2p_tx_download.py @@ -5,6 +5,7 @@ """ Test transaction download behavior """ +from decimal import Decimal import time from test_framework.messages import ( @@ -14,6 +15,7 @@ MSG_WTX, msg_inv, msg_notfound, + msg_tx, ) from test_framework.p2p import ( P2PInterface, @@ -22,6 +24,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + fill_mempool, ) from test_framework.wallet import MiniWallet @@ -54,6 +57,7 @@ def on_getdata(self, message): class TxDownloadTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 + self.extra_args= [['-datacarriersize=100000', '-maxmempool=5', '-persistmempool=0']] * self.num_nodes def test_tx_requests(self): self.log.info("Test that we request transactions from all our peers, eventually") @@ -241,6 +245,29 @@ def test_spurious_notfound(self): self.log.info('Check that spurious notfound is ignored') self.nodes[0].p2ps[0].send_message(msg_notfound(vec=[CInv(MSG_TX, 1)])) + def test_rejects_filter_reset(self): + self.log.info('Check that rejected tx is not requested again') + node = self.nodes[0] + fill_mempool(self, node, self.wallet) + self.wallet.rescan_utxos() + mempoolminfee = node.getmempoolinfo()['mempoolminfee'] + peer = node.add_p2p_connection(TestP2PConn()) + low_fee_tx = self.wallet.create_self_transfer(fee_rate=Decimal("0.9")*mempoolminfee) + assert_equal(node.testmempoolaccept([low_fee_tx['hex']])[0]["reject-reason"], "mempool min fee not met") + peer.send_and_ping(msg_tx(low_fee_tx['tx'])) + peer.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=int(low_fee_tx['wtxid'], 16))])) + node.setmocktime(int(time.time())) + node.bumpmocktime(MAX_GETDATA_INBOUND_WAIT) + peer.sync_with_ping() + assert_equal(peer.tx_getdata_count, 0) + + self.log.info('Check that rejection filter is cleared after new block comes in') + self.generate(self.wallet, 1, sync_fun=self.no_op) + peer.sync_with_ping() + peer.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=int(low_fee_tx['wtxid'], 16))])) + node.bumpmocktime(MAX_GETDATA_INBOUND_WAIT) + peer.wait_for_getdata([int(low_fee_tx['wtxid'], 16)]) + def run_test(self): self.wallet = MiniWallet(self.nodes[0]) @@ -257,7 +284,8 @@ def run_test(self): # Run each test against new bitcoind instances, as setting mocktimes has long-term effects on when # the next trickle relay event happens. - for test in [self.test_in_flight_max, self.test_inv_block, self.test_tx_requests]: + for test in [self.test_in_flight_max, self.test_inv_block, self.test_tx_requests, + self.test_rejects_filter_reset]: self.stop_nodes() self.start_nodes() self.connect_nodes(1, 0) diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py index e061030da3..37c42f2533 100755 --- a/test/functional/rpc_packages.py +++ b/test/functional/rpc_packages.py @@ -386,12 +386,14 @@ def test_maxfeerate_submitpackage(self): "-maxmempool=5", "-persistmempool=0", ]) + self.wallet.rescan_utxos() fill_mempool(self, node, self.wallet) minrelay = node.getmempoolinfo()["minrelaytxfee"] parent = self.wallet.create_self_transfer( fee_rate=minrelay, + confirmed_only=True, ) child = self.wallet.create_self_transfer( @@ -411,6 +413,7 @@ def test_maxfeerate_submitpackage(self): # Reset maxmempool, datacarriersize, reset dynamic mempool minimum feerate, and empty mempool. self.restart_node(0) + self.wallet.rescan_utxos() assert_equal(node.getrawmempool(), []) @@ -420,7 +423,10 @@ def test_maxburn_submitpackage(self): assert_equal(node.getrawmempool(), []) self.log.info("Submitpackage maxburnamount arg testing") - chained_txns_burn = self.wallet.create_self_transfer_chain(chain_length=2) + chained_txns_burn = self.wallet.create_self_transfer_chain( + chain_length=2, + utxo_to_spend=self.wallet.get_utxo(confirmed_only=True), + ) chained_burn_hex = [t["hex"] for t in chained_txns_burn] tx = tx_from_hex(chained_burn_hex[1]) diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py index cb99e483ec..f8df59d02a 100755 --- a/test/functional/rpc_uptime.py +++ b/test/functional/rpc_uptime.py @@ -23,7 +23,7 @@ def run_test(self): self._test_uptime() def _test_negative_time(self): - assert_raises_rpc_error(-8, "Mocktime cannot be negative: -1.", self.nodes[0].setmocktime, -1) + assert_raises_rpc_error(-8, "Mocktime must be in the range [0, 9223372036], not -1.", self.nodes[0].setmocktime, -1) def _test_uptime(self): wait_time = 10 diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index dbaf42fdaa..0de09b6440 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -505,6 +505,8 @@ def fill_mempool(test_framework, node, miniwallet): It will not ensure mempools become synced as it is based on a single node and assumes -minrelaytxfee is 1 sat/vbyte. + To avoid unintentional tx dependencies, it is recommended to use separate miniwallets for + mempool filling vs transactions in tests. """ test_framework.log.info("Fill the mempool until eviction is triggered and the mempoolminfee rises") txouts = gen_return_txouts() @@ -522,8 +524,14 @@ def fill_mempool(test_framework, node, miniwallet): # Mine COINBASE_MATURITY - 1 blocks so that the UTXOs are allowed to be spent test_framework.generate(node, 100 - 1) + # Get all UTXOs up front to ensure none of the transactions spend from each other, as that may + # change their effective feerate and thus the order in which they are selected for eviction. + confirmed_utxos = [miniwallet.get_utxo(confirmed_only=True) for _ in range(num_of_batches * tx_batch_size + 1)] + assert_equal(len(confirmed_utxos), num_of_batches * tx_batch_size + 1) + test_framework.log.debug("Create a mempool tx that will be evicted") - tx_to_be_evicted_id = miniwallet.send_self_transfer(from_node=node, fee_rate=relayfee)["txid"] + tx_to_be_evicted_id = miniwallet.send_self_transfer(from_node=node, utxo_to_spend=confirmed_utxos[0], fee_rate=relayfee)["txid"] + del confirmed_utxos[0] # Increase the tx fee rate to give the subsequent transactions a higher priority in the mempool # The tx has an approx. vsize of 65k, i.e. multiplying the previous fee rate (in sats/kvB) @@ -534,7 +542,9 @@ def fill_mempool(test_framework, node, miniwallet): with node.assert_debug_log(["rolling minimum fee bumped"]): for batch_of_txid in range(num_of_batches): fee = (batch_of_txid + 1) * base_fee - create_lots_of_big_transactions(miniwallet, node, fee, tx_batch_size, txouts) + utxos = confirmed_utxos[:tx_batch_size] + create_lots_of_big_transactions(miniwallet, node, fee, tx_batch_size, txouts, utxos) + del confirmed_utxos[:tx_batch_size] test_framework.log.debug("The tx should be evicted by now") # The number of transactions created should be greater than the ones present in the mempool