aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml20
-rw-r--r--REVIEWERS123
-rw-r--r--build_msvc/README.md2
-rwxr-xr-xci/test/00_setup_env_native_asan.sh11
-rwxr-xr-xci/test/00_setup_env_native_qt5.sh2
-rwxr-xr-xci/test/00_setup_env_native_tidy.sh2
-rwxr-xr-xci/test/04_install.sh8
-rwxr-xr-xci/test/05_before_script.sh4
-rwxr-xr-xci/test/06_script_b.sh5
-rw-r--r--configure.ac12
-rw-r--r--contrib/guix/manifest.scm25
-rw-r--r--depends/config.site.in7
-rw-r--r--depends/hosts/darwin.mk3
-rw-r--r--depends/packages/bdb.mk2
-rw-r--r--depends/packages/libxcb.mk3
-rw-r--r--depends/packages/native_cctools.mk14
-rw-r--r--depends/packages/native_clang.mk3
-rw-r--r--depends/packages/native_libtapi.mk4
-rw-r--r--depends/packages/qt.mk15
-rw-r--r--depends/patches/libxcb/remove_pthread_stubs.patch12
-rw-r--r--depends/patches/qt/dont_hardcode_x86_64.patch4
-rw-r--r--depends/patches/qt/fix_android_jni_static.patch2
-rw-r--r--depends/patches/qt/fix_limits_header.patch33
-rw-r--r--depends/patches/qt/guix_cross_lib_path.patch17
-rw-r--r--doc/dependencies.md2
-rw-r--r--doc/policy/README.md2
-rw-r--r--doc/policy/mempool-replacements.md2
-rw-r--r--doc/policy/packages.md2
-rw-r--r--doc/release-notes-25610.md12
-rw-r--r--src/Makefile.am19
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/addrman.cpp10
-rw-r--r--src/addrman.h7
-rw-r--r--src/addrman_impl.h4
-rw-r--r--src/bench/addrman.cpp2
-rw-r--r--src/bench/wallet_loading.cpp5
-rw-r--r--src/bitcoin-chainstate.cpp6
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/chain.cpp8
-rw-r--r--src/chain.h2
-rw-r--r--src/coins.cpp6
-rw-r--r--src/cuckoocache.h23
-rw-r--r--src/init.cpp62
-rw-r--r--src/init/common.cpp2
-rw-r--r--src/interfaces/wallet.h6
-rw-r--r--src/kernel/mempool_options.h19
-rw-r--r--src/kernel/validation_cache_sizes.h20
-rw-r--r--src/leveldb/util/env_posix.cc2
-rw-r--r--src/mempool_args.cpp39
-rw-r--r--src/net.cpp6
-rw-r--r--src/net_processing.cpp10
-rw-r--r--src/node/interfaces.cpp75
-rw-r--r--src/node/mempool_args.cpp99
-rw-r--r--src/node/mempool_args.h (renamed from src/mempool_args.h)13
-rw-r--r--src/node/psbt.cpp2
-rw-r--r--src/node/validation_cache_args.cpp34
-rw-r--r--src/node/validation_cache_args.h17
-rw-r--r--src/policy/policy.cpp13
-rw-r--r--src/policy/policy.h8
-rw-r--r--src/policy/settings.cpp5
-rw-r--r--src/policy/settings.h29
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/walletcontroller.cpp4
-rw-r--r--src/qt/walletmodel.cpp4
-rw-r--r--src/rest.cpp41
-rw-r--r--src/rpc/client.cpp2
-rw-r--r--src/rpc/fees.cpp3
-rw-r--r--src/rpc/mempool.cpp6
-rw-r--r--src/rpc/net.cpp10
-rw-r--r--src/rpc/rawtransaction.cpp6
-rw-r--r--src/rpc/rawtransaction_util.cpp7
-rw-r--r--src/rpc/rawtransaction_util.h3
-rw-r--r--src/rpc/request.cpp6
-rw-r--r--src/script/script.h2
-rw-r--r--src/script/sigcache.cpp18
-rw-r--r--src/script/sigcache.h11
-rw-r--r--src/script/standard.cpp3
-rw-r--r--src/script/standard.h11
-rw-r--r--src/test/addrman_tests.cpp18
-rw-r--r--src/test/fuzz/integer.cpp3
-rw-r--r--src/test/fuzz/key.cpp4
-rw-r--r--src/test/fuzz/rbf.cpp2
-rw-r--r--src/test/fuzz/script.cpp2
-rw-r--r--src/test/fuzz/script_sigcache.cpp11
-rw-r--r--src/test/fuzz/transaction.cpp5
-rw-r--r--src/test/fuzz/tx_pool.cpp11
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp2
-rw-r--r--src/test/miner_tests.cpp6
-rw-r--r--src/test/multisig_tests.cpp22
-rw-r--r--src/test/result_tests.cpp96
-rw-r--r--src/test/rpc_tests.cpp4
-rw-r--r--src/test/script_p2sh_tests.cpp14
-rw-r--r--src/test/skiplist_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp22
-rw-r--r--src/test/txvalidationcache_tests.cpp5
-rw-r--r--src/test/util/setup_common.cpp18
-rw-r--r--src/test/util/wallet.cpp6
-rw-r--r--src/timedata.h1
-rw-r--r--src/txmempool.cpp14
-rw-r--r--src/txmempool.h16
-rw-r--r--src/univalue/include/univalue.h20
-rw-r--r--src/univalue/lib/univalue.cpp33
-rw-r--r--src/univalue/test/object.cpp45
-rw-r--r--src/util/result.h87
-rw-r--r--src/util/system.cpp16
-rw-r--r--src/util/system.h2
-rw-r--r--src/validation.cpp44
-rw-r--r--src/validation.h3
-rw-r--r--src/wallet/feebumper.cpp4
-rw-r--r--src/wallet/fees.cpp2
-rw-r--r--src/wallet/interfaces.cpp18
-rw-r--r--src/wallet/rpc/addresses.cpp8
-rw-r--r--src/wallet/rpc/spend.cpp6
-rw-r--r--src/wallet/rpc/wallet.cpp112
-rw-r--r--src/wallet/scriptpubkeyman.cpp20
-rw-r--r--src/wallet/scriptpubkeyman.h6
-rw-r--r--src/wallet/spend.cpp50
-rw-r--r--src/wallet/spend.h2
-rw-r--r--src/wallet/test/availablecoins_tests.cpp18
-rw-r--r--src/wallet/test/coinselector_tests.cpp4
-rw-r--r--src/wallet/test/fuzz/notifications.cpp5
-rw-r--r--src/wallet/test/spend_tests.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp108
-rw-r--r--src/wallet/wallet.cpp18
-rw-r--r--src/wallet/wallet.h10
-rw-r--r--test/README.md6
-rwxr-xr-xtest/functional/feature_taproot.py6
-rwxr-xr-xtest/functional/interface_usdt_net.py2
-rwxr-xr-xtest/functional/interface_usdt_utxocache.py40
-rwxr-xr-xtest/functional/interface_usdt_validation.py2
-rwxr-xr-xtest/functional/mempool_package_limits.py316
-rwxr-xr-xtest/functional/p2p_permissions.py3
-rwxr-xr-xtest/functional/p2p_segwit.py6
-rwxr-xr-xtest/functional/rpc_psbt.py2
-rw-r--r--test/functional/test_framework/util.py4
-rw-r--r--test/functional/test_framework/wallet.py58
-rwxr-xr-xtest/functional/test_runner.py2
-rwxr-xr-xtest/functional/wallet_listtransactions.py6
-rwxr-xr-xtest/functional/wallet_simulaterawtx.py129
-rwxr-xr-xtest/get_previous_releases.py113
141 files changed, 1532 insertions, 1144 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index fcf1200d35..f2a08cdd48 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -109,9 +109,9 @@ task:
VCPKG_DEFAULT_BINARY_CACHE: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\archives'
CCACHE_DIR: 'C:\Users\ContainerAdministrator\AppData\Local\ccache'
WRAPPED_CL: 'C:\Users\ContainerAdministrator\AppData\Local\Temp\cirrus-ci-build\ci\test\wrapped-cl.bat'
- QT_DOWNLOAD_URL: 'https://download.qt.io/official_releases/qt/5.15/5.15.3/single/qt-everywhere-opensource-src-5.15.3.zip'
- QT_LOCAL_PATH: 'C:\qt-everywhere-opensource-src-5.15.3.zip'
- QT_SOURCE_DIR: 'C:\qt-everywhere-src-5.15.3'
+ QT_DOWNLOAD_URL: 'https://download.qt.io/official_releases/qt/5.15/5.15.5/single/qt-everywhere-opensource-src-5.15.5.zip'
+ QT_LOCAL_PATH: 'C:\qt-everywhere-opensource-src-5.15.5.zip'
+ QT_SOURCE_DIR: 'C:\qt-everywhere-src-5.15.5'
QTBASEDIR: 'C:\Qt_static'
x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
QT_CONFIGURE_COMMAND: '..\configure -release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml'
@@ -259,12 +259,20 @@ task:
MAKEJOBS: "-j4" # Avoid excessive memory use due to MSan
task:
- name: '[ASan + LSan + UBSan + integer, no depends] [jammy]'
+ name: '[ASan + LSan + UBSan + integer, no depends, USDT] [jammy]'
<< : *GLOBAL_TASK_TEMPLATE
- container:
- image: ubuntu:jammy
+ # We can't use a 'container' for the USDT interface tests as the CirrusCI
+ # containers don't have privileges to hook into bitcoind. CirrusCI uses
+ # Google Compute Engine instances: https://cirrus-ci.org/guide/custom-vms/
+ # Images can be found here: https://cloud.google.com/compute/docs/images/os-details
+ compute_engine_instance:
+ image_project: ubuntu-os-cloud
+ image: family/ubuntu-2204-lts # when upgrading, check if we can drop "ADD_UNTRUSTED_BPFCC_PPA"
+ cpu: 4
+ memory: 12G
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
+ HOME: /root/ # Only needed for compute_engine_instance
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
MAKEJOBS: "-j4" # Avoid excessive memory use
diff --git a/REVIEWERS b/REVIEWERS
index dd962947ff..cb1bafa496 100644
--- a/REVIEWERS
+++ b/REVIEWERS
@@ -15,126 +15,3 @@
# review a pull request. Peer review is always welcome and is a critical
# component of the progress of the codebase. Information on peer review
# guidelines can be found in the CONTRIBUTING.md doc.
-
-
-# Maintainers
-# @achow101
-# @fanquake
-# @hebasto
-# @laanwj
-# @marcofalke
-# @sipa
-
-# Docs
-/doc/*[a-zA-Z-].md @harding
-/doc/Doxyfile.in @fanquake
-/doc/REST-interface.md @jonasschnelli
-/doc/benchmarking.md @ariard
-/doc/bitcoin-conf.md @hebasto
-/doc/build-freebsd.md @fanquake
-/doc/build-netbsd.md @fanquake
-/doc/build-openbsd.md @laanwj
-/doc/build-osx.md @fanquake
-/doc/build-unix.md @laanwj
-/doc/build-windows.md @sipsorcery
-/doc/dependencies.md @fanquake
-/doc/developer-notes.md @laanwj
-/doc/files.md @hebasto
-/doc/reduce-memory.md @fanquake
-/doc/reduce-traffic.md @jonasschnelli
-/doc/release-process.md @laanwj
-/doc/translation_strings_policy.md @laanwj
-
-# Build aux
-/build-aux/m4/bitcoin_qt.m4 @hebasto
-
-# MSVC build system
-/build_msvc/ @sipsorcery
-
-# Settings
-/src/util/settings.* @ryanofsky
-
-# Fuzzing
-
-# Tests
-/src/test/net_peer_eviction_tests.cpp @jonatack
-/test/functional/mempool_updatefromblock.py @hebasto
-/test/functional/feature_asmap.py @jonatack
-/test/functional/interface_bitcoin_cli.py @jonatack
-
-# Backwards compatibility tests
-*_compatibility.py @sjors
-/test/functional/wallet_upgradewallet.py @sjors @achow101
-/test/get_previous_releases.py @sjors
-
-# Translations
-/src/util/translation.h @hebasto
-
-# Dev Tools
-/contrib/devtools/security-check.py @fanquake
-/contrib/devtools/test-security-check.py @fanquake
-/contrib/devtools/symbol-check.py @fanquake
-
-# Guix
-/contrib/guix/ @dongcarl
-
-# Compatibility
-/src/compat/glibc_* @fanquake
-
-# GUI
-/src/qt/forms/ @hebasto
-
-# Wallet
-/src/wallet/ @achow101
-
-# CLI
-/src/bitcoin-cli.cpp @jonatack
-
-# Coinstats
-/src/node/coinstats.* @fjahr
-
-# Index
-/src/index/ @fjahr
-
-# Descriptors
-*descriptor* @achow101 @sipa
-
-# External signer
-*external_signer* @sjors
-/doc/external-signer.md @sjors
-*signer.py @sjors
-
-# Interfaces
-/src/interfaces/ @ryanofsky
-
-# DB
-/src/txdb.* @jamesob
-/src/dbwrapper.* @jamesob
-
-# Linter
-/test/lint/lint-shell.py @hebasto
-
-# Bech32
-/src/bech32.* @sipa
-/src/bench/bech32.* @sipa
-
-# PSBT
-/src/psbt* @achow101
-/src/node/psbt* @achow101
-/doc/psbt.md @achow101
-
-# P2P
-/src/net_processing.* @sipa
-/src/protocol.* @sipa
-
-# Consensus
-/src/coins.* @sipa @jamesob
-/src/script/script.* @sipa
-/src/script/interpreter.* @sipa
-/src/validation.* @sipa
-/src/consensus/ @sipa
-
-# Tracing
-/doc/tracing.md @jb55 @0xB10C
-/src/util/trace.h @jb55 @0xB10C
-/contrib/tracing/ @jb55 @0xB10C
diff --git a/build_msvc/README.md b/build_msvc/README.md
index 05cc2aad83..b9bebd369c 100644
--- a/build_msvc/README.md
+++ b/build_msvc/README.md
@@ -30,7 +30,7 @@ Qt
---------------------
To build Bitcoin Core with the GUI, a static build of Qt is required.
-1. Download a single ZIP archive of Qt source code from https://download.qt.io/official_releases/qt/ (e.g., [`qt-everywhere-opensource-src-5.15.3.zip`](https://download.qt.io/official_releases/qt/5.15/5.15.3/single/qt-everywhere-opensource-src-5.15.3.zip)), and expand it into a dedicated folder. The following instructions assume that this folder is `C:\dev\qt-source`.
+1. Download a single ZIP archive of Qt source code from https://download.qt.io/official_releases/qt/ (e.g., [`qt-everywhere-opensource-src-5.15.5.zip`](https://download.qt.io/official_releases/qt/5.15/5.15.5/single/qt-everywhere-opensource-src-5.15.5.zip)), and expand it into a dedicated folder. The following instructions assume that this folder is `C:\dev\qt-source`.
2. Open "x64 Native Tools Command Prompt for VS 2022", and input the following commands:
```cmd
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index 69883e3609..4f1792a9f0 100755
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -6,9 +6,14 @@
export LC_ALL=C.UTF-8
+# We install an up-to-date 'bpfcc-tools' package from an untrusted PPA.
+# This can be dropped with the next Ubuntu or Debian release that includes up-to-date packages.
+# See the if-then in ci/test/04_install.sh too.
+export ADD_UNTRUSTED_BPFCC_PPA=true
+
export CONTAINER_NAME=ci_native_asan
-export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
-export DOCKER_NAME_TAG=ubuntu:22.04
+export PACKAGES="systemtap-sdt-dev bpfcc-tools clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
+export DOCKER_NAME_TAG=ubuntu:22.04 # May not run in docker unless --enable-usdt is dropped
export NO_DEPENDS=1
export GOAL="install"
-export BITCOIN_CONFIG="--enable-c++20 --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
+export BITCOIN_CONFIG="--enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh
index f399e43612..8a6ea62d5c 100755
--- a/ci/test/00_setup_env_native_qt5.sh
+++ b/ci/test/00_setup_env_native_qt5.sh
@@ -14,6 +14,6 @@ export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude fe
export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"
-export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.14.3 v0.15.2 v0.16.3 v0.17.2 v0.18.1 v0.19.1 v0.20.1 v0.21.0 v22.0 v23.0"
+export DOWNLOAD_PREVIOUS_RELEASES="true"
export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-reduce-exports \
--enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\" CC=gcc-8 CXX=g++-8"
diff --git a/ci/test/00_setup_env_native_tidy.sh b/ci/test/00_setup_env_native_tidy.sh
index e4d3468473..11a12e336a 100755
--- a/ci/test/00_setup_env_native_tidy.sh
+++ b/ci/test/00_setup_env_native_tidy.sh
@@ -15,5 +15,5 @@ export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=false
export RUN_TIDY=true
export GOAL="install"
-export BITCOIN_CONFIG="CC=clang CXX=clang++ --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'"
+export BITCOIN_CONFIG="CC=clang CXX=clang++ --enable-c++20 --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'"
export CCACHE_SIZE=200M
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
index 453a34ca78..b706fb0906 100755
--- a/ci/test/04_install.sh
+++ b/ci/test/04_install.sh
@@ -68,6 +68,14 @@ if [[ $DOCKER_NAME_TAG == *centos* ]]; then
${CI_RETRY_EXE} CI_EXEC dnf -y install epel-release
${CI_RETRY_EXE} CI_EXEC dnf -y --allowerasing install "$DOCKER_PACKAGES" "$PACKAGES"
elif [ "$CI_USE_APT_INSTALL" != "no" ]; then
+ if [[ "${ADD_UNTRUSTED_BPFCC_PPA}" == "true" ]]; then
+ # Ubuntu 22.04 LTS and Debian 11 both have an outdated bpfcc-tools packages.
+ # The iovisor PPA is outdated as well. The next Ubuntu and Debian releases will contain updated
+ # packages. Meanwhile, use an untrusted PPA to install an up-to-date version of the bpfcc-tools
+ # package.
+ # TODO: drop this once we can use newer images in GCE
+ CI_EXEC add-apt-repository ppa:hadret/bpfcc
+ fi
${CI_RETRY_EXE} CI_EXEC apt-get update
${CI_RETRY_EXE} CI_EXEC apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$DOCKER_PACKAGES"
if [ -n "$PIP_PACKAGES" ]; then
diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh
index f3da6b4f31..ef3dff86ca 100755
--- a/ci/test/05_before_script.sh
+++ b/ci/test/05_before_script.sh
@@ -47,6 +47,6 @@ if [ -z "$NO_DEPENDS" ]; then
fi
CI_EXEC "$SHELL_OPTS" make "$MAKEJOBS" -C depends HOST="$HOST" "$DEP_OPTS" LOG=1
fi
-if [ -n "$PREVIOUS_RELEASES_TO_DOWNLOAD" ]; then
- CI_EXEC test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR" "${PREVIOUS_RELEASES_TO_DOWNLOAD}"
+if [ "$DOWNLOAD_PREVIOUS_RELEASES" = "true" ]; then
+ CI_EXEC test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR"
fi
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index 84b7ebe3fd..f1b0c1ac15 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -35,8 +35,9 @@ if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
fi
if [ "${RUN_TIDY}" = "true" ]; then
+ set -eo pipefail
export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/src/"
- CI_EXEC run-clang-tidy "${MAKEJOBS}"
+ ( CI_EXEC run-clang-tidy -quiet "${MAKEJOBS}" ) | grep -C5 "error"
export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/"
CI_EXEC "python3 ${DIR_IWYU}/include-what-you-use/iwyu_tool.py"\
" src/compat"\
@@ -44,6 +45,8 @@ if [ "${RUN_TIDY}" = "true" ]; then
" src/init"\
" src/kernel"\
" src/node/chainstate.cpp"\
+ " src/node/mempool_args.cpp"\
+ " src/node/validation_cache_args.cpp"\
" src/policy/feerate.cpp"\
" src/policy/packages.cpp"\
" src/policy/settings.cpp"\
diff --git a/configure.ac b/configure.ac
index 90e7f18515..7ed9514aae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,6 +19,16 @@ if test "$PKG_CONFIG" = ""; then
AC_MSG_ERROR([pkg-config not found])
fi
+# When compiling with depends, the `PKG_CONFIG_PATH` and `PKG_CONFIG_LIBDIR` variables,
+# being set in a `config.site` file, are not exported to let the `--config-cache` option
+# work properly.
+if test -n "$PKG_CONFIG_PATH"; then
+ PKG_CONFIG="env PKG_CONFIG_PATH=$PKG_CONFIG_PATH $PKG_CONFIG"
+fi
+if test -n "$PKG_CONFIG_LIBDIR"; then
+ PKG_CONFIG="env PKG_CONFIG_LIBDIR=$PKG_CONFIG_LIBDIR $PKG_CONFIG"
+fi
+
BITCOIN_DAEMON_NAME=bitcoind
BITCOIN_GUI_NAME=bitcoin-qt
BITCOIN_CLI_NAME=bitcoin-cli
@@ -322,7 +332,7 @@ AC_ARG_ENABLE([werror],
[enable_werror=no])
AC_ARG_ENABLE([external-signer],
- [AS_HELP_STRING([--enable-external-signer],[compile external signer support (default is yes, requires Boost::Process)])],
+ [AS_HELP_STRING([--enable-external-signer],[compile external signer support (default is auto, requires Boost::Process)])],
[use_external_signer=$enableval],
[use_external_signer=auto])
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 7471f08a2b..a2b1fe1f24 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -132,12 +132,19 @@ chain for " target " development."))
(define base-gcc gcc-10)
(define base-linux-kernel-headers linux-libre-headers-5.15)
+;; https://gcc.gnu.org/install/configure.html
+(define (hardened-gcc gcc)
+ (package-with-extra-configure-variable (
+ package-with-extra-configure-variable gcc
+ "--enable-default-ssp" "yes")
+ "--enable-default-pie" "yes"))
+
(define* (make-bitcoin-cross-toolchain target
#:key
(base-gcc-for-libc base-gcc)
(base-kernel-headers base-linux-kernel-headers)
- (base-libc (make-glibc-without-werror glibc-2.24))
- (base-gcc (make-gcc-rpath-link base-gcc)))
+ (base-libc (make-glibc-with-bind-now (make-glibc-without-werror glibc-2.24)))
+ (base-gcc (make-gcc-rpath-link (hardened-gcc base-gcc))))
"Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values
desirable for building Bitcoin Core release binaries."
(make-cross-toolchain target
@@ -402,6 +409,11 @@ thus should be able to compile on most platforms where these exist.")
(string-append indent
"@unittest.skip(\"Disabled by Guix\")\n"
line)))
+ (substitute* "tests/test_validate.py"
+ (("^(.*)def test_revocation_mode_soft" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
#t))
(replace 'check
(lambda _
@@ -520,6 +532,12 @@ inspecting signatures in Mach-O binaries.")
(define (make-glibc-without-werror glibc)
(package-with-extra-configure-variable glibc "enable_werror" "no"))
+(define (make-glibc-with-stack-protector glibc)
+ (package-with-extra-configure-variable glibc "--enable-stack-protector" "all"))
+
+(define (make-glibc-with-bind-now glibc)
+ (package-with-extra-configure-variable glibc "--enable-bind-now" "yes"))
+
(define-public glibc-2.24
(package
(inherit glibc-2.31)
@@ -607,7 +625,8 @@ inspecting signatures in Mach-O binaries.")
((string-contains target "-linux-")
(list (cond ((string-contains target "riscv64-")
(make-bitcoin-cross-toolchain target
- #:base-libc (make-glibc-without-werror glibc-2.27/bitcoin-patched)))
+ #:base-libc (make-glibc-with-stack-protector
+ (make-glibc-with-bind-now (make-glibc-without-werror glibc-2.27/bitcoin-patched)))))
(else
(make-bitcoin-cross-toolchain target)))))
((string-contains target "darwin")
diff --git a/depends/config.site.in b/depends/config.site.in
index f7e770343c..8f6849214d 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -84,12 +84,9 @@ fi
PKG_CONFIG="$(which pkg-config) --static"
-# These two need to remain exported because pkg-config does not see them
-# otherwise. That means they must be unexported at the end of configure.ac to
-# avoid ruining the cache. Sigh.
-export PKG_CONFIG_PATH="${depends_prefix}/share/pkgconfig:${depends_prefix}/lib/pkgconfig"
+PKG_CONFIG_PATH="${depends_prefix}/share/pkgconfig:${depends_prefix}/lib/pkgconfig"
if test -z "@allow_host_packages@"; then
- export PKG_CONFIG_LIBDIR="${depends_prefix}/lib/pkgconfig"
+ PKG_CONFIG_LIBDIR="${depends_prefix}/lib/pkgconfig"
fi
CPPFLAGS="-I${depends_prefix}/include/ ${CPPFLAGS}"
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index 8507e28532..8fcea35d98 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -17,6 +17,7 @@ darwin_native_toolchain=native_cctools
clang_prog=$(build_prefix)/bin/clang
clangxx_prog=$(clang_prog)++
+llvm_config_prog=$(build_prefix)/bin/llvm-config
clang_resource_dir=$(build_prefix)/lib/clang/$(native_clang_version)
else
@@ -34,8 +35,10 @@ darwin_native_toolchain=
# Source: https://lists.gnu.org/archive/html/bug-make/2017-11/msg00017.html
clang_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang")
clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++")
+llvm_config_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-config")
clang_resource_dir=$(shell clang -print-resource-dir)
+llvm_lib_dir=$(shell $(llvm_config_prog) --libdir)
endif
cctools_TOOLS=AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL DSYMUTIL
diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk
index 80c7ce8429..2370c5b759 100644
--- a/depends/packages/bdb.mk
+++ b/depends/packages/bdb.mk
@@ -14,7 +14,7 @@ $(package)_config_opts_freebsd=--with-pic
$(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
$(package)_config_opts_android=--with-pic
-$(package)_cflags+=-Wno-error=implicit-function-declaration
+$(package)_cflags+=-Wno-error=implicit-function-declaration -Wno-error=format-security
$(package)_cppflags_mingw32=-DUNICODE -D_UNICODE
endef
diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk
index fa30e80f5c..036eaf6560 100644
--- a/depends/packages/libxcb.mk
+++ b/depends/packages/libxcb.mk
@@ -4,6 +4,7 @@ $(package)_download_path=https://xcb.freedesktop.org/dist
$(package)_file_name=$(package)-$($(package)_version).tar.xz
$(package)_sha256_hash=a55ed6db98d43469801262d81dc2572ed124edc3db31059d4e9916eb9f844c34
$(package)_dependencies=xcb_proto libXau
+$(package)_patches = remove_pthread_stubs.patch
define $(package)_set_vars
$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen --without-launchd
@@ -20,7 +21,7 @@ endef
define $(package)_preprocess_cmds
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux && \
- sed "s/pthread-stubs//" -i configure
+ patch -p1 -i $($(package)_patch_dir)/remove_pthread_stubs.patch
endef
define $(package)_config_cmds
diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk
index d169eb6723..03e9002ecd 100644
--- a/depends/packages/native_cctools.mk
+++ b/depends/packages/native_cctools.mk
@@ -7,18 +7,24 @@ $(package)_build_subdir=cctools
$(package)_dependencies=native_libtapi
define $(package)_set_vars
- $(package)_config_opts=--target=$(host)
+ $(package)_config_opts=--target=$(host) --enable-lto-support
+ $(package)_config_opts+=--with-llvm-config=$(llvm_config_prog)
$(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib
- ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
- $(package)_config_opts+=--enable-lto-support --with-llvm-config=$(build_prefix)/bin/llvm-config
- endif
$(package)_cc=$(clang_prog)
$(package)_cxx=$(clangxx_prog)
endef
+ifneq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
define $(package)_preprocess_cmds
+ mkdir -p $($(package)_staging_prefix_dir)/lib && \
+ cp $(llvm_lib_dir)/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub cctools
endef
+else
+define $(package)_preprocess_cmds
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub cctools
+endef
+endif
define $(package)_config_cmds
$($(package)_autoconf)
diff --git a/depends/packages/native_clang.mk b/depends/packages/native_clang.mk
index 245269a9d3..f2712294ab 100644
--- a/depends/packages/native_clang.mk
+++ b/depends/packages/native_clang.mk
@@ -16,10 +16,13 @@ endef
define $(package)_stage_cmds
mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include && \
mkdir -p $($(package)_staging_prefix_dir)/bin && \
+ mkdir -p $($(package)_staging_prefix_dir)/include/llvm-c && \
cp bin/clang $($(package)_staging_prefix_dir)/bin/ && \
cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ && \
cp bin/dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil && \
cp bin/llvm-config $($(package)_staging_prefix_dir)/bin/ && \
+ cp include/llvm-c/ExternC.h $($(package)_staging_prefix_dir)/include/llvm-c && \
+ cp include/llvm-c/lto.h $($(package)_staging_prefix_dir)/include/llvm-c && \
cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \
cp -r lib/clang/$($(package)_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include/
endef
diff --git a/depends/packages/native_libtapi.mk b/depends/packages/native_libtapi.mk
index 1633213a42..052bb23689 100644
--- a/depends/packages/native_libtapi.mk
+++ b/depends/packages/native_libtapi.mk
@@ -13,7 +13,5 @@ define $(package)_build_cmds
endef
define $(package)_stage_cmds
- ./install.sh && \
- mkdir -p $($(package)_staging_prefix_dir)/include/llvm-c && \
- cp src/llvm/include/llvm-c/lto.h $($(package)_staging_prefix_dir)/include/llvm-c
+ ./install.sh
endef
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index bddc9b4871..148a18cf53 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -1,9 +1,9 @@
package=qt
-$(package)_version=5.15.3
+$(package)_version=5.15.5
$(package)_download_path=https://download.qt.io/official_releases/qt/5.15/$($(package)_version)/submodules
$(package)_suffix=everywhere-opensource-src-$($(package)_version).tar.xz
$(package)_file_name=qtbase-$($(package)_suffix)
-$(package)_sha256_hash=26394ec9375d52c1592bd7b689b1619c6b8dbe9b6f91fdd5c355589787f3a0b6
+$(package)_sha256_hash=0c42c799aa7c89e479a07c451bf5a301e291266ba789e81afc18f95049524edc
$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm
$(package)_qt_libs=corelib network widgets gui plugins testlib
$(package)_linguist_tools = lrelease lupdate lconvert
@@ -17,17 +17,17 @@ $(package)_patches += fix_montery_include.patch
$(package)_patches += fix_android_jni_static.patch
$(package)_patches += dont_hardcode_pwd.patch
$(package)_patches += qtbase-moc-ignore-gcc-macro.patch
-$(package)_patches += fix_limits_header.patch
$(package)_patches += use_android_ndk23.patch
$(package)_patches += rcc_hardcode_timestamp.patch
$(package)_patches += duplicate_lcqpafonts.patch
$(package)_patches += fast_fixed_dtoa_no_optimize.patch
+$(package)_patches += guix_cross_lib_path.patch
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
-$(package)_qttranslations_sha256_hash=5d7869f670a135ad0986e266813b9dd5bbae2b09577338f9cdf8904d4af52db0
+$(package)_qttranslations_sha256_hash=c92af4171397a0ed272330b4fa0669790fcac8d050b07c8b8cc565ebeba6735e
$(package)_qttools_file_name=qttools-$($(package)_suffix)
-$(package)_qttools_sha256_hash=463b2fe71a085e7ab4e39333ae360ab0ec857b966d7a08f752c427e5df55f90d
+$(package)_qttools_sha256_hash=6d0778b71b2742cb527561791d1d3d255366163d54a10f78c683a398f09ffc6c
$(package)_extra_sources = $($(package)_qttranslations_file_name)
$(package)_extra_sources += $($(package)_qttools_file_name)
@@ -248,12 +248,12 @@ define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \
patch -p1 -i $($(package)_patch_dir)/dont_hardcode_x86_64.patch && \
patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_limits_header.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_montery_include.patch && \
patch -p1 -i $($(package)_patch_dir)/use_android_ndk23.patch && \
patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch && \
patch -p1 -i $($(package)_patch_dir)/duplicate_lcqpafonts.patch && \
patch -p1 -i $($(package)_patch_dir)/fast_fixed_dtoa_no_optimize.patch && \
+ patch -p1 -i $($(package)_patch_dir)/guix_cross_lib_path.patch && \
mkdir -p qtbase/mkspecs/macx-clang-linux &&\
cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\
cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \
@@ -263,8 +263,7 @@ define $(package)_preprocess_cmds
echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
sed -i.old "s|QMAKE_CC = \$$$$\$$$${CROSS_COMPILE}clang|QMAKE_CC = $($(package)_cc)|" qtbase/mkspecs/common/clang.conf && \
- sed -i.old "s|QMAKE_CXX = \$$$$\$$$${CROSS_COMPILE}clang++|QMAKE_CXX = $($(package)_cxx)|" qtbase/mkspecs/common/clang.conf && \
- sed -i.old "s/LIBRARY_PATH/(CROSS_)?\0/g" qtbase/mkspecs/features/toolchain.prf
+ sed -i.old "s|QMAKE_CXX = \$$$$\$$$${CROSS_COMPILE}clang++|QMAKE_CXX = $($(package)_cxx)|" qtbase/mkspecs/common/clang.conf
endef
define $(package)_config_cmds
diff --git a/depends/patches/libxcb/remove_pthread_stubs.patch b/depends/patches/libxcb/remove_pthread_stubs.patch
new file mode 100644
index 0000000000..1f32dea527
--- /dev/null
+++ b/depends/patches/libxcb/remove_pthread_stubs.patch
@@ -0,0 +1,12 @@
+Remove uneeded pthread-stubs dependency
+--- a/configure
++++ b/configure
+@@ -19695,7 +19695,7 @@ fi
+ NEEDED="xau >= 0.99.2"
+ case $host_os in
+ linux*) ;;
+- *) NEEDED="$NEEDED pthread-stubs" ;;
++ *) NEEDED="$NEEDED" ;;
+ esac
+
+ pkg_failed=no
diff --git a/depends/patches/qt/dont_hardcode_x86_64.patch b/depends/patches/qt/dont_hardcode_x86_64.patch
index 5c1e030fa4..a66426877a 100644
--- a/depends/patches/qt/dont_hardcode_x86_64.patch
+++ b/depends/patches/qt/dont_hardcode_x86_64.patch
@@ -73,7 +73,7 @@ diff --git a/mkspecs/features/mac/default_post.prf b/mkspecs/features/mac/defaul
index 92a9112bca6..d888731ec8d 100644
--- old/qtbase/mkspecs/features/mac/default_post.prf
+++ new/qtbase/mkspecs/features/mac/default_post.prf
-@@ -90,6 +90,11 @@ app_extension_api_only {
+@@ -95,6 +95,11 @@ app_extension_api_only {
QMAKE_LFLAGS += $$QMAKE_CFLAGS_APPLICATION_EXTENSION
}
@@ -85,7 +85,7 @@ index 92a9112bca6..d888731ec8d 100644
macx-xcode {
qmake_pkginfo_typeinfo.name = QMAKE_PKGINFO_TYPEINFO
!isEmpty(QMAKE_PKGINFO_TYPEINFO): \
-@@ -145,9 +150,6 @@ macx-xcode {
+@@ -150,9 +155,6 @@ macx-xcode {
simulator: VALID_SIMULATOR_ARCHS = $$QMAKE_APPLE_SIMULATOR_ARCHS
VALID_ARCHS = $$VALID_DEVICE_ARCHS $$VALID_SIMULATOR_ARCHS
diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch
index 22a4d5ab0e..936b82e152 100644
--- a/depends/patches/qt/fix_android_jni_static.patch
+++ b/depends/patches/qt/fix_android_jni_static.patch
@@ -1,6 +1,6 @@
--- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp
+++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp
-@@ -934,6 +934,14 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
+@@ -943,6 +943,14 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
diff --git a/depends/patches/qt/fix_limits_header.patch b/depends/patches/qt/fix_limits_header.patch
deleted file mode 100644
index 258128c0ca..0000000000
--- a/depends/patches/qt/fix_limits_header.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-Fix compiling with GCC 11
-
-Upstream:
- - bug report: https://bugreports.qt.io/browse/QTBUG-89977
- - fix in Qt 6.1: 813a928c7c3cf98670b6043149880ed5c955efb9
-
---- old/qtbase/src/corelib/text/qbytearraymatcher.h
-+++ new/qtbase/src/corelib/text/qbytearraymatcher.h
-@@ -42,6 +42,8 @@
-
- #include <QtCore/qbytearray.h>
-
-+#include <limits>
-+
- QT_BEGIN_NAMESPACE
-
-
-
-Upstream fix and backports:
- - Qt 6.1: 3eab20ad382569cb2c9e6ccec2322c3d08c0f716
- - Qt 6.2: 380294a5971da85010a708dc23b0edec192cbf27
- - Qt 6.3: 2b2b3155d9f6ba1e4f859741468fbc47db09292b
-
---- old/qtbase/src/corelib/tools/qoffsetstringarray_p.h
-+++ new/qtbase/src/corelib/tools/qoffsetstringarray_p.h
-@@ -55,6 +55,7 @@
-
- #include <tuple>
- #include <array>
-+#include <limits>
-
- QT_BEGIN_NAMESPACE
-
diff --git a/depends/patches/qt/guix_cross_lib_path.patch b/depends/patches/qt/guix_cross_lib_path.patch
new file mode 100644
index 0000000000..0c67743dc1
--- /dev/null
+++ b/depends/patches/qt/guix_cross_lib_path.patch
@@ -0,0 +1,17 @@
+Facilitate guix building with CROSS_LIBRARY_PATH
+
+See discussion in https://github.com/bitcoin/bitcoin/pull/15277.
+
+--- a/qtbase/mkspecs/features/toolchain.prf
++++ b/qtbase/mkspecs/features/toolchain.prf
+@@ -231,8 +231,8 @@ isEmpty($${target_prefix}.INCDIRS) {
+ add_libraries = false
+ for (line, output) {
+ line ~= s/^[ \\t]*// # remove leading spaces
+- contains(line, "LIBRARY_PATH=.*") {
+- line ~= s/^LIBRARY_PATH=// # remove leading LIBRARY_PATH=
++ contains(line, "(CROSS_)?LIBRARY_PATH=.*") {
++ line ~= s/^(CROSS_)?LIBRARY_PATH=// # remove leading (CROSS_)?LIBRARY_PATH=
+ equals(QMAKE_HOST.os, Windows): \
+ paths = $$split(line, ;)
+ else: \
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 697d432520..8b8259ab0a 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -30,7 +30,7 @@ You can find installation instructions in the `build-*.md` file for your platfor
| [Fontconfig](../depends/packages/fontconfig.mk) | [link](https://www.freedesktop.org/wiki/Software/fontconfig/) | [2.12.6](https://github.com/bitcoin/bitcoin/pull/23495) | 2.6 | Yes |
| [FreeType](../depends/packages/freetype.mk) | [link](https://freetype.org) | [2.11.0](https://github.com/bitcoin/bitcoin/commit/01544dd78ccc0b0474571da854e27adef97137fb) | 2.3.0 | Yes |
| [qrencode](../depends/packages/qrencode.mk) | [link](https://fukuchi.org/works/qrencode/) | [3.4.4](https://github.com/bitcoin/bitcoin/pull/6373) | | No |
-| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.3](https://github.com/bitcoin/bitcoin/pull/24668) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
+| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.5](https://github.com/bitcoin/bitcoin/pull/25719) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
### Networking
| Dependency | Releases | Version used | Minimum required | Runtime |
diff --git a/doc/policy/README.md b/doc/policy/README.md
index 6e8686365d..27536407e7 100644
--- a/doc/policy/README.md
+++ b/doc/policy/README.md
@@ -3,7 +3,7 @@
**Policy** (Mempool or Transaction Relay Policy) is the node's set of validation rules, in addition
to consensus, enforced for unconfirmed transactions before submitting them to the mempool. These
rules are local to the node and configurable (e.g. `-minrelaytxfee`, `-limitancestorsize`,
-`-incrementalRelayFee`). Policy may include restrictions on the transaction itself, the transaction
+`-incrementalrelayfee`). Policy may include restrictions on the transaction itself, the transaction
in relation to the current chain tip, and the transaction in relation to the node's mempool
contents. Policy is *not* applied to transactions in blocks.
diff --git a/doc/policy/mempool-replacements.md b/doc/policy/mempool-replacements.md
index 430a96f228..b3c4239b73 100644
--- a/doc/policy/mempool-replacements.md
+++ b/doc/policy/mempool-replacements.md
@@ -71,7 +71,7 @@ This set of rules is similar but distinct from BIP125.
Bitcoin Core implementation.
* The incremental relay feerate used to calculate the required additional fees is distinct from
- `minRelayTxFee` and configurable using `-incrementalrelayfee`
+ `-minrelaytxfee` and configurable using `-incrementalrelayfee`
([PR #9380](https://github.com/bitcoin/bitcoin/pull/9380)).
* RBF enabled by default in the wallet GUI as of **v0.18.1** ([PR
diff --git a/doc/policy/packages.md b/doc/policy/packages.md
index f2a3d6517e..03c26da86b 100644
--- a/doc/policy/packages.md
+++ b/doc/policy/packages.md
@@ -81,7 +81,7 @@ If any transactions in the package are already in the mempool, they are not subm
("deduplicated") and are thus excluded from this calculation.
To meet the two feerate requirements of a mempool, i.e., the pre-configured minimum relay feerate
-(`minRelayTxFee`) and the dynamic mempool minimum feerate, the total package feerate is used instead
+(`-minrelaytxfee`) and the dynamic mempool minimum feerate, the total package feerate is used instead
of the individual feerate. The individual transactions are allowed to be below the feerate
requirements if the package meets the feerate requirements. For example, the parent(s) in the
package can pay no fees but be paid for by the child.
diff --git a/doc/release-notes-25610.md b/doc/release-notes-25610.md
new file mode 100644
index 0000000000..743a7709bf
--- /dev/null
+++ b/doc/release-notes-25610.md
@@ -0,0 +1,12 @@
+Wallet
+------
+
+- The `-walletrbf` startup option will now default to `true`. The
+ wallet will now default to opt-in RBF on transactions that it creates.
+
+Updated RPCs
+------------
+
+- The `replaceable` option for the `createrawtransaction` and
+ `createpsbt` RPCs will now default to `true`. Transactions created
+ with these RPCs will default to having opt-in RBF enabled.
diff --git a/src/Makefile.am b/src/Makefile.am
index 23bc180095..576a448a0d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -139,7 +139,6 @@ BITCOIN_CORE_H = \
compat/cpuid.h \
compat/endian.h \
compressor.h \
- node/connection_types.h \
consensus/consensus.h \
consensus/tx_check.h \
consensus/tx_verify.h \
@@ -149,7 +148,6 @@ BITCOIN_CORE_H = \
dbwrapper.h \
deploymentinfo.h \
deploymentstatus.h \
- node/eviction.h \
external_signer.h \
flatfile.h \
fs.h \
@@ -179,12 +177,12 @@ BITCOIN_CORE_H = \
kernel/mempool_limits.h \
kernel/mempool_options.h \
kernel/mempool_persist.h \
+ kernel/validation_cache_sizes.h \
key.h \
key_io.h \
logging.h \
logging/timer.h \
mapport.h \
- mempool_args.h \
memusage.h \
merkleblock.h \
net.h \
@@ -199,14 +197,18 @@ BITCOIN_CORE_H = \
node/caches.h \
node/chainstate.h \
node/coin.h \
+ node/connection_types.h \
node/context.h \
+ node/eviction.h \
+ node/interface_ui.h \
+ node/mempool_args.h \
node/mempool_persist_args.h \
node/miner.h \
node/minisketchwrapper.h \
node/psbt.h \
node/transaction.h \
- node/interface_ui.h \
node/utxo_snapshot.h \
+ node/validation_cache_args.h \
noui.h \
outputtype.h \
policy/feerate.h \
@@ -372,10 +374,9 @@ libbitcoin_node_a_SOURCES = \
kernel/context.cpp \
kernel/mempool_persist.cpp \
mapport.cpp \
- mempool_args.cpp \
net.cpp \
- netgroup.cpp \
net_processing.cpp \
+ netgroup.cpp \
node/blockstorage.cpp \
node/caches.cpp \
node/chainstate.cpp \
@@ -383,13 +384,15 @@ libbitcoin_node_a_SOURCES = \
node/connection_types.cpp \
node/context.cpp \
node/eviction.cpp \
+ node/interface_ui.cpp \
node/interfaces.cpp \
+ node/mempool_args.cpp \
node/mempool_persist_args.cpp \
node/miner.cpp \
node/minisketchwrapper.cpp \
node/psbt.cpp \
node/transaction.cpp \
- node/interface_ui.cpp \
+ node/validation_cache_args.cpp \
noui.cpp \
policy/fees.cpp \
policy/fees_args.cpp \
@@ -402,8 +405,8 @@ libbitcoin_node_a_SOURCES = \
rpc/fees.cpp \
rpc/mempool.cpp \
rpc/mining.cpp \
- rpc/node.cpp \
rpc/net.cpp \
+ rpc/node.cpp \
rpc/output_script.cpp \
rpc/rawtransaction.cpp \
rpc/server.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index f52964b033..9ed5731af1 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -119,6 +119,7 @@ BITCOIN_TESTS =\
test/random_tests.cpp \
test/rbf_tests.cpp \
test/rest_tests.cpp \
+ test/result_tests.cpp \
test/reverselock_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 857ad73b2f..f16ff2230b 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -14,10 +14,10 @@
#include <random.h>
#include <serialize.h>
#include <streams.h>
-#include <timedata.h>
#include <tinyformat.h>
#include <uint256.h>
#include <util/check.h>
+#include <util/time.h>
#include <cmath>
#include <optional>
@@ -560,7 +560,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::c
if (pinfo) {
// periodically update nTime
- const bool currently_online{AdjustedTime() - addr.nTime < 24h};
+ const bool currently_online{NodeClock::now() - addr.nTime < 24h};
const auto update_interval{currently_online ? 1h : 24h};
if (pinfo->nTime < addr.nTime - update_interval - time_penalty) {
pinfo->nTime = std::max(NodeSeconds{0s}, addr.nTime - time_penalty);
@@ -788,7 +788,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
}
// gather a list of random nodes, skipping those of low quality
- const auto now{AdjustedTime()};
+ const auto now{Now<NodeSeconds>()};
std::vector<CAddress> addresses;
for (unsigned int n = 0; n < vRandom.size(); n++) {
if (addresses.size() >= nNodes)
@@ -874,7 +874,7 @@ void AddrManImpl::ResolveCollisions_()
int id_old = vvTried[tried_bucket][tried_bucket_pos];
AddrInfo& info_old = mapInfo[id_old];
- const auto current_time{AdjustedTime()};
+ const auto current_time{Now<NodeSeconds>()};
// Has successfully connected in last X hours
if (current_time - info_old.m_last_success < ADDRMAN_REPLACEMENT) {
@@ -898,7 +898,7 @@ void AddrManImpl::ResolveCollisions_()
erase_collision = true;
}
} else { // Collision is not actually a collision anymore
- Good_(info_new, false, AdjustedTime());
+ Good_(info_new, false, Now<NodeSeconds>());
erase_collision = true;
}
}
diff --git a/src/addrman.h b/src/addrman.h
index b70c6a48ad..5099c8c7a3 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -10,7 +10,6 @@
#include <netgroup.h>
#include <protocol.h>
#include <streams.h>
-#include <timedata.h>
#include <util/time.h>
#include <cstdint>
@@ -121,10 +120,10 @@ public:
* @param[in] time The time that we were last connected to this peer.
* @return true if the address is successfully moved from the new table to the tried table.
*/
- bool Good(const CService& addr, NodeSeconds time = AdjustedTime());
+ bool Good(const CService& addr, NodeSeconds time = Now<NodeSeconds>());
//! Mark an entry as connection attempted to.
- void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time = AdjustedTime());
+ void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time = Now<NodeSeconds>());
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
void ResolveCollisions();
@@ -169,7 +168,7 @@ public:
* @param[in] addr The address of the peer we were connected to
* @param[in] time The time that we were last connected to this peer
*/
- void Connected(const CService& addr, NodeSeconds time = AdjustedTime());
+ void Connected(const CService& addr, NodeSeconds time = Now<NodeSeconds>());
//! Update an entry's service bits.
void SetServices(const CService& addr, ServiceFlags nServices);
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index a73a026940..376e79f49f 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -93,10 +93,10 @@ public:
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
- bool IsTerrible(NodeSeconds now = AdjustedTime()) const;
+ bool IsTerrible(NodeSeconds now = Now<NodeSeconds>()) const;
//! Calculate the relative chance this entry should be given when selecting nodes to connect to
- double GetChance(NodeSeconds now = AdjustedTime()) const;
+ double GetChance(NodeSeconds now = Now<NodeSeconds>()) const;
};
class AddrManImpl
diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp
index 2600b03022..f14d1f89b6 100644
--- a/src/bench/addrman.cpp
+++ b/src/bench/addrman.cpp
@@ -43,7 +43,7 @@ static void CreateAddresses()
CAddress ret(CService(addr, port), NODE_NETWORK);
- ret.nTime = AdjustedTime();
+ ret.nTime = Now<NodeSeconds>();
return ret;
};
diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp
index a10f7ff7d1..27e4dd015d 100644
--- a/src/bench/wallet_loading.cpp
+++ b/src/bench/wallet_loading.cpp
@@ -45,11 +45,8 @@ static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet)
static void AddTx(CWallet& wallet)
{
- const auto& dest = wallet.GetNewDestination(OutputType::BECH32, "");
- assert(dest.HasRes());
-
CMutableTransaction mtx;
- mtx.vout.push_back({COIN, GetScriptForDestination(dest.GetObj())});
+ mtx.vout.push_back({COIN, GetScriptForDestination(*Assert(wallet.GetNewDestination(OutputType::BECH32, "")))});
mtx.vin.push_back(CTxIn());
wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInactive{});
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index 4656cb23e7..fc3f91d492 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -13,6 +13,7 @@
#include <kernel/checks.h>
#include <kernel/context.h>
+#include <kernel/validation_cache_sizes.h>
#include <chainparams.h>
#include <consensus/validation.h>
@@ -62,8 +63,9 @@ int main(int argc, char* argv[])
// Necessary for CheckInputScripts (eventually called by ProcessNewBlock),
// which will try the script cache first and fall back to actually
// performing the check with the signature cache.
- InitSignatureCache();
- InitScriptExecutionCache();
+ kernel::ValidationCacheSizes validation_cache_sizes{};
+ Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
+ Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
// SETUP: Scheduling and Background Signals
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 7cc956ebda..6ce4e05e4d 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -807,7 +807,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
if (failedToGetAuthCookie) {
throw std::runtime_error(strprintf(
"Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
- fs::PathToString(GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)))));
+ fs::PathToString(GetConfigFile(gArgs.GetPathArg("-conf", BITCOIN_CONF_FILENAME)))));
} else {
throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
}
diff --git a/src/chain.cpp b/src/chain.cpp
index 0f898bafd5..446bb216c2 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -18,11 +18,9 @@ std::string CBlockIndex::ToString() const
pprev, nHeight, hashMerkleRoot.ToString(), GetBlockHash().ToString());
}
-void CChain::SetTip(CBlockIndex *pindex) {
- if (pindex == nullptr) {
- vChain.clear();
- return;
- }
+void CChain::SetTip(CBlockIndex& block)
+{
+ CBlockIndex* pindex = &block;
vChain.resize(pindex->nHeight + 1);
while (pindex && vChain[pindex->nHeight] != pindex) {
vChain[pindex->nHeight] = pindex;
diff --git a/src/chain.h b/src/chain.h
index 627a3dfab2..1c5cd3f1f6 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -465,7 +465,7 @@ public:
}
/** Set/initialize a chain with a given tip. */
- void SetTip(CBlockIndex* pindex);
+ void SetTip(CBlockIndex& block);
/** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
CBlockLocator GetLocator(const CBlockIndex* pindex = nullptr) const;
diff --git a/src/coins.cpp b/src/coins.cpp
index 1abdcb54d2..1753d33b71 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -99,9 +99,9 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
TRACE5(utxocache, add,
outpoint.hash.data(),
(uint32_t)outpoint.n,
- (uint32_t)coin.nHeight,
- (int64_t)coin.out.nValue,
- (bool)coin.IsCoinBase());
+ (uint32_t)it->second.coin.nHeight,
+ (int64_t)it->second.coin.out.nValue,
+ (bool)it->second.coin.IsCoinBase());
}
void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin) {
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index d0dc61c7e6..61f553806e 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -12,7 +12,9 @@
#include <atomic>
#include <cmath>
#include <cstring>
+#include <limits>
#include <memory>
+#include <optional>
#include <utility>
#include <vector>
@@ -326,7 +328,7 @@ public:
}
/** setup initializes the container to store no more than new_size
- * elements.
+ * elements and no less than 2 elements.
*
* setup should only be called once.
*
@@ -336,8 +338,8 @@ public:
uint32_t setup(uint32_t new_size)
{
// depth_limit must be at least one otherwise errors can occur.
- depth_limit = static_cast<uint8_t>(std::log2(static_cast<float>(std::max((uint32_t)2, new_size))));
size = std::max<uint32_t>(2, new_size);
+ depth_limit = static_cast<uint8_t>(std::log2(static_cast<float>(size)));
table.resize(size);
collection_flags.setup(size);
epoch_flags.resize(size);
@@ -357,12 +359,21 @@ public:
*
* @param bytes the approximate number of bytes to use for this data
* structure
- * @returns the maximum number of elements storable (see setup()
- * documentation for more detail)
+ * @returns A pair of the maximum number of elements storable (see setup()
+ * documentation for more detail) and the approxmiate total size of these
+ * elements in bytes or std::nullopt if the size requested is too large.
*/
- uint32_t setup_bytes(size_t bytes)
+ std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t bytes)
{
- return setup(bytes/sizeof(Element));
+ size_t requested_num_elems = bytes / sizeof(Element);
+ if (std::numeric_limits<uint32_t>::max() < requested_num_elems) {
+ return std::nullopt;
+ }
+
+ auto num_elems = setup(bytes/sizeof(Element));
+
+ size_t approx_size_bytes = num_elems * sizeof(Element);
+ return std::make_pair(num_elems, approx_size_bytes);
}
/** insert loops at most depth_limit times trying to insert a hash
diff --git a/src/init.cpp b/src/init.cpp
index a94bbe6460..4606b77e9f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -11,6 +11,7 @@
#include <kernel/checks.h>
#include <kernel/mempool_persist.h>
+#include <kernel/validation_cache_sizes.h>
#include <addrman.h>
#include <banman.h>
@@ -31,7 +32,6 @@
#include <interfaces/init.h>
#include <interfaces/node.h>
#include <mapport.h>
-#include <mempool_args.h>
#include <net.h>
#include <net_permissions.h>
#include <net_processing.h>
@@ -42,8 +42,10 @@
#include <node/chainstate.h>
#include <node/context.h>
#include <node/interface_ui.h>
+#include <node/mempool_args.h>
#include <node/mempool_persist_args.h>
#include <node/miner.h>
+#include <node/validation_cache_args.h>
#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/fees_args.h>
@@ -105,7 +107,9 @@
#endif
using kernel::DumpMempool;
+using kernel::ValidationCacheSizes;
+using node::ApplyArgsManOptions;
using node::CacheSizes;
using node::CalculateCacheSizes;
using node::DEFAULT_PERSIST_MEMPOOL;
@@ -548,7 +552,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-addrmantest", "Allows to test address relay on localhost", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
- argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
+ argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in " + CURRENCY_UNIT + "/kvB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
@@ -935,16 +939,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex());
}
- // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
- // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
- if (args.IsArgSet("-incrementalrelayfee")) {
- if (std::optional<CAmount> inc_relay_fee = ParseMoney(args.GetArg("-incrementalrelayfee", ""))) {
- ::incrementalRelayFee = CFeeRate{inc_relay_fee.value()};
- } else {
- return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", "")));
- }
- }
-
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
int64_t nPruneArg = args.GetIntArg("-prune", 0);
if (nPruneArg < 0) {
@@ -973,19 +967,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
return InitError(Untranslated("peertimeout must be a positive integer."));
}
- if (args.IsArgSet("-minrelaytxfee")) {
- if (std::optional<CAmount> min_relay_fee = ParseMoney(args.GetArg("-minrelaytxfee", ""))) {
- // High fee check is done afterward in CWallet::Create()
- ::minRelayTxFee = CFeeRate{min_relay_fee.value()};
- } else {
- return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", "")));
- }
- } else if (incrementalRelayFee > ::minRelayTxFee) {
- // Allow only setting incrementalRelayFee to control both
- ::minRelayTxFee = incrementalRelayFee;
- LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString());
- }
-
// Sanity check argument for min fee for including tx in block
// TODO: Harmonize which arguments need sanity checking and where that happens
if (args.IsArgSet("-blockmintxfee")) {
@@ -994,28 +975,10 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
}
}
- // Feerate used to define dust. Shouldn't be changed lightly as old
- // implementations may inadvertently create non-standard transactions
- if (args.IsArgSet("-dustrelayfee")) {
- if (std::optional<CAmount> parsed = ParseMoney(args.GetArg("-dustrelayfee", ""))) {
- dustRelayFee = CFeeRate{parsed.value()};
- } else {
- return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", "")));
- }
- }
-
- fRequireStandard = !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
- if (!chainparams.IsTestChain() && !fRequireStandard) {
- return InitError(strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString()));
- }
nBytesPerSigOp = args.GetIntArg("-bytespersigop", nBytesPerSigOp);
if (!g_wallet_init_interface.ParameterInteraction()) return false;
- fIsBareMultisigStd = args.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
- fAcceptDatacarrier = args.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
- nMaxDatacarrierBytes = args.GetIntArg("-datacarriersize", nMaxDatacarrierBytes);
-
// Option to startup with mocktime set (used for regression testing):
SetMockTime(args.GetIntArg("-mocktime", 0)); // SetMockTime(0) is a no-op
@@ -1156,8 +1119,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
}
- InitSignatureCache();
- InitScriptExecutionCache();
+ ValidationCacheSizes validation_cache_sizes{};
+ ApplyArgsManOptions(args, validation_cache_sizes);
+ if (!InitSignatureCache(validation_cache_sizes.signature_cache_bytes)
+ || !InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes))
+ {
+ return InitError(strprintf(_("Unable to allocate memory for -maxsigcachesize: '%s' MiB"), args.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_BYTES >> 20)));
+ }
int script_threads = args.GetIntArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (script_threads <= 0) {
@@ -1418,7 +1386,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
.estimator = node.fee_estimator.get(),
.check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0,
};
- ApplyArgsManOptions(args, mempool_opts);
+ if (const auto err{ApplyArgsManOptions(args, chainparams, mempool_opts)}) {
+ return InitError(*err);
+ }
mempool_opts.check_ratio = std::clamp<int>(mempool_opts.check_ratio, 0, 1'000'000);
int64_t descendant_limit_bytes = mempool_opts.limits.descendant_size_vbytes * 40;
diff --git a/src/init/common.cpp b/src/init/common.cpp
index a0cdf44f47..bdd7f16307 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -99,7 +99,7 @@ bool StartLogging(const ArgsManager& args)
LogPrintf("Using data directory %s\n", fs::PathToString(gArgs.GetDataDirNet()));
// Only log conf file usage message if conf file actually exists.
- fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME));
+ fs::path config_file_path = GetConfigFile(args.GetPathArg("-conf", BITCOIN_CONF_FILENAME));
if (fs::exists(config_file_path)) {
LogPrintf("Config file: %s\n", fs::PathToString(config_file_path));
} else if (args.IsArgSet("-conf")) {
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 4ab416f451..63603c7f7b 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -88,7 +88,7 @@ public:
virtual std::string getWalletName() = 0;
// Get a new address.
- virtual BResult<CTxDestination> getNewDestination(const OutputType type, const std::string label) = 0;
+ virtual util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string label) = 0;
//! Get public key.
virtual bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) = 0;
@@ -139,7 +139,7 @@ public:
virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0;
//! Create transaction.
- virtual BResult<CTransactionRef> createTransaction(const std::vector<wallet::CRecipient>& recipients,
+ virtual util::Result<CTransactionRef> createTransaction(const std::vector<wallet::CRecipient>& recipients,
const wallet::CCoinControl& coin_control,
bool sign,
int& change_pos,
@@ -329,7 +329,7 @@ public:
virtual std::string getWalletDir() = 0;
//! Restore backup wallet
- virtual BResult<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0;
+ virtual util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0;
//! Return available wallets in wallet directory.
virtual std::vector<std::string> listWalletDir() = 0;
diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h
index 07953b443b..dad6f14c39 100644
--- a/src/kernel/mempool_options.h
+++ b/src/kernel/mempool_options.h
@@ -6,8 +6,13 @@
#include <kernel/mempool_limits.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <script/standard.h>
+
#include <chrono>
#include <cstdint>
+#include <optional>
class CBlockPolicyEstimator;
@@ -33,6 +38,20 @@ struct MemPoolOptions {
int check_ratio{0};
int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000};
std::chrono::seconds expiry{std::chrono::hours{DEFAULT_MEMPOOL_EXPIRY_HOURS}};
+ CFeeRate incremental_relay_feerate{DEFAULT_INCREMENTAL_RELAY_FEE};
+ /** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
+ CFeeRate min_relay_feerate{DEFAULT_MIN_RELAY_TX_FEE};
+ CFeeRate dust_relay_feerate{DUST_RELAY_TX_FEE};
+ /**
+ * A data carrying output is an unspendable output containing data. The script
+ * type is designated as TxoutType::NULL_DATA.
+ *
+ * Maximum size of TxoutType::NULL_DATA scripts that this node considers standard.
+ * If nullopt, any size is nonstandard.
+ */
+ std::optional<unsigned> max_datacarrier_bytes{DEFAULT_ACCEPT_DATACARRIER ? std::optional{MAX_OP_RETURN_RELAY} : std::nullopt};
+ bool permit_bare_multisig{DEFAULT_PERMIT_BAREMULTISIG};
+ bool require_standard{true};
bool full_rbf{DEFAULT_MEMPOOL_FULL_RBF};
MemPoolLimits limits{};
};
diff --git a/src/kernel/validation_cache_sizes.h b/src/kernel/validation_cache_sizes.h
new file mode 100644
index 0000000000..72e4d1a52c
--- /dev/null
+++ b/src/kernel/validation_cache_sizes.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H
+#define BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H
+
+#include <script/sigcache.h>
+
+#include <cstddef>
+#include <limits>
+
+namespace kernel {
+struct ValidationCacheSizes {
+ size_t signature_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
+ size_t script_execution_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
+};
+}
+
+#endif // BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H
diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc
index 18626b327c..fac41be6ce 100644
--- a/src/leveldb/util/env_posix.cc
+++ b/src/leveldb/util/env_posix.cc
@@ -49,7 +49,7 @@ constexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 4096 : 0;
int g_mmap_limit = kDefaultMmapLimit;
// Common flags defined for all posix open operations
-#if defined(HAVE_O_CLOEXEC)
+#if HAVE_O_CLOEXEC
constexpr const int kOpenBaseFlags = O_CLOEXEC;
#else
constexpr const int kOpenBaseFlags = 0;
diff --git a/src/mempool_args.cpp b/src/mempool_args.cpp
deleted file mode 100644
index 77caa127e9..0000000000
--- a/src/mempool_args.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2022 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <mempool_args.h>
-
-#include <kernel/mempool_limits.h>
-#include <kernel/mempool_options.h>
-
-#include <util/system.h>
-
-using kernel::MemPoolLimits;
-using kernel::MemPoolOptions;
-
-namespace {
-void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolLimits& mempool_limits)
-{
- mempool_limits.ancestor_count = argsman.GetIntArg("-limitancestorcount", mempool_limits.ancestor_count);
-
- if (auto vkb = argsman.GetIntArg("-limitancestorsize")) mempool_limits.ancestor_size_vbytes = *vkb * 1'000;
-
- mempool_limits.descendant_count = argsman.GetIntArg("-limitdescendantcount", mempool_limits.descendant_count);
-
- if (auto vkb = argsman.GetIntArg("-limitdescendantsize")) mempool_limits.descendant_size_vbytes = *vkb * 1'000;
-}
-}
-
-void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolOptions& mempool_opts)
-{
- mempool_opts.check_ratio = argsman.GetIntArg("-checkmempool", mempool_opts.check_ratio);
-
- if (auto mb = argsman.GetIntArg("-maxmempool")) mempool_opts.max_size_bytes = *mb * 1'000'000;
-
- if (auto hours = argsman.GetIntArg("-mempoolexpiry")) mempool_opts.expiry = std::chrono::hours{*hours};
-
- mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf);
-
- ApplyArgsManOptions(argsman, mempool_opts.limits);
-}
diff --git a/src/net.cpp b/src/net.cpp
index c4aaac4986..e87ac079b5 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -454,7 +454,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying connection %s lastseen=%.1fhrs\n",
pszDest ? pszDest : addrConnect.ToString(),
- Ticks<HoursDouble>(pszDest ? 0h : AdjustedTime() - addrConnect.nTime));
+ Ticks<HoursDouble>(pszDest ? 0h : Now<NodeSeconds>() - addrConnect.nTime));
// Resolve
const uint16_t default_port{pszDest != nullptr ? Params().GetDefaultPort(pszDest) :
@@ -1735,7 +1735,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
addrman.ResolveCollisions();
- const auto nANow{AdjustedTime()};
+ const auto current_time{NodeClock::now()};
int nTries = 0;
while (!interruptNet)
{
@@ -1798,7 +1798,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
continue;
// only consider very recently tried nodes after 30 failed attempts
- if (nANow - addr_last_try < 10min && nTries < 30) {
+ if (current_time - addr_last_try < 10min && nTries < 30) {
continue;
}
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 0e10fa5f9d..64c2a29245 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2930,7 +2930,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// indicate to the peer that we will participate in addr relay.
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
{
- CAddress addr{GetLocalAddress(pfrom.addr), peer->m_our_services, AdjustedTime()};
+ CAddress addr{GetLocalAddress(pfrom.addr), peer->m_our_services, Now<NodeSeconds>()};
FastRandomContext insecure_rand;
if (addr.IsRoutable())
{
@@ -3135,7 +3135,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Store the new addresses
std::vector<CAddress> vAddrOk;
- const auto current_a_time{AdjustedTime()};
+ const auto current_a_time{Now<NodeSeconds>()};
// Update/increment addr rate limiting bucket.
const auto current_time{GetTime<std::chrono::microseconds>()};
@@ -4683,7 +4683,7 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
peer.m_addr_known->reset();
}
if (std::optional<CService> local_service = GetLocalAddrForPeer(node)) {
- CAddress local_addr{*local_service, peer.m_our_services, AdjustedTime()};
+ CAddress local_addr{*local_service, peer.m_our_services, Now<NodeSeconds>()};
FastRandomContext insecure_rand;
PushAddress(peer, local_addr, insecure_rand);
}
@@ -4759,8 +4759,8 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::mi
}
if (current_time > peer.m_next_send_feefilter) {
CAmount filterToSend = g_filter_rounder.round(currentFilter);
- // We always have a fee filter of at least minRelayTxFee
- filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
+ // We always have a fee filter of at least the min relay fee
+ filterToSend = std::max(filterToSend, m_mempool.m_min_relay_feerate.GetFeePerK());
if (filterToSend != peer.m_fee_filter_sent) {
m_connman.PushMessage(&pto, CNetMsgMaker(pto.GetCommonVersion()).Make(NetMsgType::FEEFILTER, filterToSend));
peer.m_fee_filter_sent = filterToSend;
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 46d45377fa..2c845d0127 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -66,6 +66,8 @@ using interfaces::Node;
using interfaces::WalletLoader;
namespace node {
+// All members of the classes in this namespace are intentionally public, as the
+// classes themselves are private.
namespace {
#ifdef ENABLE_EXTERNAL_SIGNER
class ExternalSignerImpl : public interfaces::ExternalSigner
@@ -73,15 +75,12 @@ class ExternalSignerImpl : public interfaces::ExternalSigner
public:
ExternalSignerImpl(::ExternalSigner signer) : m_signer(std::move(signer)) {}
std::string getName() override { return m_signer.m_name; }
-private:
::ExternalSigner m_signer;
};
#endif
class NodeImpl : public Node
{
-private:
- ChainstateManager& chainman() { return *Assert(m_context->chainman); }
public:
explicit NodeImpl(NodeContext& context) { setContext(&context); }
void initLogging() override { InitLogging(*Assert(m_context->args)); }
@@ -288,12 +287,7 @@ public:
}
double getVerificationProgress() override
{
- const CBlockIndex* tip;
- {
- LOCK(::cs_main);
- tip = chainman().ActiveChain().Tip();
- }
- return GuessVerificationProgress(chainman().GetParams().TxData(), tip);
+ return GuessVerificationProgress(chainman().GetParams().TxData(), WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()));
}
bool isInitialBlockDownload() override {
return chainman().ActiveChainstate().IsInitialBlockDownload();
@@ -307,7 +301,11 @@ public:
}
}
bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
- CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
+ CFeeRate getDustRelayFee() override
+ {
+ if (!m_context->mempool) return CFeeRate{DUST_RELAY_TX_FEE};
+ return m_context->mempool->m_dust_relay_feerate;
+ }
UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
{
JSONRPCRequest req;
@@ -389,6 +387,7 @@ public:
{
m_context = context;
}
+ ChainstateManager& chainman() { return *Assert(m_context->chainman); }
NodeContext* m_context{nullptr};
};
@@ -501,40 +500,28 @@ public:
class ChainImpl : public Chain
{
-private:
- ChainstateManager& chainman() { return *Assert(m_node.chainman); }
public:
explicit ChainImpl(NodeContext& node) : m_node(node) {}
std::optional<int> getHeight() override
{
- LOCK(::cs_main);
- const CChain& active = chainman().ActiveChain();
- int height = active.Height();
- if (height >= 0) {
- return height;
- }
- return std::nullopt;
+ const int height{WITH_LOCK(::cs_main, return chainman().ActiveChain().Height())};
+ return height >= 0 ? std::optional{height} : std::nullopt;
}
uint256 getBlockHash(int height) override
{
LOCK(::cs_main);
- const CChain& active = chainman().ActiveChain();
- CBlockIndex* block = active[height];
- assert(block);
- return block->GetBlockHash();
+ return Assert(chainman().ActiveChain()[height])->GetBlockHash();
}
bool haveBlockOnDisk(int height) override
{
LOCK(::cs_main);
- const CChain& active = chainman().ActiveChain();
- CBlockIndex* block = active[height];
+ const CBlockIndex* block{chainman().ActiveChain()[height]};
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
}
CBlockLocator getTipLocator() override
{
LOCK(::cs_main);
- const CChain& active = chainman().ActiveChain();
- return active.GetLocator();
+ return chainman().ActiveChain().GetLocator();
}
CBlockLocator getActiveChainLocator(const uint256& block_hash) override
{
@@ -546,8 +533,7 @@ public:
std::optional<int> findLocatorFork(const CBlockLocator& locator) override
{
LOCK(::cs_main);
- const CChainState& active = chainman().ActiveChainstate();
- if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
+ if (const CBlockIndex* fork = chainman().ActiveChainstate().FindForkInGlobalIndex(locator)) {
return fork->nHeight;
}
return std::nullopt;
@@ -555,8 +541,7 @@ public:
bool findBlock(const uint256& hash, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = chainman().ActiveChain();
- return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, active);
+ return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, chainman().ActiveChain());
}
bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
{
@@ -578,11 +563,10 @@ public:
bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = chainman().ActiveChain();
const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);
const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);
if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
- return FillBlock(ancestor, ancestor_out, lock, active);
+ return FillBlock(ancestor, ancestor_out, lock, chainman().ActiveChain());
}
bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override
{
@@ -696,9 +680,21 @@ public:
if (!m_node.mempool) return {};
return m_node.mempool->GetMinFee();
}
- CFeeRate relayMinFee() override { return ::minRelayTxFee; }
- CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
- CFeeRate relayDustFee() override { return ::dustRelayFee; }
+ CFeeRate relayMinFee() override
+ {
+ if (!m_node.mempool) return CFeeRate{DEFAULT_MIN_RELAY_TX_FEE};
+ return m_node.mempool->m_min_relay_feerate;
+ }
+ CFeeRate relayIncrementalFee() override
+ {
+ if (!m_node.mempool) return CFeeRate{DEFAULT_INCREMENTAL_RELAY_FEE};
+ return m_node.mempool->m_incremental_relay_feerate;
+ }
+ CFeeRate relayDustFee() override
+ {
+ if (!m_node.mempool) return CFeeRate{DUST_RELAY_TX_FEE};
+ return m_node.mempool->m_dust_relay_feerate;
+ }
bool havePruned() override
{
LOCK(::cs_main);
@@ -722,11 +718,7 @@ public:
}
void waitForNotificationsIfTipChanged(const uint256& old_tip) override
{
- if (!old_tip.IsNull()) {
- LOCK(::cs_main);
- const CChain& active = chainman().ActiveChain();
- if (old_tip == active.Tip()->GetBlockHash()) return;
- }
+ if (!old_tip.IsNull() && old_tip == WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()->GetBlockHash())) return;
SyncWithValidationInterfaceQueue();
}
std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
@@ -782,6 +774,7 @@ public:
}
NodeContext* context() override { return &m_node; }
+ ChainstateManager& chainman() { return *Assert(m_node.chainman); }
NodeContext& m_node;
};
} // namespace
diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp
new file mode 100644
index 0000000000..60993f1d8d
--- /dev/null
+++ b/src/node/mempool_args.cpp
@@ -0,0 +1,99 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <node/mempool_args.h>
+
+#include <kernel/mempool_limits.h>
+#include <kernel/mempool_options.h>
+
+#include <chainparams.h>
+#include <consensus/amount.h>
+#include <logging.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <tinyformat.h>
+#include <util/error.h>
+#include <util/moneystr.h>
+#include <util/system.h>
+#include <util/translation.h>
+
+#include <chrono>
+#include <memory>
+
+using kernel::MemPoolLimits;
+using kernel::MemPoolOptions;
+
+namespace {
+void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolLimits& mempool_limits)
+{
+ mempool_limits.ancestor_count = argsman.GetIntArg("-limitancestorcount", mempool_limits.ancestor_count);
+
+ if (auto vkb = argsman.GetIntArg("-limitancestorsize")) mempool_limits.ancestor_size_vbytes = *vkb * 1'000;
+
+ mempool_limits.descendant_count = argsman.GetIntArg("-limitdescendantcount", mempool_limits.descendant_count);
+
+ if (auto vkb = argsman.GetIntArg("-limitdescendantsize")) mempool_limits.descendant_size_vbytes = *vkb * 1'000;
+}
+}
+
+std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, const CChainParams& chainparams, MemPoolOptions& mempool_opts)
+{
+ mempool_opts.check_ratio = argsman.GetIntArg("-checkmempool", mempool_opts.check_ratio);
+
+ if (auto mb = argsman.GetIntArg("-maxmempool")) mempool_opts.max_size_bytes = *mb * 1'000'000;
+
+ if (auto hours = argsman.GetIntArg("-mempoolexpiry")) mempool_opts.expiry = std::chrono::hours{*hours};
+
+ // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
+ // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
+ if (argsman.IsArgSet("-incrementalrelayfee")) {
+ if (std::optional<CAmount> inc_relay_fee = ParseMoney(argsman.GetArg("-incrementalrelayfee", ""))) {
+ mempool_opts.incremental_relay_feerate = CFeeRate{inc_relay_fee.value()};
+ } else {
+ return AmountErrMsg("incrementalrelayfee", argsman.GetArg("-incrementalrelayfee", ""));
+ }
+ }
+
+ if (argsman.IsArgSet("-minrelaytxfee")) {
+ if (std::optional<CAmount> min_relay_feerate = ParseMoney(argsman.GetArg("-minrelaytxfee", ""))) {
+ // High fee check is done afterward in CWallet::Create()
+ mempool_opts.min_relay_feerate = CFeeRate{min_relay_feerate.value()};
+ } else {
+ return AmountErrMsg("minrelaytxfee", argsman.GetArg("-minrelaytxfee", ""));
+ }
+ } else if (mempool_opts.incremental_relay_feerate > mempool_opts.min_relay_feerate) {
+ // Allow only setting incremental fee to control both
+ mempool_opts.min_relay_feerate = mempool_opts.incremental_relay_feerate;
+ LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n", mempool_opts.min_relay_feerate.ToString());
+ }
+
+ // Feerate used to define dust. Shouldn't be changed lightly as old
+ // implementations may inadvertently create non-standard transactions
+ if (argsman.IsArgSet("-dustrelayfee")) {
+ if (std::optional<CAmount> parsed = ParseMoney(argsman.GetArg("-dustrelayfee", ""))) {
+ mempool_opts.dust_relay_feerate = CFeeRate{parsed.value()};
+ } else {
+ return AmountErrMsg("dustrelayfee", argsman.GetArg("-dustrelayfee", ""));
+ }
+ }
+
+ mempool_opts.permit_bare_multisig = argsman.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
+
+ if (argsman.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER)) {
+ mempool_opts.max_datacarrier_bytes = argsman.GetIntArg("-datacarriersize", MAX_OP_RETURN_RELAY);
+ } else {
+ mempool_opts.max_datacarrier_bytes = std::nullopt;
+ }
+
+ mempool_opts.require_standard = !argsman.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
+ if (!chainparams.IsTestChain() && !mempool_opts.require_standard) {
+ return strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString());
+ }
+
+ mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf);
+
+ ApplyArgsManOptions(argsman, mempool_opts.limits);
+
+ return std::nullopt;
+}
diff --git a/src/mempool_args.h b/src/node/mempool_args.h
index 9a4abe6618..52d8b4f265 100644
--- a/src/mempool_args.h
+++ b/src/node/mempool_args.h
@@ -2,21 +2,26 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_MEMPOOL_ARGS_H
-#define BITCOIN_MEMPOOL_ARGS_H
+#ifndef BITCOIN_NODE_MEMPOOL_ARGS_H
+#define BITCOIN_NODE_MEMPOOL_ARGS_H
+
+#include <optional>
class ArgsManager;
+class CChainParams;
+struct bilingual_str;
namespace kernel {
struct MemPoolOptions;
};
/**
* Overlay the options set in \p argsman on top of corresponding members in \p mempool_opts.
+ * Returns an error if one was encountered.
*
* @param[in] argsman The ArgsManager in which to check set options.
* @param[in,out] mempool_opts The MemPoolOptions to modify according to \p argsman.
*/
-void ApplyArgsManOptions(const ArgsManager& argsman, kernel::MemPoolOptions& mempool_opts);
+[[nodiscard]] std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, const CChainParams& chainparams, kernel::MemPoolOptions& mempool_opts);
-#endif // BITCOIN_MEMPOOL_ARGS_H
+#endif // BITCOIN_NODE_MEMPOOL_ARGS_H
diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp
index 5a932f435d..57162cd679 100644
--- a/src/node/psbt.cpp
+++ b/src/node/psbt.cpp
@@ -137,7 +137,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
if (success) {
CTransaction ctx = CTransaction(mtx);
- size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
+ size_t size(GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS), ::nBytesPerSigOp));
result.estimated_vsize = size;
// Estimate fee rate
CFeeRate feerate(fee, size);
diff --git a/src/node/validation_cache_args.cpp b/src/node/validation_cache_args.cpp
new file mode 100644
index 0000000000..5ea0a8ca0a
--- /dev/null
+++ b/src/node/validation_cache_args.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <node/validation_cache_args.h>
+
+#include <kernel/validation_cache_sizes.h>
+
+#include <util/system.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
+
+using kernel::ValidationCacheSizes;
+
+namespace node {
+void ApplyArgsManOptions(const ArgsManager& argsman, ValidationCacheSizes& cache_sizes)
+{
+ if (auto max_size = argsman.GetIntArg("-maxsigcachesize")) {
+ // 1. When supplied with a max_size of 0, both InitSignatureCache and
+ // InitScriptExecutionCache create the minimum possible cache (2
+ // elements). Therefore, we can use 0 as a floor here.
+ // 2. Multiply first, divide after to avoid integer truncation.
+ size_t clamped_size_each = std::max<int64_t>(*max_size, 0) * (1 << 20) / 2;
+ cache_sizes = {
+ .signature_cache_bytes = clamped_size_each,
+ .script_execution_cache_bytes = clamped_size_each,
+ };
+ }
+}
+} // namespace node
diff --git a/src/node/validation_cache_args.h b/src/node/validation_cache_args.h
new file mode 100644
index 0000000000..f447c13b49
--- /dev/null
+++ b/src/node/validation_cache_args.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_NODE_VALIDATION_CACHE_ARGS_H
+#define BITCOIN_NODE_VALIDATION_CACHE_ARGS_H
+
+class ArgsManager;
+namespace kernel {
+struct ValidationCacheSizes;
+};
+
+namespace node {
+void ApplyArgsManOptions(const ArgsManager& argsman, kernel::ValidationCacheSizes& cache_sizes);
+} // namespace node
+
+#endif // BITCOIN_NODE_VALIDATION_CACHE_ARGS_H
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index f6452266b7..5086542865 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -67,7 +67,7 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
}
-bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
+bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType)
{
std::vector<std::vector<unsigned char> > vSolutions;
whichType = Solver(scriptPubKey, vSolutions);
@@ -82,15 +82,16 @@ bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
return false;
if (m < 1 || m > n)
return false;
- } else if (whichType == TxoutType::NULL_DATA &&
- (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
- return false;
+ } else if (whichType == TxoutType::NULL_DATA) {
+ if (!max_datacarrier_bytes || scriptPubKey.size() > *max_datacarrier_bytes) {
+ return false;
+ }
}
return true;
}
-bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
+bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
{
if (tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) {
reason = "version";
@@ -130,7 +131,7 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
unsigned int nDataOut = 0;
TxoutType whichType;
for (const CTxOut& txout : tx.vout) {
- if (!::IsStandard(txout.scriptPubKey, whichType)) {
+ if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) {
reason = "scriptpubkey";
return false;
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index cd98a601a3..3d2660b081 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -47,8 +47,8 @@ static constexpr unsigned int MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE{80};
static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE{3600};
/** The maximum size of a standard ScriptSig */
static constexpr unsigned int MAX_STANDARD_SCRIPTSIG_SIZE{1650};
-/** Min feerate for defining dust. Historically this has been based on the
- * minRelayTxFee, however changing the dust limit changes which transactions are
+/** Min feerate for defining dust.
+ * Changing the dust limit changes which transactions are
* standard and should be done with care and ideally rarely. It makes sense to
* only increase the dust limit after prior releases were already not creating
* outputs below the new threshold */
@@ -105,7 +105,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
-bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType);
+bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType);
// Changing the default transaction version requires a two step process: first
@@ -117,7 +117,7 @@ static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2};
* Check for standard transaction types
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
-bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
+bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
/**
* Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
diff --git a/src/policy/settings.cpp b/src/policy/settings.cpp
index 0b67d274ce..39e00f1111 100644
--- a/src/policy/settings.cpp
+++ b/src/policy/settings.cpp
@@ -5,11 +5,6 @@
#include <policy/settings.h>
-#include <policy/feerate.h>
#include <policy/policy.h>
-bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
-CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
-CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
-CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
diff --git a/src/policy/settings.h b/src/policy/settings.h
index 2311d01fe8..f0d6f779ae 100644
--- a/src/policy/settings.h
+++ b/src/policy/settings.h
@@ -6,35 +6,6 @@
#ifndef BITCOIN_POLICY_SETTINGS_H
#define BITCOIN_POLICY_SETTINGS_H
-#include <policy/feerate.h>
-#include <policy/policy.h>
-
-#include <cstdint>
-#include <string>
-
-class CTransaction;
-
-// Policy settings which are configurable at runtime.
-extern CFeeRate incrementalRelayFee;
-extern CFeeRate dustRelayFee;
-/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
-extern CFeeRate minRelayTxFee;
extern unsigned int nBytesPerSigOp;
-extern bool fIsBareMultisigStd;
-
-static inline bool IsStandardTx(const CTransaction& tx, std::string& reason)
-{
- return IsStandardTx(tx, ::fIsBareMultisigStd, ::dustRelayFee, reason);
-}
-
-static inline int64_t GetVirtualTransactionSize(int64_t weight, int64_t sigop_cost)
-{
- return GetVirtualTransactionSize(weight, sigop_cost, ::nBytesPerSigOp);
-}
-
-static inline int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t sigop_cost)
-{
- return GetVirtualTransactionSize(tx, sigop_cost, ::nBytesPerSigOp);
-}
#endif // BITCOIN_POLICY_SETTINGS_H
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index bb50b5384a..8b5da7f9f0 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -384,7 +384,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
}
- strAddress = EncodeDestination(op_dest.GetObj());
+ strAddress = EncodeDestination(*op_dest);
}
else
{
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 2551be0af3..5cc21dd40b 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -428,7 +428,7 @@ void openDebugLogfile()
bool openBitcoinConf()
{
- fs::path pathConfig = GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
+ fs::path pathConfig = GetConfigFile(gArgs.GetPathArg("-conf", BITCOIN_CONF_FILENAME));
/* Create the file */
std::ofstream configFile{pathConfig, std::ios_base::app};
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 01d84624e8..6e07dc09a0 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -393,8 +393,8 @@ void RestoreWalletActivity::restore(const fs::path& backup_file, const std::stri
QTimer::singleShot(0, worker(), [this, backup_file, wallet_name] {
auto wallet{node().walletLoader().restoreWallet(backup_file, wallet_name, m_warning_message)};
- m_error_message = wallet ? bilingual_str{} : wallet.GetError();
- if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(wallet.ReleaseObj());
+ m_error_message = util::ErrorString(wallet);
+ if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet));
QTimer::singleShot(0, this, &RestoreWalletActivity::finish);
});
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index fde136b727..ac6c8bea46 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -207,7 +207,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
auto& newTx = transaction.getWtx();
const auto& res = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired);
- newTx = res ? res.GetObj() : nullptr;
+ newTx = res ? *res : nullptr;
transaction.setTransactionFee(nFeeRequired);
if (fSubtractFeeFromAmount && newTx)
transaction.reassignAmounts(nChangePosRet);
@@ -218,7 +218,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
return SendCoinsReturn(AmountWithFeeExceedsBalance);
}
- Q_EMIT message(tr("Send Coins"), QString::fromStdString(res.GetError().translated),
+ Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated),
CClientUIInterface::MSG_ERROR);
return TransactionCreationFailed;
}
diff --git a/src/rest.cpp b/src/rest.cpp
index 43c248b03b..85815a9c8b 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -590,45 +590,31 @@ static bool rest_chaininfo(const std::any& context, HTTPRequest* req, const std:
}
}
-static bool rest_mempool_info(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::string& str_uri_part)
{
if (!CheckWarmup(req))
return false;
- const CTxMemPool* mempool = GetMemPool(context, req);
- if (!mempool) return false;
- std::string param;
- const RESTResponseFormat rf = ParseDataFormat(param, strURIPart);
-
- switch (rf) {
- case RESTResponseFormat::JSON: {
- UniValue mempoolInfoObject = MempoolInfoToJSON(*mempool);
- std::string strJSON = mempoolInfoObject.write() + "\n";
- req->WriteHeader("Content-Type", "application/json");
- req->WriteReply(HTTP_OK, strJSON);
- return true;
- }
- default: {
- return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
- }
+ std::string param;
+ const RESTResponseFormat rf = ParseDataFormat(param, str_uri_part);
+ if (param != "contents" && param != "info") {
+ return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/mempool/<info|contents>.json");
}
-}
-static bool rest_mempool_contents(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
-{
- if (!CheckWarmup(req)) return false;
const CTxMemPool* mempool = GetMemPool(context, req);
if (!mempool) return false;
- std::string param;
- const RESTResponseFormat rf = ParseDataFormat(param, strURIPart);
switch (rf) {
case RESTResponseFormat::JSON: {
- UniValue mempoolObject = MempoolToJSON(*mempool, true);
+ std::string str_json;
+ if (param == "contents") {
+ str_json = MempoolToJSON(*mempool, true).write() + "\n";
+ } else {
+ str_json = MempoolInfoToJSON(*mempool).write() + "\n";
+ }
- std::string strJSON = mempoolObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
- req->WriteReply(HTTP_OK, strJSON);
+ req->WriteReply(HTTP_OK, str_json);
return true;
}
default: {
@@ -946,8 +932,7 @@ static const struct {
{"/rest/blockfilter/", rest_block_filter},
{"/rest/blockfilterheaders/", rest_filter_header},
{"/rest/chaininfo", rest_chaininfo},
- {"/rest/mempool/info", rest_mempool_info},
- {"/rest/mempool/contents", rest_mempool_contents},
+ {"/rest/mempool/", rest_mempool},
{"/rest/headers/", rest_headers},
{"/rest/getutxos", rest_getutxos},
{"/rest/blockhashbyheight/", rest_blockhash_by_height},
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 9be3ab7df0..ee287656b6 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -147,6 +147,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendall", 1, "conf_target" },
{ "sendall", 3, "fee_rate"},
{ "sendall", 4, "options" },
+ { "simulaterawtransaction", 0, "rawtxs" },
+ { "simulaterawtransaction", 1, "options" },
{ "importprivkey", 2, "rescan" },
{ "importaddress", 2, "rescan" },
{ "importaddress", 3, "p2sh" },
diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp
index 41f386d443..aa047bdea8 100644
--- a/src/rpc/fees.cpp
+++ b/src/rpc/fees.cpp
@@ -6,7 +6,6 @@
#include <core_io.h>
#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/settings.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <rpc/server.h>
@@ -88,7 +87,7 @@ static RPCHelpMan estimatesmartfee()
CFeeRate feeRate{fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative)};
if (feeRate != CFeeRate(0)) {
CFeeRate min_mempool_feerate{mempool.GetMinFee()};
- CFeeRate min_relay_feerate{::minRelayTxFee};
+ CFeeRate min_relay_feerate{mempool.m_min_relay_feerate};
feeRate = std::max({feeRate, min_mempool_feerate, min_relay_feerate});
result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
} else {
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index 0ae10b6c39..02b51ce0a0 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -666,9 +666,9 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
ret.pushKV("maxmempool", pool.m_max_size_bytes);
- ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), ::minRelayTxFee).GetFeePerK()));
- ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
- ret.pushKV("incrementalrelayfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));
+ ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_min_relay_feerate).GetFeePerK()));
+ ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_min_relay_feerate.GetFeePerK()));
+ ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_incremental_relay_feerate.GetFeePerK()));
ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
ret.pushKV("fullrbf", pool.m_full_rbf);
return ret;
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 059be61bb4..3b234bc317 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -23,6 +23,7 @@
#include <timedata.h>
#include <util/strencodings.h>
#include <util/string.h>
+#include <util/time.h>
#include <util/translation.h>
#include <validation.h>
#include <version.h>
@@ -645,8 +646,11 @@ static RPCHelpMan getnetworkinfo()
obj.pushKV("connections_out", node.connman->GetNodeCount(ConnectionDirection::Out));
}
obj.pushKV("networks", GetNetworksInfo());
- obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
- obj.pushKV("incrementalfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));
+ if (node.mempool) {
+ // Those fields can be deprecated, to be replaced by the getmempoolinfo fields
+ obj.pushKV("relayfee", ValueFromAmount(node.mempool->m_min_relay_feerate.GetFeePerK()));
+ obj.pushKV("incrementalfee", ValueFromAmount(node.mempool->m_incremental_relay_feerate.GetFeePerK()));
+ }
UniValue localAddresses(UniValue::VARR);
{
LOCK(g_maplocalhost_mutex);
@@ -942,7 +946,7 @@ static RPCHelpMan addpeeraddress()
if (LookupHost(addr_string, net_addr, false)) {
CAddress address{{net_addr, port}, ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
- address.nTime = AdjustedTime();
+ address.nTime = Now<NodeSeconds>();
// The source address is set equal to the address. This is equivalent to the peer
// announcing itself.
if (node.addrman->Add({address}, address)) {
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 9ec506b0fb..7ffb499330 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -157,7 +157,7 @@ static std::vector<RPCArg> CreateTxDoc()
},
},
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125-replaceable.\n"
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Marks this transaction as BIP125-replaceable.\n"
"Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
};
}
@@ -302,7 +302,7 @@ static RPCHelpMan createrawtransaction()
}, true
);
- bool rbf = false;
+ std::optional<bool> rbf;
if (!request.params[3].isNull()) {
rbf = request.params[3].isTrue();
}
@@ -1451,7 +1451,7 @@ static RPCHelpMan createpsbt()
}, true
);
- bool rbf = false;
+ std::optional<bool> rbf;
if (!request.params[3].isNull()) {
rbf = request.params[3].isTrue();
}
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 86b5b7e960..b06e9f6e4b 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -21,7 +21,7 @@
#include <util/strencodings.h>
#include <util/translation.h>
-CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
+CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf)
{
if (outputs_in.isNull()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
@@ -60,7 +60,8 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
uint32_t nSequence;
- if (rbf) {
+
+ if (rbf.value_or(true)) {
nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
} else if (rawTx.nLockTime) {
nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; /* CTxIn::SEQUENCE_FINAL - 1 */
@@ -132,7 +133,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
}
}
- if (rbf && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
+ if (rbf.has_value() && rbf.value() && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
}
diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h
index c3eb1417f8..9b5c9f08d4 100644
--- a/src/rpc/rawtransaction_util.h
+++ b/src/rpc/rawtransaction_util.h
@@ -7,6 +7,7 @@
#include <map>
#include <string>
+#include <optional>
struct bilingual_str;
class FillableSigningProvider;
@@ -38,6 +39,6 @@ void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const
void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins);
/** Create a transaction from univalue parameters */
-CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf);
+CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf);
#endif // BITCOIN_RPC_RAWTRANSACTION_UTIL_H
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index 304c265b31..8595fa78bb 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -66,16 +66,16 @@ UniValue JSONRPCError(int code, const std::string& message)
*/
static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
-static const std::string COOKIEAUTH_FILE = ".cookie";
+static const char* const COOKIEAUTH_FILE = ".cookie";
/** Get name of RPC authentication cookie file */
static fs::path GetAuthCookieFile(bool temp=false)
{
- std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE);
+ fs::path arg = gArgs.GetPathArg("-rpccookiefile", COOKIEAUTH_FILE);
if (temp) {
arg += ".tmp";
}
- return AbsPathForConfigVal(fs::PathFromString(arg));
+ return AbsPathForConfigVal(arg);
}
bool GenerateAuthCookie(std::string *cookie_out)
diff --git a/src/script/script.h b/src/script/script.h
index 3b799ad637..1e5f694d52 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -588,7 +588,6 @@ CScript BuildScript(Ts&&... inputs)
int cnt{0};
([&ret, &cnt] (Ts&& input) {
- cnt++;
if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ts>>, CScript>) {
// If it is a CScript, extend ret with it. Move or copy the first element instead.
if (cnt == 0) {
@@ -600,6 +599,7 @@ CScript BuildScript(Ts&&... inputs)
// Otherwise invoke CScript::operator<<.
ret << input;
}
+ cnt++;
} (std::forward<Ts>(inputs)), ...);
return ret;
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 4e2acc463a..e507ec7528 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -14,6 +14,7 @@
#include <algorithm>
#include <mutex>
+#include <optional>
#include <shared_mutex>
#include <vector>
@@ -75,7 +76,7 @@ public:
std::unique_lock<std::shared_mutex> lock(cs_sigcache);
setValid.insert(entry);
}
- uint32_t setup_bytes(size_t n)
+ std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t n)
{
return setValid.setup_bytes(n);
}
@@ -92,14 +93,15 @@ static CSignatureCache signatureCache;
// To be called once in AppInitMain/BasicTestingSetup to initialize the
// signatureCache.
-void InitSignatureCache()
+bool InitSignatureCache(size_t max_size_bytes)
{
- // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
- // setup_bytes creates the minimum possible cache (2 elements).
- size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
- size_t nElems = signatureCache.setup_bytes(nMaxCacheSize);
- LogPrintf("Using %zu MiB out of %zu/2 requested for signature cache, able to store %zu elements\n",
- (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
+ auto setup_results = signatureCache.setup_bytes(max_size_bytes);
+ if (!setup_results) return false;
+
+ const auto [num_elems, approx_size_bytes] = *setup_results;
+ LogPrintf("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements\n",
+ approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
+ return true;
}
bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 1e21d6f340..290955090d 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -10,14 +10,13 @@
#include <span.h>
#include <util/hasher.h>
+#include <optional>
#include <vector>
-// DoS prevention: limit cache size to 32MB (over 1000000 entries on 64-bit
+// DoS prevention: limit cache size to 32MiB (over 1000000 entries on 64-bit
// systems). Due to how we count cache size, actual memory usage is slightly
-// more (~32.25 MB)
-static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 32;
-// Maximum sig cache size allowed
-static const int64_t MAX_MAX_SIG_CACHE_SIZE = 16384;
+// more (~32.25 MiB)
+static constexpr size_t DEFAULT_MAX_SIG_CACHE_BYTES{32 << 20};
class CPubKey;
@@ -33,6 +32,6 @@ public:
bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const override;
};
-void InitSignatureCache();
+[[nodiscard]] bool InitSignatureCache(size_t max_size_bytes);
#endif // BITCOIN_SCRIPT_SIGCACHE_H
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index b3f6a1b669..6101738061 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -16,9 +16,6 @@
typedef std::vector<unsigned char> valtype;
-bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
-unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
-
CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in)) {}
CScriptID::CScriptID(const ScriptHash& in) : BaseHash(static_cast<uint160>(in)) {}
diff --git a/src/script/standard.h b/src/script/standard.h
index 448fdff010..1e6769782a 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -33,21 +33,12 @@ public:
};
/**
- * Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
+ * Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN,
* +2 for the pushdata opcodes.
*/
static const unsigned int MAX_OP_RETURN_RELAY = 83;
/**
- * A data carrying output is an unspendable output containing data. The script
- * type is designated as TxoutType::NULL_DATA.
- */
-extern bool fAcceptDatacarrier;
-
-/** Maximum size of TxoutType::NULL_DATA scripts that this node considers standard. */
-extern unsigned nMaxDatacarrierBytes;
-
-/**
* Mandatory script verification flags that all new blocks must comply with for
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
* but in the future other flags may be added.
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index b1372a3e98..b10d32ccec 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -225,7 +225,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
- const auto start_time{AdjustedTime()};
+ const auto start_time{Now<NodeSeconds>()};
addr.nTime = start_time;
// test that multiplicity stays at 1 if nTime doesn't increase
@@ -295,15 +295,15 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
- addr1.nTime = AdjustedTime(); // Set time so isTerrible = false
+ addr1.nTime = Now<NodeSeconds>(); // Set time so isTerrible = false
CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
- addr2.nTime = AdjustedTime();
+ addr2.nTime = Now<NodeSeconds>();
CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
- addr3.nTime = AdjustedTime();
+ addr3.nTime = Now<NodeSeconds>();
CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
- addr4.nTime = AdjustedTime();
+ addr4.nTime = Now<NodeSeconds>();
CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
- addr5.nTime = AdjustedTime();
+ addr5.nTime = Now<NodeSeconds>();
CNetAddr source1 = ResolveIP("250.1.2.1");
CNetAddr source2 = ResolveIP("250.2.3.3");
@@ -329,7 +329,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
// Ensure that for all addrs in addrman, isTerrible == false.
- addr.nTime = AdjustedTime();
+ addr.nTime = Now<NodeSeconds>();
addrman->Add({addr}, ResolveIP(strAddr));
if (i % 8 == 0)
addrman->Good(addr);
@@ -822,7 +822,7 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
// Ensure test of address fails, so that it is evicted.
// Update entry in tried by setting last good connection in the deep past.
BOOST_CHECK(!addrman->Good(info, NodeSeconds{1s}));
- addrman->Attempt(info, /*fCountFailure=*/false, AdjustedTime() - 61s);
+ addrman->Attempt(info, /*fCountFailure=*/false, Now<NodeSeconds>() - 61s);
// Should swap 36 for 19.
addrman->ResolveCollisions();
@@ -966,7 +966,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
CNetAddr source{ResolveIP("252.2.2.2")};
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
- const auto start_time{AdjustedTime() - 10000s};
+ const auto start_time{Now<NodeSeconds>() - 10000s};
addr.nTime = start_time;
BOOST_CHECK(addrman->Add({addr}, source));
BOOST_CHECK_EQUAL(addrman->size(), 1U);
diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp
index 72574612a2..c52fca5fe8 100644
--- a/src/test/fuzz/integer.cpp
+++ b/src/test/fuzz/integer.cpp
@@ -87,9 +87,6 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
}
(void)GetSizeOfCompactSize(u64);
(void)GetSpecialScriptSize(u32);
- if (!MultiplicationOverflow(i64, static_cast<int64_t>(::nBytesPerSigOp)) && !AdditionOverflow(i64 * ::nBytesPerSigOp, static_cast<int64_t>(4))) {
- (void)GetVirtualTransactionSize(i64, i64);
- }
if (!MultiplicationOverflow(i64, static_cast<int64_t>(u32)) && !AdditionOverflow(i64, static_cast<int64_t>(4)) && !AdditionOverflow(i64 * u32, static_cast<int64_t>(4))) {
(void)GetVirtualTransactionSize(i64, i64, u32);
}
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index bfea9778f4..6d2d2e2bc5 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -157,12 +157,12 @@ FUZZ_TARGET_INIT(key, initialize_key)
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
TxoutType which_type_tx_pubkey;
- const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, which_type_tx_pubkey);
+ const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, std::nullopt, which_type_tx_pubkey);
assert(is_standard_tx_pubkey);
assert(which_type_tx_pubkey == TxoutType::PUBKEY);
TxoutType which_type_tx_multisig;
- const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, which_type_tx_multisig);
+ const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, std::nullopt, which_type_tx_multisig);
assert(is_standard_tx_multisig);
assert(which_type_tx_multisig == TxoutType::MULTISIG);
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index 4801635791..1a06ae886e 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <mempool_args.h>
+#include <node/mempool_args.h>
#include <policy/rbf.h>
#include <primitives/transaction.h>
#include <sync.h>
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index fdcd0da37d..69a4b782aa 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -55,7 +55,7 @@ FUZZ_TARGET_INIT(script, initialize_script)
}
TxoutType which_type;
- bool is_standard_ret = IsStandard(script, which_type);
+ bool is_standard_ret = IsStandard(script, std::nullopt, which_type);
if (!is_standard_ret) {
assert(which_type == TxoutType::NONSTANDARD ||
which_type == TxoutType::NULL_DATA ||
diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp
index f7e45d6889..f6af7947df 100644
--- a/src/test/fuzz/script_sigcache.cpp
+++ b/src/test/fuzz/script_sigcache.cpp
@@ -10,18 +10,21 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
+namespace {
+const BasicTestingSetup* g_setup;
+} // namespace
+
void initialize_script_sigcache()
{
- static const ECCVerifyHandle ecc_verify_handle;
- ECC_Start();
- SelectParams(CBaseChainParams::REGTEST);
- InitSignatureCache();
+ static const auto testing_setup = MakeNoLogFileContext<>();
+ g_setup = testing_setup.get();
}
FUZZ_TARGET_INIT(script_sigcache, initialize_script_sigcache)
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 273aa0dc5c..7fa4523800 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -69,8 +69,8 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
std::string reason;
- const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, /* permit_bare_multisig= */ true, dust_relay_fee, reason);
- const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, /* permit_bare_multisig= */ false, dust_relay_fee, reason);
+ const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ true, dust_relay_fee, reason);
+ const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ false, dust_relay_fee, reason);
if (is_standard_without_permit_bare_multisig) {
assert(is_standard_with_permit_bare_multisig);
}
@@ -92,7 +92,6 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
(void)GetTransactionWeight(tx);
(void)GetVirtualTransactionSize(tx);
(void)IsFinalTx(tx, /* nBlockHeight= */ 1024, /* nBlockTime= */ 1024);
- (void)IsStandardTx(tx, reason);
(void)RecursiveDynamicUsage(tx);
(void)SignalsOptInRBF(tx);
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index cfb112879a..3191367870 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -3,8 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/validation.h>
-#include <mempool_args.h>
#include <node/context.h>
+#include <node/mempool_args.h>
#include <node/miner.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -116,7 +116,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chain
SetMockTime(time);
}
-CTxMemPool MakeMempool(const NodeContext& node)
+CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
{
// Take the default options for tests...
CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
@@ -124,6 +124,7 @@ CTxMemPool MakeMempool(const NodeContext& node)
// ...override specific options for this specific fuzz suite
mempool_opts.estimator = nullptr;
mempool_opts.check_ratio = 1;
+ mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
// ...and construct a CTxMemPool from it
return CTxMemPool{mempool_opts};
@@ -150,7 +151,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
SetMempoolConstraints(*node.args, fuzzed_data_provider);
- CTxMemPool tx_pool_{MakeMempool(node)};
+ CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
chainstate.SetMempool(&tx_pool);
@@ -237,7 +238,6 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
auto txr = std::make_shared<TransactionsDelta>(removed, added);
RegisterSharedValidationInterface(txr);
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
- ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
// Make sure ProcessNewPackage on one transaction works.
// The result is not guaranteed to be the same as what is returned by ATMP.
@@ -325,7 +325,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
}
SetMempoolConstraints(*node.args, fuzzed_data_provider);
- CTxMemPool tx_pool_{MakeMempool(node)};
+ CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
@@ -348,7 +348,6 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
const auto tx = MakeTransactionRef(mut_tx);
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
- ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
if (accepted) {
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
index 90c1a71d9f..8241dff189 100644
--- a/src/test/fuzz/validation_load_mempool.cpp
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -5,7 +5,7 @@
#include <kernel/mempool_persist.h>
#include <chainparamsbase.h>
-#include <mempool_args.h>
+#include <node/mempool_args.h>
#include <node/mempool_persist_args.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 20d670c1e1..df04bfcc2f 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -325,7 +325,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
- m_node.chainman->ActiveChain().SetTip(next);
+ m_node.chainman->ActiveChain().SetTip(*next);
}
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// Extend to a 210000-long block chain.
@@ -337,7 +337,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
- m_node.chainman->ActiveChain().SetTip(next);
+ m_node.chainman->ActiveChain().SetTip(*next);
}
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
@@ -362,7 +362,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
// Delete the dummy blocks again.
while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) {
CBlockIndex* del = m_node.chainman->ActiveChain().Tip();
- m_node.chainman->ActiveChain().SetTip(del->pprev);
+ m_node.chainman->ActiveChain().SetTip(*Assert(del->pprev));
m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(del->pprev->GetBlockHash());
delete del->phashBlock;
delete del;
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index dccc7ce795..ce23d6013d 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -141,23 +141,30 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
for (int i = 0; i < 4; i++)
key[i].MakeNewKey(true);
- TxoutType whichType;
+ const auto is_standard{[](const CScript& spk) {
+ TxoutType type;
+ bool res{::IsStandard(spk, std::nullopt, type)};
+ if (res) {
+ BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
+ }
+ return res;
+ }};
CScript a_and_b;
a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(::IsStandard(a_and_b, whichType));
+ BOOST_CHECK(is_standard(a_and_b));
CScript a_or_b;
a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(::IsStandard(a_or_b, whichType));
+ BOOST_CHECK(is_standard(a_or_b));
CScript escrow;
escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
- BOOST_CHECK(::IsStandard(escrow, whichType));
+ BOOST_CHECK(is_standard(escrow));
CScript one_of_four;
one_of_four << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << ToByteVector(key[3].GetPubKey()) << OP_4 << OP_CHECKMULTISIG;
- BOOST_CHECK(!::IsStandard(one_of_four, whichType));
+ BOOST_CHECK(!is_standard(one_of_four));
CScript malformed[6];
malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
@@ -167,8 +174,9 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;
malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());
- for (int i = 0; i < 6; i++)
- BOOST_CHECK(!::IsStandard(malformed[i], whichType));
+ for (int i = 0; i < 6; i++) {
+ BOOST_CHECK(!is_standard(malformed[i]));
+ }
}
BOOST_AUTO_TEST_CASE(multisig_Sign)
diff --git a/src/test/result_tests.cpp b/src/test/result_tests.cpp
new file mode 100644
index 0000000000..6a23a7b895
--- /dev/null
+++ b/src/test/result_tests.cpp
@@ -0,0 +1,96 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <util/result.h>
+
+#include <boost/test/unit_test.hpp>
+
+inline bool operator==(const bilingual_str& a, const bilingual_str& b)
+{
+ return a.original == b.original && a.translated == b.translated;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const bilingual_str& s)
+{
+ return os << "bilingual_str('" << s.original << "' , '" << s.translated << "')";
+}
+
+BOOST_AUTO_TEST_SUITE(result_tests)
+
+struct NoCopy {
+ NoCopy(int n) : m_n{std::make_unique<int>(n)} {}
+ std::unique_ptr<int> m_n;
+};
+
+bool operator==(const NoCopy& a, const NoCopy& b)
+{
+ return *a.m_n == *b.m_n;
+}
+
+std::ostream& operator<<(std::ostream& os, const NoCopy& o)
+{
+ return os << "NoCopy(" << *o.m_n << ")";
+}
+
+util::Result<int> IntFn(int i, bool success)
+{
+ if (success) return i;
+ return util::Error{Untranslated(strprintf("int %i error.", i))};
+}
+
+util::Result<bilingual_str> StrFn(bilingual_str s, bool success)
+{
+ if (success) return s;
+ return util::Error{strprintf(Untranslated("str %s error."), s.original)};
+}
+
+util::Result<NoCopy> NoCopyFn(int i, bool success)
+{
+ if (success) return {i};
+ return util::Error{Untranslated(strprintf("nocopy %i error.", i))};
+}
+
+template <typename T>
+void ExpectResult(const util::Result<T>& result, bool success, const bilingual_str& str)
+{
+ BOOST_CHECK_EQUAL(bool(result), success);
+ BOOST_CHECK_EQUAL(util::ErrorString(result), str);
+}
+
+template <typename T, typename... Args>
+void ExpectSuccess(const util::Result<T>& result, const bilingual_str& str, Args&&... args)
+{
+ ExpectResult(result, true, str);
+ BOOST_CHECK_EQUAL(result.has_value(), true);
+ BOOST_CHECK_EQUAL(result.value(), T{std::forward<Args>(args)...});
+ BOOST_CHECK_EQUAL(&result.value(), &*result);
+}
+
+template <typename T, typename... Args>
+void ExpectFail(const util::Result<T>& result, const bilingual_str& str)
+{
+ ExpectResult(result, false, str);
+}
+
+BOOST_AUTO_TEST_CASE(check_returned)
+{
+ ExpectSuccess(IntFn(5, true), {}, 5);
+ ExpectFail(IntFn(5, false), Untranslated("int 5 error."));
+ ExpectSuccess(NoCopyFn(5, true), {}, 5);
+ ExpectFail(NoCopyFn(5, false), Untranslated("nocopy 5 error."));
+ ExpectSuccess(StrFn(Untranslated("S"), true), {}, Untranslated("S"));
+ ExpectFail(StrFn(Untranslated("S"), false), Untranslated("str S error."));
+}
+
+BOOST_AUTO_TEST_CASE(check_value_or)
+{
+ BOOST_CHECK_EQUAL(IntFn(10, true).value_or(20), 10);
+ BOOST_CHECK_EQUAL(IntFn(10, false).value_or(20), 20);
+ BOOST_CHECK_EQUAL(NoCopyFn(10, true).value_or(20), 10);
+ BOOST_CHECK_EQUAL(NoCopyFn(10, false).value_or(20), 20);
+ BOOST_CHECK_EQUAL(StrFn(Untranslated("A"), true).value_or(Untranslated("B")), Untranslated("A"));
+ BOOST_CHECK_EQUAL(StrFn(Untranslated("A"), false).value_or(Untranslated("B")), Untranslated("B"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 3e9e04da25..a52530e179 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -181,10 +181,10 @@ BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
BOOST_CHECK_EQUAL(ValueFromAmount(std::numeric_limits<CAmount>::min()).write(), "-92233720368.54775808");
}
-static UniValue ValueFromString(const std::string &str)
+static UniValue ValueFromString(const std::string& str) noexcept
{
UniValue value;
- BOOST_CHECK(value.setNumStr(str));
+ value.setNumStr(str);
return value;
}
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index a221e02d2f..a02d51eecc 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -18,15 +18,18 @@
#include <boost/test/unit_test.hpp>
// Helpers:
-static std::vector<unsigned char>
-Serialize(const CScript& s)
+static bool IsStandardTx(const CTransaction& tx, std::string& reason)
+{
+ return IsStandardTx(tx, std::nullopt, DEFAULT_PERMIT_BAREMULTISIG, CFeeRate{DUST_RELAY_TX_FEE}, reason);
+}
+
+static std::vector<unsigned char> Serialize(const CScript& s)
{
std::vector<unsigned char> sSerialized(s.begin(), s.end());
return sSerialized;
}
-static bool
-Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
+static bool Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
{
// Create dummy to/from transactions:
CMutableTransaction txFrom;
@@ -49,7 +52,6 @@ BOOST_FIXTURE_TEST_SUITE(script_p2sh_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sign)
{
- LOCK(cs_main);
// Pay-to-script-hash looks like this:
// scriptSig: <sig> <sig...> <serialized_script>
// scriptPubKey: HASH160 <hash> EQUAL
@@ -149,7 +151,6 @@ BOOST_AUTO_TEST_CASE(norecurse)
BOOST_AUTO_TEST_CASE(set)
{
- LOCK(cs_main);
// Test the CScript::Set* methods
FillableSigningProvider keystore;
CKey key[4];
@@ -263,7 +264,6 @@ BOOST_AUTO_TEST_CASE(switchover)
BOOST_AUTO_TEST_CASE(AreInputsStandard)
{
- LOCK(cs_main);
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
FillableSigningProvider keystore;
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 6dadf09176..3d3fd5d93d 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
// Build a CChain for the main branch.
CChain chain;
- chain.SetTip(&vBlocksMain.back());
+ chain.SetTip(vBlocksMain.back());
// Test 100 random starting points for locators.
for (int n=0; n<100; n++) {
@@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test)
// Build a CChain for the main branch.
CChain chain;
- chain.SetTip(&vBlocksMain.back());
+ chain.SetTip(vBlocksMain.back());
// Verify that FindEarliestAtLeast is correct.
for (unsigned int i=0; i<10000; ++i) {
@@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_edge_test)
}
CChain chain;
- chain.SetTip(&blocks.back());
+ chain.SetTip(blocks.back());
BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(50, 0)->nHeight, 0);
BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(100, 0)->nHeight, 0);
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 4e6c223ccc..cd6bf11327 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -40,6 +40,9 @@ typedef std::vector<unsigned char> valtype;
// In script_tests.cpp
UniValue read_json(const std::string& jsondata);
+static CFeeRate g_dust{DUST_RELAY_TX_FEE};
+static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
+
static std::map<std::string, unsigned int> mapFlagNames = {
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
{std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC},
@@ -745,7 +748,6 @@ BOOST_AUTO_TEST_CASE(test_witness)
BOOST_AUTO_TEST_CASE(test_IsStandard)
{
- LOCK(cs_main);
FillableSigningProvider keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
@@ -765,19 +767,19 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
constexpr auto CheckIsStandard = [](const auto& t) {
std::string reason;
- BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
+ BOOST_CHECK(IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason));
BOOST_CHECK(reason.empty());
};
constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in) {
std::string reason;
- BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
+ BOOST_CHECK(!IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason));
BOOST_CHECK_EQUAL(reason_in, reason);
};
CheckIsStandard(t);
// Check dust with default relay fee:
- CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK() / 1000;
+ CAmount nDustThreshold = 182 * g_dust.GetFeePerK() / 1000;
BOOST_CHECK_EQUAL(nDustThreshold, 546);
// dust:
t.vout[0].nValue = nDustThreshold - 1;
@@ -805,14 +807,14 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
// Check dust with odd relay fee to verify rounding:
// nDustThreshold = 182 * 3702 / 1000
- dustRelayFee = CFeeRate(3702);
+ g_dust = CFeeRate(3702);
// dust:
t.vout[0].nValue = 674 - 1;
CheckIsNotStandard(t, "dust");
// not dust:
t.vout[0].nValue = 674;
CheckIsStandard(t);
- dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
+ g_dust = CFeeRate{DUST_RELAY_TX_FEE};
t.vout[0].scriptPubKey = CScript() << OP_1;
CheckIsNotStandard(t, "scriptpubkey");
@@ -924,16 +926,16 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(t)), 400004);
CheckIsNotStandard(t, "tx-size");
- // Check bare multisig (standard if policy flag fIsBareMultisigStd is set)
- fIsBareMultisigStd = true;
+ // Check bare multisig (standard if policy flag g_bare_multi is set)
+ g_bare_multi = true;
t.vout[0].scriptPubKey = GetScriptForMultisig(1, {key.GetPubKey()}); // simple 1-of-1
t.vin.resize(1);
t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(65, 0);
CheckIsStandard(t);
- fIsBareMultisigStd = false;
+ g_bare_multi = false;
CheckIsNotStandard(t, "bare-multisig");
- fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
+ g_bare_multi = DEFAULT_PERMIT_BAREMULTISIG;
// Check P2WPKH outputs dust threshold
t.vout[0].scriptPubKey = CScript() << OP_0 << ParseHex("ffffffffffffffffffffffffffffffffffffffff");
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index dd4bc5af75..633f75ff4f 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -161,11 +161,6 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
{
// Test that passing CheckInputScripts with one set of script flags doesn't imply
// that we would pass again with a different set of flags.
- {
- LOCK(cs_main);
- InitScriptExecutionCache();
- }
-
CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
CScript p2sh_scriptPubKey = GetScriptForDestination(ScriptHash(p2pk_scriptPubKey));
CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 67984721a3..30d26ecf79 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -4,6 +4,8 @@
#include <test/util/setup_common.h>
+#include <kernel/validation_cache_sizes.h>
+
#include <addrman.h>
#include <banman.h>
#include <chainparams.h>
@@ -14,13 +16,14 @@
#include <init.h>
#include <init/common.h>
#include <interfaces/chain.h>
-#include <mempool_args.h>
#include <net.h>
#include <net_processing.h>
#include <node/blockstorage.h>
#include <node/chainstate.h>
#include <node/context.h>
+#include <node/mempool_args.h>
#include <node/miner.h>
+#include <node/validation_cache_args.h>
#include <noui.h>
#include <policy/fees.h>
#include <policy/fees_args.h>
@@ -52,6 +55,8 @@
#include <functional>
#include <stdexcept>
+using kernel::ValidationCacheSizes;
+using node::ApplyArgsManOptions;
using node::BlockAssembler;
using node::CalculateCacheSizes;
using node::LoadChainstate;
@@ -133,8 +138,12 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
m_node.kernel = std::make_unique<kernel::Context>();
SetupEnvironment();
SetupNetworking();
- InitSignatureCache();
- InitScriptExecutionCache();
+
+ ValidationCacheSizes validation_cache_sizes{};
+ ApplyArgsManOptions(*m_node.args, validation_cache_sizes);
+ Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
+ Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
+
m_node.chain = interfaces::MakeChain(m_node);
fCheckBlockIndex = true;
static bool noui_connected = false;
@@ -160,7 +169,8 @@ CTxMemPool::Options MemPoolOptionsForTest(const NodeContext& node)
// chainparams.DefaultConsistencyChecks for tests
.check_ratio = 1,
};
- ApplyArgsManOptions(*node.args, mempool_opts);
+ const auto err{ApplyArgsManOptions(*node.args, ::Params(), mempool_opts)};
+ Assert(!err);
return mempool_opts;
}
diff --git a/src/test/util/wallet.cpp b/src/test/util/wallet.cpp
index 7a00ac9e1f..b54774cbb9 100644
--- a/src/test/util/wallet.cpp
+++ b/src/test/util/wallet.cpp
@@ -8,6 +8,7 @@
#include <outputtype.h>
#include <script/standard.h>
#ifdef ENABLE_WALLET
+#include <util/check.h>
#include <util/translation.h>
#include <wallet/wallet.h>
#endif
@@ -20,10 +21,7 @@ const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqq
std::string getnewaddress(CWallet& w)
{
constexpr auto output_type = OutputType::BECH32;
- auto op_dest = w.GetNewDestination(output_type, "");
- assert(op_dest.HasRes());
-
- return EncodeDestination(op_dest.GetObj());
+ return EncodeDestination(*Assert(w.GetNewDestination(output_type, "")));
}
#endif // ENABLE_WALLET
diff --git a/src/timedata.h b/src/timedata.h
index ed2d8639f7..cfe5111644 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -76,7 +76,6 @@ public:
/** Functions to keep track of adjusted P2P time */
int64_t GetTimeOffset();
int64_t GetAdjustedTime();
-inline NodeSeconds AdjustedTime() { return Now<NodeSeconds>() + std::chrono::seconds{GetTimeOffset()}; }
void AddTimeData(const CNetAddr& ip, int64_t nTime);
/**
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 7eff6bdbe3..b151953d0d 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -106,7 +106,7 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp)
size_t CTxMemPoolEntry::GetTxSize() const
{
- return GetVirtualTransactionSize(nTxWeight, sigOpCost);
+ return GetVirtualTransactionSize(nTxWeight, sigOpCost, ::nBytesPerSigOp);
}
void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants,
@@ -458,6 +458,12 @@ CTxMemPool::CTxMemPool(const Options& opts)
minerPolicyEstimator{opts.estimator},
m_max_size_bytes{opts.max_size_bytes},
m_expiry{opts.expiry},
+ m_incremental_relay_feerate{opts.incremental_relay_feerate},
+ m_min_relay_feerate{opts.min_relay_feerate},
+ m_dust_relay_feerate{opts.dust_relay_feerate},
+ m_permit_bare_multisig{opts.permit_bare_multisig},
+ m_max_datacarrier_bytes{opts.max_datacarrier_bytes},
+ m_require_standard{opts.require_standard},
m_full_rbf{opts.full_rbf},
m_limits{opts.limits}
{
@@ -1117,12 +1123,12 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
lastRollingFeeUpdate = time;
- if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) {
+ if (rollingMinimumFeeRate < (double)m_incremental_relay_feerate.GetFeePerK() / 2) {
rollingMinimumFeeRate = 0;
return CFeeRate(0);
}
}
- return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee);
+ return std::max(CFeeRate(llround(rollingMinimumFeeRate)), m_incremental_relay_feerate);
}
void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
@@ -1146,7 +1152,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
// to have 0 fee). This way, we don't allow txn to enter mempool with feerate
// equal to txn which were removed with no block in between.
CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
- removed += incrementalRelayFee;
+ removed += m_incremental_relay_feerate;
trackPackageRemoved(removed);
maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
diff --git a/src/txmempool.h b/src/txmempool.h
index d7d308038c..73904cc370 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -568,6 +568,12 @@ public:
const int64_t m_max_size_bytes;
const std::chrono::seconds m_expiry;
+ const CFeeRate m_incremental_relay_feerate;
+ const CFeeRate m_min_relay_feerate;
+ const CFeeRate m_dust_relay_feerate;
+ const bool m_permit_bare_multisig;
+ const std::optional<unsigned> m_max_datacarrier_bytes;
+ const bool m_require_standard;
const bool m_full_rbf;
using Limits = kernel::MemPoolLimits;
@@ -702,11 +708,11 @@ public:
void CalculateDescendants(txiter it, setEntries& setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** The minimum fee to get into the mempool, which may itself not be enough
- * for larger-sized transactions.
- * The incrementalRelayFee policy variable is used to bound the time it
- * takes the fee rate to go back down all the way to 0. When the feerate
- * would otherwise be half of this, it is set to 0 instead.
- */
+ * for larger-sized transactions.
+ * The m_incremental_relay_feerate policy variable is used to bound the time it
+ * takes the fee rate to go back down all the way to 0. When the feerate
+ * would otherwise be half of this, it is set to 0 instead.
+ */
CFeeRate GetMinFee() const {
return GetMinFee(m_max_size_bytes);
}
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index 230a5fd096..8ba6fd5425 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -47,16 +47,16 @@ public:
void clear();
- bool setNull();
- bool setBool(bool val);
- bool setNumStr(const std::string& val);
- bool setInt(uint64_t val);
- bool setInt(int64_t val);
- bool setInt(int val_) { return setInt((int64_t)val_); }
- bool setFloat(double val);
- bool setStr(const std::string& val);
- bool setArray();
- bool setObject();
+ void setNull();
+ void setBool(bool val);
+ void setNumStr(const std::string& val);
+ void setInt(uint64_t val);
+ void setInt(int64_t val);
+ void setInt(int val_) { return setInt(int64_t{val_}); }
+ void setFloat(double val);
+ void setStr(const std::string& val);
+ void setArray();
+ void setObject();
enum VType getType() const { return typ; }
const std::string& getValStr() const { return val; }
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 051bc8eba6..55e777b8ae 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -23,19 +23,17 @@ void UniValue::clear()
values.clear();
}
-bool UniValue::setNull()
+void UniValue::setNull()
{
clear();
- return true;
}
-bool UniValue::setBool(bool val_)
+void UniValue::setBool(bool val_)
{
clear();
typ = VBOOL;
if (val_)
val = "1";
- return true;
}
static bool validNumStr(const std::string& s)
@@ -46,18 +44,18 @@ static bool validNumStr(const std::string& s)
return (tt == JTOK_NUMBER);
}
-bool UniValue::setNumStr(const std::string& val_)
+void UniValue::setNumStr(const std::string& val_)
{
- if (!validNumStr(val_))
- return false;
+ if (!validNumStr(val_)) {
+ throw std::runtime_error{"The string '" + val_ + "' is not a valid JSON number"};
+ }
clear();
typ = VNUM;
val = val_;
- return true;
}
-bool UniValue::setInt(uint64_t val_)
+void UniValue::setInt(uint64_t val_)
{
std::ostringstream oss;
@@ -66,7 +64,7 @@ bool UniValue::setInt(uint64_t val_)
return setNumStr(oss.str());
}
-bool UniValue::setInt(int64_t val_)
+void UniValue::setInt(int64_t val_)
{
std::ostringstream oss;
@@ -75,37 +73,32 @@ bool UniValue::setInt(int64_t val_)
return setNumStr(oss.str());
}
-bool UniValue::setFloat(double val_)
+void UniValue::setFloat(double val_)
{
std::ostringstream oss;
oss << std::setprecision(16) << val_;
- bool ret = setNumStr(oss.str());
- typ = VNUM;
- return ret;
+ return setNumStr(oss.str());
}
-bool UniValue::setStr(const std::string& val_)
+void UniValue::setStr(const std::string& val_)
{
clear();
typ = VSTR;
val = val_;
- return true;
}
-bool UniValue::setArray()
+void UniValue::setArray()
{
clear();
typ = VARR;
- return true;
}
-bool UniValue::setObject()
+void UniValue::setObject()
{
clear();
typ = VOBJ;
- return true;
}
void UniValue::push_back(const UniValue& val_)
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
index cf8c29ec67..94d7343ff3 100644
--- a/src/univalue/test/object.cpp
+++ b/src/univalue/test/object.cpp
@@ -45,7 +45,7 @@ void univalue_constructor()
BOOST_CHECK_EQUAL(v3.getValStr(), "foo");
UniValue numTest;
- BOOST_CHECK(numTest.setNumStr("82"));
+ numTest.setNumStr("82");
BOOST_CHECK(numTest.isNum());
BOOST_CHECK_EQUAL(numTest.getValStr(), "82");
@@ -93,33 +93,33 @@ void univalue_push_throw()
void univalue_typecheck()
{
UniValue v1;
- BOOST_CHECK(v1.setNumStr("1"));
+ v1.setNumStr("1");
BOOST_CHECK(v1.isNum());
BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);
{
UniValue v_negative;
- BOOST_CHECK(v_negative.setNumStr("-1"));
+ v_negative.setNumStr("-1");
BOOST_CHECK_THROW(v_negative.getInt<uint8_t>(), std::runtime_error);
BOOST_CHECK_EQUAL(v_negative.getInt<int8_t>(), -1);
}
UniValue v2;
- BOOST_CHECK(v2.setBool(true));
+ v2.setBool(true);
BOOST_CHECK_EQUAL(v2.get_bool(), true);
BOOST_CHECK_THROW(v2.getInt<int>(), std::runtime_error);
UniValue v3;
- BOOST_CHECK(v3.setNumStr("32482348723847471234"));
+ v3.setNumStr("32482348723847471234");
BOOST_CHECK_THROW(v3.getInt<int64_t>(), std::runtime_error);
- BOOST_CHECK(v3.setNumStr("1000"));
+ v3.setNumStr("1000");
BOOST_CHECK_EQUAL(v3.getInt<int64_t>(), 1000);
UniValue v4;
- BOOST_CHECK(v4.setNumStr("2147483648"));
+ v4.setNumStr("2147483648");
BOOST_CHECK_EQUAL(v4.getInt<int64_t>(), 2147483648);
BOOST_CHECK_THROW(v4.getInt<int>(), std::runtime_error);
- BOOST_CHECK(v4.setNumStr("1000"));
+ v4.setNumStr("1000");
BOOST_CHECK_EQUAL(v4.getInt<int>(), 1000);
BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);
BOOST_CHECK_EQUAL(v4.get_real(), 1000);
@@ -146,55 +146,55 @@ void univalue_set()
BOOST_CHECK(v.isNull());
BOOST_CHECK_EQUAL(v.getValStr(), "");
- BOOST_CHECK(v.setObject());
+ v.setObject();
BOOST_CHECK(v.isObject());
BOOST_CHECK_EQUAL(v.size(), 0);
BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
BOOST_CHECK(v.empty());
- BOOST_CHECK(v.setArray());
+ v.setArray();
BOOST_CHECK(v.isArray());
BOOST_CHECK_EQUAL(v.size(), 0);
- BOOST_CHECK(v.setStr("zum"));
+ v.setStr("zum");
BOOST_CHECK(v.isStr());
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
- BOOST_CHECK(v.setFloat(-1.01));
+ v.setFloat(-1.01);
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
- BOOST_CHECK(v.setInt((int)1023));
+ v.setInt(int{1023});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
- BOOST_CHECK(v.setInt((int64_t)-1023LL));
+ v.setInt(int64_t{-1023LL});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1023");
- BOOST_CHECK(v.setInt((uint64_t)1023ULL));
+ v.setInt(uint64_t{1023ULL});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
- BOOST_CHECK(v.setNumStr("-688"));
+ v.setNumStr("-688");
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-688");
- BOOST_CHECK(v.setBool(false));
+ v.setBool(false);
BOOST_CHECK_EQUAL(v.isBool(), true);
BOOST_CHECK_EQUAL(v.isTrue(), false);
BOOST_CHECK_EQUAL(v.isFalse(), true);
BOOST_CHECK_EQUAL(v.getBool(), false);
- BOOST_CHECK(v.setBool(true));
+ v.setBool(true);
BOOST_CHECK_EQUAL(v.isBool(), true);
BOOST_CHECK_EQUAL(v.isTrue(), true);
BOOST_CHECK_EQUAL(v.isFalse(), false);
BOOST_CHECK_EQUAL(v.getBool(), true);
- BOOST_CHECK(!v.setNumStr("zombocom"));
+ BOOST_CHECK_THROW(v.setNumStr("zombocom"), std::runtime_error);
- BOOST_CHECK(v.setNull());
+ v.setNull();
BOOST_CHECK(v.isNull());
}
@@ -352,7 +352,7 @@ void univalue_object()
BOOST_CHECK_EQUAL(obj.size(), 0);
BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL);
- BOOST_CHECK_EQUAL(obj.setObject(), true);
+ obj.setObject();
UniValue uv;
uv.setInt(42);
obj.__pushKV("age", uv);
@@ -419,7 +419,7 @@ void univalue_readwrite()
BOOST_CHECK(!v.read("{} 42"));
}
-int main (int argc, char *argv[])
+int main(int argc, char* argv[])
{
univalue_constructor();
univalue_push_throw();
@@ -430,4 +430,3 @@ int main (int argc, char *argv[])
univalue_readwrite();
return 0;
}
-
diff --git a/src/util/result.h b/src/util/result.h
index 2f586a4c9b..972b1aada0 100644
--- a/src/util/result.h
+++ b/src/util/result.h
@@ -5,45 +5,80 @@
#ifndef BITCOIN_UTIL_RESULT_H
#define BITCOIN_UTIL_RESULT_H
+#include <attributes.h>
#include <util/translation.h>
#include <variant>
-/*
- * 'BResult' is a generic class useful for wrapping a return object
- * (in case of success) or propagating the error cause.
-*/
-template<class T>
-class BResult {
+namespace util {
+
+struct Error {
+ bilingual_str message;
+};
+
+//! The util::Result class provides a standard way for functions to return
+//! either error messages or result values.
+//!
+//! It is intended for high-level functions that need to report error strings to
+//! end users. Lower-level functions that don't need this error-reporting and
+//! only need error-handling should avoid util::Result and instead use standard
+//! classes like std::optional, std::variant, and std::tuple, or custom structs
+//! and enum types to return function results.
+//!
+//! Usage examples can be found in \example ../test/result_tests.cpp, but in
+//! general code returning `util::Result<T>` values is very similar to code
+//! returning `std::optional<T>` values. Existing functions returning
+//! `std::optional<T>` can be updated to return `util::Result<T>` and return
+//! error strings usually just replacing `return std::nullopt;` with `return
+//! util::Error{error_string};`.
+template <class T>
+class Result
+{
private:
std::variant<bilingual_str, T> m_variant;
-public:
- BResult() : m_variant{Untranslated("")} {}
- BResult(T obj) : m_variant{std::move(obj)} {}
- BResult(bilingual_str error) : m_variant{std::move(error)} {}
+ template <typename FT>
+ friend bilingual_str ErrorString(const Result<FT>& result);
- /* Whether the function succeeded or not */
- bool HasRes() const { return std::holds_alternative<T>(m_variant); }
+public:
+ Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
+ Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}
- /* In case of success, the result object */
- const T& GetObj() const {
- assert(HasRes());
- return std::get<T>(m_variant);
+ //! std::optional methods, so functions returning optional<T> can change to
+ //! return Result<T> with minimal changes to existing code, and vice versa.
+ bool has_value() const noexcept { return m_variant.index() == 1; }
+ const T& value() const LIFETIMEBOUND
+ {
+ assert(has_value());
+ return std::get<1>(m_variant);
}
- T ReleaseObj()
+ T& value() LIFETIMEBOUND
{
- assert(HasRes());
- return std::move(std::get<T>(m_variant));
+ assert(has_value());
+ return std::get<1>(m_variant);
}
-
- /* In case of failure, the error cause */
- const bilingual_str& GetError() const {
- assert(!HasRes());
- return std::get<bilingual_str>(m_variant);
+ template <class U>
+ T value_or(U&& default_value) const&
+ {
+ return has_value() ? value() : std::forward<U>(default_value);
}
-
- explicit operator bool() const { return HasRes(); }
+ template <class U>
+ T value_or(U&& default_value) &&
+ {
+ return has_value() ? std::move(value()) : std::forward<U>(default_value);
+ }
+ explicit operator bool() const noexcept { return has_value(); }
+ const T* operator->() const LIFETIMEBOUND { return &value(); }
+ const T& operator*() const LIFETIMEBOUND { return value(); }
+ T* operator->() LIFETIMEBOUND { return &value(); }
+ T& operator*() LIFETIMEBOUND { return value(); }
};
+template <typename T>
+bilingual_str ErrorString(const Result<T>& result)
+{
+ return result ? bilingual_str{} : std::get<0>(result.m_variant);
+}
+} // namespace util
+
#endif // BITCOIN_UTIL_RESULT_H
diff --git a/src/util/system.cpp b/src/util/system.cpp
index ce45fb2ed4..1953a9f836 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -522,7 +522,7 @@ bool ArgsManager::InitSettings(std::string& error)
bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const
{
- fs::path settings = GetPathArg("-settings", fs::path{BITCOIN_SETTINGS_FILENAME});
+ fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME);
if (settings.empty()) {
return false;
}
@@ -885,9 +885,9 @@ bool CheckDataDirOption()
return datadir.empty() || fs::is_directory(fs::absolute(datadir));
}
-fs::path GetConfigFile(const std::string& confPath)
+fs::path GetConfigFile(const fs::path& configuration_file_path)
{
- return AbsPathForConfigVal(fs::PathFromString(confPath), false);
+ return AbsPathForConfigVal(configuration_file_path, /*net_specific=*/false);
}
static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
@@ -971,17 +971,17 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
m_config_sections.clear();
}
- const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME);
- std::ifstream stream{GetConfigFile(confPath)};
+ const fs::path conf_path = GetPathArg("-conf", BITCOIN_CONF_FILENAME);
+ std::ifstream stream{GetConfigFile(conf_path)};
// not ok to have a config file specified that cannot be opened
if (IsArgSet("-conf") && !stream.good()) {
- error = strprintf("specified config file \"%s\" could not be opened.", confPath);
+ error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
return false;
}
// ok to not have a config file
if (stream.good()) {
- if (!ReadConfigStream(stream, confPath, error, ignore_invalid_keys)) {
+ if (!ReadConfigStream(stream, fs::PathToString(conf_path), error, ignore_invalid_keys)) {
return false;
}
// `-includeconf` cannot be included in the command line arguments except
@@ -1019,7 +1019,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
const size_t default_includes = add_includes({});
for (const std::string& conf_file_name : conf_file_names) {
- std::ifstream conf_file_stream{GetConfigFile(conf_file_name)};
+ std::ifstream conf_file_stream{GetConfigFile(fs::PathFromString(conf_file_name))};
if (conf_file_stream.good()) {
if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
return false;
diff --git a/src/util/system.h b/src/util/system.h
index fa03e88920..756e6642f2 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -97,7 +97,7 @@ bool TryCreateDirectories(const fs::path& p);
fs::path GetDefaultDataDir();
// Return true if -datadir option points to a valid directory or is not specified.
bool CheckDataDirOption();
-fs::path GetConfigFile(const std::string& confPath);
+fs::path GetConfigFile(const fs::path& configuration_file_path);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
diff --git a/src/validation.cpp b/src/validation.cpp
index 17211956f5..d30333f710 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -124,7 +124,6 @@ GlobalMutex g_best_block_mutex;
std::condition_variable g_best_block_cv;
uint256 g_best_block;
bool g_parallel_script_checks{false};
-bool fRequireStandard = true;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
@@ -647,8 +646,9 @@ private:
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
}
- if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
+ if (package_fee < m_pool.m_min_relay_feerate.GetFee(package_size)) {
+ return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met",
+ strprintf("%d < %d", package_fee, m_pool.m_min_relay_feerate.GetFee(package_size)));
}
return true;
}
@@ -700,8 +700,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
std::string reason;
- if (fRequireStandard && !IsStandardTx(tx, reason))
+ if (m_pool.m_require_standard && !IsStandardTx(tx, m_pool.m_max_datacarrier_bytes, m_pool.m_permit_bare_multisig, m_pool.m_dust_relay_feerate, reason)) {
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
+ }
// Do not work on transactions that are too small.
// A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes.
@@ -807,13 +808,14 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return false; // state filled in by CheckTxInputs
}
- if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
+ if (m_pool.m_require_standard && !AreInputsStandard(tx, m_view)) {
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
}
// Check for non-standard witnesses.
- if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, m_view))
+ if (tx.HasWitness() && m_pool.m_require_standard && !IsWitnessStandard(tx, m_view)) {
return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, "bad-witness-nonstandard");
+ }
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
@@ -840,7 +842,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
strprintf("%d", nSigOpsCost));
- // No individual transactions are allowed below minRelayTxFee and mempool min fee except from
+ // No individual transactions are allowed below the min relay feerate and mempool min feerate except from
// disconnected blocks and transactions in a package. Package transactions will be checked using
// package feerate later.
if (!bypass_limits && !args.m_package_feerates && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state)) return false;
@@ -958,7 +960,7 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
ws.m_conflicting_size += it->GetTxSize();
}
if (const auto err_string{PaysForRBF(ws.m_conflicting_fees, ws.m_modified_fees, ws.m_vsize,
- ::incrementalRelayFee, hash)}) {
+ m_pool.m_incremental_relay_feerate, hash)}) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
}
return true;
@@ -1654,7 +1656,8 @@ bool CScriptCheck::operator()() {
static CuckooCache::cache<uint256, SignatureCacheHasher> g_scriptExecutionCache;
static CSHA256 g_scriptExecutionCacheHasher;
-void InitScriptExecutionCache() {
+bool InitScriptExecutionCache(size_t max_size_bytes)
+{
// Setup the salted hasher
uint256 nonce = GetRandHash();
// We want the nonce to be 64 bytes long to force the hasher to process
@@ -1662,12 +1665,14 @@ void InitScriptExecutionCache() {
// just write our 32-byte entropy twice to fill the 64 bytes.
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
- // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
- // setup_bytes creates the minimum possible cache (2 elements).
- size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
- size_t nElems = g_scriptExecutionCache.setup_bytes(nMaxCacheSize);
- LogPrintf("Using %zu MiB out of %zu/2 requested for script execution cache, able to store %zu elements\n",
- (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
+
+ auto setup_results = g_scriptExecutionCache.setup_bytes(max_size_bytes);
+ if (!setup_results) return false;
+
+ const auto [num_elems, approx_size_bytes] = *setup_results;
+ LogPrintf("Using %zu MiB out of %zu MiB requested for script execution cache, able to store %zu elements\n",
+ approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
+ return true;
}
/**
@@ -2578,6 +2583,7 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr
CBlockIndex *pindexDelete = m_chain.Tip();
assert(pindexDelete);
+ assert(pindexDelete->pprev);
// Read block from disk.
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
CBlock& block = *pblock;
@@ -2625,7 +2631,7 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr
}
}
- m_chain.SetTip(pindexDelete->pprev);
+ m_chain.SetTip(*pindexDelete->pprev);
UpdateTip(pindexDelete->pprev);
// Let wallets know transactions went from 1-confirmed to
@@ -2739,7 +2745,7 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew
disconnectpool.removeForBlock(blockConnecting.vtx);
}
// Update m_chain & related variables.
- m_chain.SetTip(pindexNew);
+ m_chain.SetTip(*pindexNew);
UpdateTip(pindexNew);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
@@ -3887,7 +3893,7 @@ bool CChainState::LoadChainTip()
if (!pindex) {
return false;
}
- m_chain.SetTip(pindex);
+ m_chain.SetTip(*pindex);
PruneBlockIndexCandidates();
tip = m_chain.Tip();
@@ -4964,7 +4970,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
return false;
}
- snapshot_chainstate.m_chain.SetTip(snapshot_start_block);
+ snapshot_chainstate.m_chain.SetTip(*snapshot_start_block);
// The remainder of this function requires modifying data protected by cs_main.
LOCK(::cs_main);
diff --git a/src/validation.h b/src/validation.h
index 9fef69799b..ec9043ad7a 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -100,7 +100,6 @@ extern uint256 g_best_block;
* False indicates all script checking is done on the main threadMessageHandler thread.
*/
extern bool g_parallel_script_checks;
-extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
@@ -324,7 +323,7 @@ public:
};
/** Initializes the script-execution cache */
-void InitScriptExecutionCache();
+[[nodiscard]] bool InitScriptExecutionCache(size_t max_size_bytes);
/** Functions for validating blocks and updating the block tree */
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 3ae81456b6..c2b8082eae 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -221,11 +221,11 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
constexpr int RANDOM_CHANGE_POSITION = -1;
auto res = CreateTransaction(wallet, recipients, RANDOM_CHANGE_POSITION, new_coin_control, false);
if (!res) {
- errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + res.GetError());
+ errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + util::ErrorString(res));
return Result::WALLET_ERROR;
}
- const auto& txr = res.GetObj();
+ const auto& txr = *res;
// Write back new fee if successful
new_fee = txr.fee;
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index 6f81fa30a1..3514d018b7 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -87,7 +87,7 @@ CFeeRate GetDiscardRate(const CWallet& wallet)
CFeeRate discard_rate = wallet.chain().estimateSmartFee(highest_target, false /* conservative */);
// Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate);
- // Discard rate must be at least dustRelayFee
+ // Discard rate must be at least dust relay feerate
discard_rate = std::max(discard_rate, wallet.chain().relayDustFee());
return discard_rate;
}
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 5add128717..aea6d5534e 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -48,6 +48,8 @@ using interfaces::WalletTxStatus;
using interfaces::WalletValueMap;
namespace wallet {
+// All members of the classes in this namespace are intentionally public, as the
+// classes themselves are private.
namespace {
//! Construct wallet tx struct.
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
@@ -146,7 +148,7 @@ public:
void abortRescan() override { m_wallet->AbortRescan(); }
bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
std::string getWalletName() override { return m_wallet->GetName(); }
- BResult<CTxDestination> getNewDestination(const OutputType type, const std::string label) override
+ util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string label) override
{
LOCK(m_wallet->cs_wallet);
return m_wallet->GetNewDestination(type, label);
@@ -249,17 +251,17 @@ public:
LOCK(m_wallet->cs_wallet);
return m_wallet->ListLockedCoins(outputs);
}
- BResult<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients,
+ util::Result<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients,
const CCoinControl& coin_control,
bool sign,
int& change_pos,
CAmount& fee) override
{
LOCK(m_wallet->cs_wallet);
- const auto& res = CreateTransaction(*m_wallet, recipients, change_pos,
+ auto res = CreateTransaction(*m_wallet, recipients, change_pos,
coin_control, sign);
- if (!res) return res.GetError();
- const auto& txr = res.GetObj();
+ if (!res) return util::Error{util::ErrorString(res)};
+ const auto& txr = *res;
fee = txr.fee;
change_pos = txr.change_pos;
@@ -568,12 +570,12 @@ public:
options.require_existing = true;
return MakeWallet(m_context, LoadWallet(m_context, name, true /* load_on_start */, options, status, error, warnings));
}
- BResult<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override
+ util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override
{
DatabaseStatus status;
bilingual_str error;
- BResult<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
- if (!wallet) return error;
+ util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
+ if (!wallet) return util::Error{error};
return wallet;
}
std::string getWalletDir() override
diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp
index 2a6eb96871..148343a8b0 100644
--- a/src/wallet/rpc/addresses.cpp
+++ b/src/wallet/rpc/addresses.cpp
@@ -60,10 +60,10 @@ RPCHelpMan getnewaddress()
auto op_dest = pwallet->GetNewDestination(output_type, label);
if (!op_dest) {
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, op_dest.GetError().original);
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, util::ErrorString(op_dest).original);
}
- return EncodeDestination(op_dest.GetObj());
+ return EncodeDestination(*op_dest);
},
};
}
@@ -107,9 +107,9 @@ RPCHelpMan getrawchangeaddress()
auto op_dest = pwallet->GetNewChangeDestination(output_type);
if (!op_dest) {
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, op_dest.GetError().original);
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, util::ErrorString(op_dest).original);
}
- return EncodeDestination(op_dest.GetObj());
+ return EncodeDestination(*op_dest);
},
};
}
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index e27cb1139e..628bf3cc99 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -158,14 +158,14 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
constexpr int RANDOM_CHANGE_POSITION = -1;
auto res = CreateTransaction(wallet, recipients, RANDOM_CHANGE_POSITION, coin_control, true);
if (!res) {
- throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, res.GetError().original);
+ throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, util::ErrorString(res).original);
}
- const CTransactionRef& tx = res.GetObj().tx;
+ const CTransactionRef& tx = res->tx;
wallet.CommitTransaction(tx, std::move(map_value), {} /* orderForm */);
if (verbose) {
UniValue entry(UniValue::VOBJ);
entry.pushKV("txid", tx->GetHash().GetHex());
- entry.pushKV("fee_reason", StringForFeeReason(res.GetObj().fee_calc.reason));
+ entry.pushKV("fee_reason", StringForFeeReason(res->fee_calc.reason));
return entry;
}
return tx->GetHash().GetHex();
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 0fe8871152..eb275f9951 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -590,6 +590,117 @@ static RPCHelpMan upgradewallet()
};
}
+RPCHelpMan simulaterawtransaction()
+{
+ return RPCHelpMan{"simulaterawtransaction",
+ "\nCalculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
+ {
+ {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "An array of hex strings of raw transactions.\n",
+ {
+ {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
+ },
+ },
+ {"options", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED_NAMED_ARG, "Options",
+ {
+ {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
+ },
+ },
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
+ }
+ },
+ RPCExamples{
+ HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
+ + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
+ if (!rpc_wallet) return UniValue::VNULL;
+ const CWallet& wallet = *rpc_wallet;
+
+ RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ}, true);
+
+ LOCK(wallet.cs_wallet);
+
+ UniValue include_watchonly(UniValue::VNULL);
+ if (request.params[1].isObject()) {
+ UniValue options = request.params[1];
+ RPCTypeCheckObj(options,
+ {
+ {"include_watchonly", UniValueType(UniValue::VBOOL)},
+ },
+ true, true);
+
+ include_watchonly = options["include_watchonly"];
+ }
+
+ isminefilter filter = ISMINE_SPENDABLE;
+ if (ParseIncludeWatchonly(include_watchonly, wallet)) {
+ filter |= ISMINE_WATCH_ONLY;
+ }
+
+ const auto& txs = request.params[0].get_array();
+ CAmount changes{0};
+ std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
+ std::set<COutPoint> spent;
+
+ for (size_t i = 0; i < txs.size(); ++i) {
+ CMutableTransaction mtx;
+ if (!DecodeHexTx(mtx, txs[i].get_str(), /* try_no_witness */ true, /* try_witness */ true)) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
+ }
+
+ // Fetch previous transactions (inputs)
+ std::map<COutPoint, Coin> coins;
+ for (const CTxIn& txin : mtx.vin) {
+ coins[txin.prevout]; // Create empty map entry keyed by prevout.
+ }
+ wallet.chain().findCoins(coins);
+
+ // Fetch debit; we are *spending* these; if the transaction is signed and
+ // broadcast, we will lose everything in these
+ for (const auto& txin : mtx.vin) {
+ const auto& outpoint = txin.prevout;
+ if (spent.count(outpoint)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
+ }
+ if (new_utxos.count(outpoint)) {
+ changes -= new_utxos.at(outpoint);
+ new_utxos.erase(outpoint);
+ } else {
+ if (coins.at(outpoint).IsSpent()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
+ }
+ changes -= wallet.GetDebit(txin, filter);
+ }
+ spent.insert(outpoint);
+ }
+
+ // Iterate over outputs; we are *receiving* these, if the wallet considers
+ // them "mine"; if the transaction is signed and broadcast, we will receive
+ // everything in these
+ // Also populate new_utxos in case these are spent in later transactions
+
+ const auto& hash = mtx.GetHash();
+ for (size_t i = 0; i < mtx.vout.size(); ++i) {
+ const auto& txout = mtx.vout[i];
+ bool is_mine = 0 < (wallet.IsMine(txout) & filter);
+ changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
+ }
+ }
+
+ UniValue result(UniValue::VOBJ);
+ result.pushKV("balance_change", ValueFromAmount(changes));
+
+ return result;
+}
+ };
+}
+
// addresses
RPCHelpMan getaddressinfo();
RPCHelpMan getnewaddress();
@@ -721,6 +832,7 @@ Span<const CRPCCommand> GetWalletRPCCommands()
{"wallet", &setwalletflag},
{"wallet", &signmessage},
{"wallet", &signrawtransactionwithwallet},
+ {"wallet", &simulaterawtransaction},
{"wallet", &sendall},
{"wallet", &unloadwallet},
{"wallet", &upgradewallet},
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index a0efc4c063..1682ce2eef 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -21,10 +21,10 @@ namespace wallet {
//! Value for the first BIP 32 hardened derivation. Can be used as a bit mask and as a value. See BIP 32 for more details.
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
-BResult<CTxDestination> LegacyScriptPubKeyMan::GetNewDestination(const OutputType type)
+util::Result<CTxDestination> LegacyScriptPubKeyMan::GetNewDestination(const OutputType type)
{
if (LEGACY_OUTPUT_TYPES.count(type) == 0) {
- return _("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types");;
+ return util::Error{_("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types")};
}
assert(type != OutputType::BECH32M);
@@ -33,7 +33,7 @@ BResult<CTxDestination> LegacyScriptPubKeyMan::GetNewDestination(const OutputTyp
// Generate a new key that is added to wallet
CPubKey new_key;
if (!GetKeyFromPool(new_key, type)) {
- return _("Error: Keypool ran out, please call keypoolrefill first");
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
LearnRelatedScripts(new_key, type);
return GetDestinationForKey(new_key, type);
@@ -1654,11 +1654,11 @@ std::set<CKeyID> LegacyScriptPubKeyMan::GetKeys() const
return set_address;
}
-BResult<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type)
+util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type)
{
// Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later
if (!CanGetAddresses()) {
- return _("No addresses available");
+ return util::Error{_("No addresses available")};
}
{
LOCK(cs_desc_man);
@@ -1676,11 +1676,11 @@ BResult<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const Outpu
std::vector<CScript> scripts_temp;
if (m_wallet_descriptor.range_end <= m_max_cached_index && !TopUp(1)) {
// We can't generate anymore keys
- return _("Error: Keypool ran out, please call keypoolrefill first");
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
if (!m_wallet_descriptor.descriptor->ExpandFromCache(m_wallet_descriptor.next_index, m_wallet_descriptor.cache, scripts_temp, out_keys)) {
// We can't generate anymore keys
- return _("Error: Keypool ran out, please call keypoolrefill first");
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
CTxDestination dest;
@@ -1766,11 +1766,11 @@ bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bo
auto op_dest = GetNewDestination(type);
index = m_wallet_descriptor.next_index - 1;
if (op_dest) {
- address = op_dest.GetObj();
+ address = *op_dest;
} else {
- error = op_dest.GetError();
+ error = util::ErrorString(op_dest);
}
- return op_dest.HasRes();
+ return bool(op_dest);
}
void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, const CTxDestination& addr)
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index d0af09463b..afe5d9ea9f 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -172,7 +172,7 @@ protected:
public:
explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {}
virtual ~ScriptPubKeyMan() {};
- virtual BResult<CTxDestination> GetNewDestination(const OutputType type) { return Untranslated("Not supported"); }
+ virtual util::Result<CTxDestination> GetNewDestination(const OutputType type) { return util::Error{Untranslated("Not supported")}; }
virtual isminetype IsMine(const CScript& script) const { return ISMINE_NO; }
//! Check that the given decryption key is valid for this ScriptPubKeyMan, i.e. it decrypts all of the keys handled by it.
@@ -360,7 +360,7 @@ private:
public:
using ScriptPubKeyMan::ScriptPubKeyMan;
- BResult<CTxDestination> GetNewDestination(const OutputType type) override;
+ util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
isminetype IsMine(const CScript& script) const override;
bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override;
@@ -570,7 +570,7 @@ public:
mutable RecursiveMutex cs_desc_man;
- BResult<CTxDestination> GetNewDestination(const OutputType type) override;
+ util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
isminetype IsMine(const CScript& script) const override;
bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override;
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index cacefffe35..b359d3e19b 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -760,7 +760,7 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
}
}
-static BResult<CreatedTransactionResult> CreateTransactionInternal(
+static util::Result<CreatedTransactionResult> CreateTransactionInternal(
CWallet& wallet,
const std::vector<CRecipient>& vecSend,
int change_pos,
@@ -846,11 +846,11 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
// provided one
if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) {
- return strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB));
+ return util::Error{strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB))};
}
if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee) {
// eventually allow a fallback fee
- return _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
+ return util::Error{_("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.")};
}
// Calculate the cost of change
@@ -876,7 +876,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
}
if (IsDust(txout, wallet.chain().relayDustFee())) {
- return _("Transaction amount too small");
+ return util::Error{_("Transaction amount too small")};
}
txNew.vout.push_back(txout);
}
@@ -897,7 +897,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Choose coins to use
std::optional<SelectionResult> result = SelectCoins(wallet, available_coins, /*nTargetValue=*/selection_target, coin_control, coin_selection_params);
if (!result) {
- return _("Insufficient funds");
+ return util::Error{_("Insufficient funds")};
}
TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result->m_algo).c_str(), result->m_target, result->GetWaste(), result->GetSelectedValue());
@@ -912,7 +912,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
nChangePosInOut = rng_fast.randrange(txNew.vout.size() + 1);
}
else if ((unsigned int)nChangePosInOut > txNew.vout.size()) {
- return _("Transaction change output index out of range");
+ return util::Error{_("Transaction change output index out of range")};
}
assert(nChangePosInOut != -1);
@@ -939,7 +939,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
TxSize tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control);
int nBytes = tx_sizes.vsize;
if (nBytes == -1) {
- return _("Missing solving data for estimating transaction size");
+ return util::Error{_("Missing solving data for estimating transaction size")};
}
nFeeRet = coin_selection_params.m_effective_feerate.GetFee(nBytes);
@@ -999,9 +999,9 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Error if this output is reduced to be below dust
if (IsDust(txout, wallet.chain().relayDustFee())) {
if (txout.nValue < 0) {
- return _("The transaction amount is too small to pay the fee");
+ return util::Error{_("The transaction amount is too small to pay the fee")};
} else {
- return _("The transaction amount is too small to send after the fee has been deducted");
+ return util::Error{_("The transaction amount is too small to send after the fee has been deducted")};
}
}
}
@@ -1012,11 +1012,11 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Give up if change keypool ran out and change is required
if (scriptChange.empty() && nChangePosInOut != -1) {
- return error;
+ return util::Error{error};
}
if (sign && !wallet.SignTransaction(txNew)) {
- return _("Signing transaction failed");
+ return util::Error{_("Signing transaction failed")};
}
// Return the constructed transaction data.
@@ -1026,17 +1026,17 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
if ((sign && GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT) ||
(!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT))
{
- return _("Transaction too large");
+ return util::Error{_("Transaction too large")};
}
if (nFeeRet > wallet.m_default_max_tx_fee) {
- return TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
+ return util::Error{TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED)};
}
if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
if (!wallet.chain().checkChainLimits(tx)) {
- return _("Transaction has too long of a mempool chain");
+ return util::Error{_("Transaction has too long of a mempool chain")};
}
}
@@ -1055,7 +1055,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut, feeCalc);
}
-BResult<CreatedTransactionResult> CreateTransaction(
+util::Result<CreatedTransactionResult> CreateTransaction(
CWallet& wallet,
const std::vector<CRecipient>& vecSend,
int change_pos,
@@ -1063,28 +1063,26 @@ BResult<CreatedTransactionResult> CreateTransaction(
bool sign)
{
if (vecSend.empty()) {
- return _("Transaction must have at least one recipient");
+ return util::Error{_("Transaction must have at least one recipient")};
}
if (std::any_of(vecSend.cbegin(), vecSend.cend(), [](const auto& recipient){ return recipient.nAmount < 0; })) {
- return _("Transaction amounts must not be negative");
+ return util::Error{_("Transaction amounts must not be negative")};
}
LOCK(wallet.cs_wallet);
auto res = CreateTransactionInternal(wallet, vecSend, change_pos, coin_control, sign);
- TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), res.HasRes(),
- res ? res.GetObj().fee : 0, res ? res.GetObj().change_pos : 0);
+ TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), bool(res),
+ res ? res->fee : 0, res ? res->change_pos : 0);
if (!res) return res;
- const auto& txr_ungrouped = res.GetObj();
+ const auto& txr_ungrouped = *res;
// try with avoidpartialspends unless it's enabled already
if (txr_ungrouped.fee > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) {
TRACE1(coin_selection, attempting_aps_create_tx, wallet.GetName().c_str());
CCoinControl tmp_cc = coin_control;
tmp_cc.m_avoid_partial_spends = true;
- auto res_tx_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
- // Helper optional class for now
- std::optional<CreatedTransactionResult> txr_grouped{res_tx_grouped.HasRes() ? std::make_optional(res_tx_grouped.GetObj()) : std::nullopt};
+ auto txr_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
// if fee of this alternative one is within the range of the max fee, we use this one
const bool use_aps{txr_grouped.has_value() ? (txr_grouped->fee <= txr_ungrouped.fee + wallet.m_max_aps_fee) : false};
TRACE5(coin_selection, aps_create_tx_internal, wallet.GetName().c_str(), use_aps, txr_grouped.has_value(),
@@ -1092,7 +1090,7 @@ BResult<CreatedTransactionResult> CreateTransaction(
if (txr_grouped) {
wallet.WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n",
txr_ungrouped.fee, txr_grouped->fee, use_aps ? "grouped" : "non-grouped");
- if (use_aps) return res_tx_grouped;
+ if (use_aps) return txr_grouped;
}
}
return res;
@@ -1133,10 +1131,10 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
auto res = CreateTransaction(wallet, vecSend, nChangePosInOut, coinControl, false);
if (!res) {
- error = res.GetError();
+ error = util::ErrorString(res);
return false;
}
- const auto& txr = res.GetObj();
+ const auto& txr = *res;
CTransactionRef tx_new = txr.tx;
nFeeRet = txr.fee;
nChangePosInOut = txr.change_pos;
diff --git a/src/wallet/spend.h b/src/wallet/spend.h
index 96ecd690be..fdb5113ba4 100644
--- a/src/wallet/spend.h
+++ b/src/wallet/spend.h
@@ -155,7 +155,7 @@ struct CreatedTransactionResult
* selected by SelectCoins(); Also create the change output, when needed
* @note passing change_pos as -1 will result in setting a random position
*/
-BResult<CreatedTransactionResult> CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, int change_pos, const CCoinControl& coin_control, bool sign = true);
+util::Result<CreatedTransactionResult> CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, int change_pos, const CCoinControl& coin_control, bool sign = true);
/**
* Insert additional inputs into the transaction by
diff --git a/src/wallet/test/availablecoins_tests.cpp b/src/wallet/test/availablecoins_tests.cpp
index 01d24da981..3356128112 100644
--- a/src/wallet/test/availablecoins_tests.cpp
+++ b/src/wallet/test/availablecoins_tests.cpp
@@ -33,7 +33,7 @@ public:
constexpr int RANDOM_CHANGE_POSITION = -1;
auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, dummy);
BOOST_CHECK(res);
- tx = res.GetObj().tx;
+ tx = res->tx;
}
wallet->CommitTransaction(tx, {}, {});
CMutableTransaction blocktx;
@@ -57,7 +57,7 @@ public:
BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, AvailableCoinsTestingSetup)
{
CoinsResult available_coins;
- BResult<CTxDestination> dest;
+ util::Result<CTxDestination> dest{util::Error{}};
LOCK(wallet->cs_wallet);
// Verify our wallet has one usable coinbase UTXO before starting
@@ -75,28 +75,28 @@ BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, AvailableCoinsTestingSetup)
// Bech32m
dest = wallet->GetNewDestination(OutputType::BECH32M, "");
- BOOST_ASSERT(dest.HasRes());
- AddTx(CRecipient{{GetScriptForDestination(dest.GetObj())}, 1 * COIN, /*fSubtractFeeFromAmount=*/true});
+ BOOST_ASSERT(dest);
+ AddTx(CRecipient{{GetScriptForDestination(*dest)}, 1 * COIN, /*fSubtractFeeFromAmount=*/true});
available_coins = AvailableCoins(*wallet);
BOOST_CHECK_EQUAL(available_coins.bech32m.size(), 2U);
// Bech32
dest = wallet->GetNewDestination(OutputType::BECH32, "");
- BOOST_ASSERT(dest.HasRes());
- AddTx(CRecipient{{GetScriptForDestination(dest.GetObj())}, 2 * COIN, /*fSubtractFeeFromAmount=*/true});
+ BOOST_ASSERT(dest);
+ AddTx(CRecipient{{GetScriptForDestination(*dest)}, 2 * COIN, /*fSubtractFeeFromAmount=*/true});
available_coins = AvailableCoins(*wallet);
BOOST_CHECK_EQUAL(available_coins.bech32.size(), 2U);
// P2SH-SEGWIT
dest = wallet->GetNewDestination(OutputType::P2SH_SEGWIT, "");
- AddTx(CRecipient{{GetScriptForDestination(dest.GetObj())}, 3 * COIN, /*fSubtractFeeFromAmount=*/true});
+ AddTx(CRecipient{{GetScriptForDestination(*dest)}, 3 * COIN, /*fSubtractFeeFromAmount=*/true});
available_coins = AvailableCoins(*wallet);
BOOST_CHECK_EQUAL(available_coins.P2SH_segwit.size(), 2U);
// Legacy (P2PKH)
dest = wallet->GetNewDestination(OutputType::LEGACY, "");
- BOOST_ASSERT(dest.HasRes());
- AddTx(CRecipient{{GetScriptForDestination(dest.GetObj())}, 4 * COIN, /*fSubtractFeeFromAmount=*/true});
+ BOOST_ASSERT(dest);
+ AddTx(CRecipient{{GetScriptForDestination(*dest)}, 4 * COIN, /*fSubtractFeeFromAmount=*/true});
available_coins = AvailableCoins(*wallet);
BOOST_CHECK_EQUAL(available_coins.legacy.size(), 2U);
}
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index cd7fd3f4dd..a4a7216436 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -74,9 +74,7 @@ static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmoun
tx.vout.resize(nInput + 1);
tx.vout[nInput].nValue = nValue;
if (spendable) {
- auto op_dest = wallet.GetNewDestination(OutputType::BECH32, "");
- assert(op_dest.HasRes());
- tx.vout[nInput].scriptPubKey = GetScriptForDestination(op_dest.GetObj());
+ tx.vout[nInput].scriptPubKey = GetScriptForDestination(*Assert(wallet.GetNewDestination(OutputType::BECH32, "")));
}
uint256 txid = tx.GetHash();
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index 5c173773e4..5e9cd4001b 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -69,14 +69,13 @@ struct FuzzedWallet {
CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider)
{
auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
- BResult<CTxDestination> op_dest;
+ util::Result<CTxDestination> op_dest{util::Error{}};
if (fuzzed_data_provider.ConsumeBool()) {
op_dest = wallet->GetNewDestination(type, "");
} else {
op_dest = wallet->GetNewChangeDestination(type);
}
- assert(op_dest.HasRes());
- return GetScriptForDestination(op_dest.GetObj());
+ return GetScriptForDestination(*Assert(op_dest));
}
};
diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp
index 53c3b5d2ae..dc935a1a04 100644
--- a/src/wallet/test/spend_tests.cpp
+++ b/src/wallet/test/spend_tests.cpp
@@ -35,7 +35,7 @@ BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
coin_control.m_change_type = OutputType::LEGACY;
auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, coin_control);
BOOST_CHECK(res);
- const auto& txr = res.GetObj();
+ const auto& txr = *res;
BOOST_CHECK_EQUAL(txr.tx->vout.size(), 1);
BOOST_CHECK_EQUAL(txr.tx->vout[0].nValue, recipient.nAmount + leftover_input_amount - txr.fee);
BOOST_CHECK_GT(txr.fee, 0);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index ac87800293..199925b4b1 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -536,7 +536,7 @@ public:
constexpr int RANDOM_CHANGE_POSITION = -1;
auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, dummy);
BOOST_CHECK(res);
- tx = res.GetObj().tx;
+ tx = res->tx;
}
wallet->CommitTransaction(tx, {}, {});
CMutableTransaction blocktx;
@@ -859,5 +859,111 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup)
TestUnloadWallet(std::move(wallet));
}
+/** RAII class that provides access to a FailDatabase. Which fails if needed. */
+class FailBatch : public DatabaseBatch
+{
+private:
+ bool m_pass{true};
+ bool ReadKey(CDataStream&& key, CDataStream& value) override { return m_pass; }
+ bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) override { return m_pass; }
+ bool EraseKey(CDataStream&& key) override { return m_pass; }
+ bool HasKey(CDataStream&& key) override { return m_pass; }
+
+public:
+ explicit FailBatch(bool pass) : m_pass(pass) {}
+ void Flush() override {}
+ void Close() override {}
+
+ bool StartCursor() override { return true; }
+ bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override { return false; }
+ void CloseCursor() override {}
+ bool TxnBegin() override { return false; }
+ bool TxnCommit() override { return false; }
+ bool TxnAbort() override { return false; }
+};
+
+/** A dummy WalletDatabase that does nothing, only fails if needed.**/
+class FailDatabase : public WalletDatabase
+{
+public:
+ bool m_pass{true}; // false when this db should fail
+
+ void Open() override {};
+ void AddRef() override {}
+ void RemoveRef() override {}
+ bool Rewrite(const char* pszSkip=nullptr) override { return true; }
+ bool Backup(const std::string& strDest) const override { return true; }
+ void Close() override {}
+ void Flush() override {}
+ bool PeriodicFlush() override { return true; }
+ void IncrementUpdateCounter() override { ++nUpdateCounter; }
+ void ReloadDbEnv() override {}
+ std::string Filename() override { return "faildb"; }
+ std::string Format() override { return "faildb"; }
+ std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<FailBatch>(m_pass); }
+};
+
+/**
+ * Checks a wallet invalid state where the inputs (prev-txs) of a new arriving transaction are not marked dirty,
+ * while the transaction that spends them exist inside the in-memory wallet tx map (not stored on db due a db write failure).
+ */
+BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
+{
+ CWallet wallet(m_node.chain.get(), "", m_args, std::make_unique<FailDatabase>());
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet.SetupDescriptorScriptPubKeyMans();
+ }
+
+ // Add tx to wallet
+ const auto& op_dest = wallet.GetNewDestination(OutputType::BECH32M, "");
+ BOOST_ASSERT(op_dest);
+ const CTxDestination& dest = *op_dest;
+
+ CMutableTransaction mtx;
+ mtx.vout.push_back({COIN, GetScriptForDestination(dest)});
+ mtx.vin.push_back(CTxIn(g_insecure_rand_ctx.rand256(), 0));
+ const auto& tx_id_to_spend = wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInMempool{})->GetHash();
+
+ {
+ // Cache and verify available balance for the wtx
+ LOCK(wallet.cs_wallet);
+ const CWalletTx* wtx_to_spend = wallet.GetWalletTx(tx_id_to_spend);
+ BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *wtx_to_spend), 1 * COIN);
+ }
+
+ // Now the good case:
+ // 1) Add a transaction that spends the previously created transaction
+ // 2) Verify that the available balance of this new tx and the old one is updated (prev tx is marked dirty)
+
+ mtx.vin.clear();
+ mtx.vin.push_back(CTxIn(tx_id_to_spend, 0));
+ wallet.transactionAddedToMempool(MakeTransactionRef(mtx), 0);
+ const uint256& good_tx_id = mtx.GetHash();
+
+ {
+ // Verify balance update for the new tx and the old one
+ LOCK(wallet.cs_wallet);
+ const CWalletTx* new_wtx = wallet.GetWalletTx(good_tx_id);
+ BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *new_wtx), 1 * COIN);
+
+ // Now the old wtx
+ const CWalletTx* wtx_to_spend = wallet.GetWalletTx(tx_id_to_spend);
+ BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *wtx_to_spend), 0 * COIN);
+ }
+
+ // Now the bad case:
+ // 1) Make db always fail
+ // 2) Try to add a transaction that spends the previously created transaction and
+ // verify that we are not moving forward if the wallet cannot store it
+ static_cast<FailDatabase&>(wallet.GetDatabase()).m_pass = false;
+ mtx.vin.clear();
+ mtx.vin.push_back(CTxIn(good_tx_id, 0));
+ BOOST_CHECK_EXCEPTION(wallet.transactionAddedToMempool(MakeTransactionRef(mtx), 0),
+ std::runtime_error,
+ HasReason("DB error adding transaction to wallet, write failed"));
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 74650b8f3f..30ba95c3c1 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1136,7 +1136,13 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS
// Block disconnection override an abandoned tx as unconfirmed
// which means user may have to call abandontransaction again
TxState tx_state = std::visit([](auto&& s) -> TxState { return s; }, state);
- return AddToWallet(MakeTransactionRef(tx), tx_state, /*update_wtx=*/nullptr, /*fFlushOnClose=*/false, rescanning_old_block);
+ CWalletTx* wtx = AddToWallet(MakeTransactionRef(tx), tx_state, /*update_wtx=*/nullptr, /*fFlushOnClose=*/false, rescanning_old_block);
+ if (!wtx) {
+ // Can only be nullptr if there was a db write error (missing db, read-only db or a db engine internal writing error).
+ // As we only store arriving transaction in this process, and we don't want an inconsistent state, let's throw an error.
+ throw std::runtime_error("DB error adding transaction to wallet, write failed");
+ }
+ return true;
}
}
return false;
@@ -2332,24 +2338,24 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
return res;
}
-BResult<CTxDestination> CWallet::GetNewDestination(const OutputType type, const std::string label)
+util::Result<CTxDestination> CWallet::GetNewDestination(const OutputType type, const std::string label)
{
LOCK(cs_wallet);
auto spk_man = GetScriptPubKeyMan(type, false /* internal */);
if (!spk_man) {
- return strprintf(_("Error: No %s addresses available."), FormatOutputType(type));
+ return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};
}
spk_man->TopUp();
auto op_dest = spk_man->GetNewDestination(type);
if (op_dest) {
- SetAddressBook(op_dest.GetObj(), label, "receive");
+ SetAddressBook(*op_dest, label, "receive");
}
return op_dest;
}
-BResult<CTxDestination> CWallet::GetNewChangeDestination(const OutputType type)
+util::Result<CTxDestination> CWallet::GetNewChangeDestination(const OutputType type)
{
LOCK(cs_wallet);
@@ -2357,7 +2363,7 @@ BResult<CTxDestination> CWallet::GetNewChangeDestination(const OutputType type)
bilingual_str error;
ReserveDestination reservedest(this, type);
if (!reservedest.GetReservedDestination(dest, true, error)) {
- return error;
+ return util::Error{error};
}
reservedest.KeepDestination();
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index bf9a12c01b..801ac5533a 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -101,7 +101,7 @@ static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS{true};
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
//! -walletrbf default
-static const bool DEFAULT_WALLET_RBF = false;
+static const bool DEFAULT_WALLET_RBF = true;
static const bool DEFAULT_WALLETBROADCAST = true;
static const bool DEFAULT_DISABLE_WALLET = false;
static const bool DEFAULT_WALLETCROSSCHAIN = false;
@@ -507,6 +507,10 @@ public:
//! @return true if wtx is changed and needs to be saved to disk, otherwise false
using UpdateWalletTxFn = std::function<bool(CWalletTx& wtx, bool new_tx)>;
+ /**
+ * Add the transaction to the wallet, wrapping it up inside a CWalletTx
+ * @return the recently added wtx pointer or nullptr if there was a db write error.
+ */
CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false);
bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override;
@@ -668,8 +672,8 @@ public:
*/
void MarkDestinationsDirty(const std::set<CTxDestination>& destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- BResult<CTxDestination> GetNewDestination(const OutputType type, const std::string label);
- BResult<CTxDestination> GetNewChangeDestination(const OutputType type);
+ util::Result<CTxDestination> GetNewDestination(const OutputType type, const std::string label);
+ util::Result<CTxDestination> GetNewChangeDestination(const OutputType type);
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
diff --git a/test/README.md b/test/README.md
index 6ca7cc0016..7d4a26fb4e 100644
--- a/test/README.md
+++ b/test/README.md
@@ -95,12 +95,14 @@ Run all possible tests with
test/functional/test_runner.py --extended
```
-In order to run backwards compatibility tests, download the previous node binaries:
+In order to run backwards compatibility tests, first run:
```
-test/get_previous_releases.py -b v23.0 v22.0 v0.21.0 v0.20.1 v0.19.1 v0.18.1 v0.17.2 v0.16.3 v0.15.2 v0.14.3
+test/get_previous_releases.py -b
```
+to download the necessary previous release binaries.
+
By default, up to 4 tests will be run in parallel by test_runner. To specify
how many jobs to run, append `--jobs=n`
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 777f873f70..67cdc5ca32 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -1131,6 +1131,12 @@ def spenders_taproot_active():
tap = taproot_construct(pubs[0], scripts)
add_spender(spenders, "alwaysvalid/notsuccessx", tap=tap, leaf="op_success", inputs=[], standard=False, failure={"leaf": "normal"}) # err_msg differs based on opcode
+ # == Test case for https://github.com/bitcoin/bitcoin/issues/24765 ==
+
+ zero_fn = lambda h: bytes([0 for _ in range(32)])
+ tap = taproot_construct(pubs[0], [("leaf", CScript([pubs[1], OP_CHECKSIG, pubs[1], OP_CHECKSIGADD, OP_2, OP_EQUAL])), zero_fn])
+ add_spender(spenders, "case24765", tap=tap, leaf="leaf", inputs=[getter("sign"), getter("sign")], key=secs[1], no_fail=True)
+
# == Legacy tests ==
# Also add a few legacy spends into the mix, so that transactions which combine taproot and pre-taproot spends get tested too.
diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py
index 9522cd8c59..2235da702b 100755
--- a/test/functional/interface_usdt_net.py
+++ b/test/functional/interface_usdt_net.py
@@ -109,7 +109,7 @@ class NetTracepointTest(BitcoinTestFramework):
self.log.info(
"hook into the net:inbound_message and net:outbound_message tracepoints")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="net:inbound_message",
fn_name="trace_inbound_message")
ctx.enable_probe(probe="net:outbound_message",
diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py
index f48ff9699d..2280de1479 100755
--- a/test/functional/interface_usdt_utxocache.py
+++ b/test/functional/interface_usdt_utxocache.py
@@ -173,7 +173,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
invalid_tx.vin[0].prevout.hash = int(block_1_coinbase_txid, 16)
self.log.info("hooking into the utxocache:uncache tracepoint")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:uncache",
fn_name="trace_utxocache_uncache")
bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0)
@@ -238,7 +238,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
self.log.info(
"hook into the utxocache:add and utxocache:spent tracepoints")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:add", fn_name="trace_utxocache_add")
ctx.enable_probe(probe="utxocache:spent",
fn_name="trace_utxocache_spent")
@@ -334,7 +334,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
self.log.info("test the utxocache:flush tracepoint API")
self.log.info("hook into the utxocache:flush tracepoint")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:flush",
fn_name="trace_utxocache_flush")
bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0)
@@ -345,16 +345,17 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
# that the handle_* functions succeeded.
EXPECTED_HANDLE_FLUSH_SUCCESS = 3
handle_flush_succeeds = 0
- possible_cache_sizes = set()
- expected_flushes = []
+ expected_flushes = list()
def handle_utxocache_flush(_, data, __):
nonlocal handle_flush_succeeds
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheFlush)).contents
self.log.info(f"handle_utxocache_flush(): {event}")
- expected = expected_flushes.pop(0)
- assert_equal(expected["mode"], FLUSHMODE_NAME[event.mode])
- possible_cache_sizes.remove(event.size) # fails if size not in set
+ expected_flushes.remove({
+ "mode": FLUSHMODE_NAME[event.mode],
+ "for_prune": event.for_prune,
+ "size": event.size
+ })
# sanity checks only
assert(event.memory > 0)
assert(event.duration > 0)
@@ -363,20 +364,19 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
self.log.info("stop the node to flush the UTXO cache")
- UTXOS_IN_CACHE = 104 # might need to be changed if the eariler tests are modified
+ UTXOS_IN_CACHE = 2 # might need to be changed if the eariler tests are modified
# A node shutdown causes two flushes. One that flushes UTXOS_IN_CACHE
# UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the
# second flush, however it can happen that the order changes.
- possible_cache_sizes = {UTXOS_IN_CACHE, 0}
- flush_for_shutdown = {"mode": "ALWAYS", "for_prune": False}
- expected_flushes.extend([flush_for_shutdown, flush_for_shutdown])
+ expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": UTXOS_IN_CACHE})
+ expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": 0})
self.stop_node(0)
bpf.perf_buffer_poll(timeout=200)
+ bpf.cleanup()
self.log.info("check that we don't expect additional flushes")
assert_equal(0, len(expected_flushes))
- assert_equal(0, len(possible_cache_sizes))
self.log.info("restart the node with -prune")
self.start_node(0, ["-fastprune=1", "-prune=1"])
@@ -384,12 +384,17 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
BLOCKS_TO_MINE = 350
self.log.info(f"mine {BLOCKS_TO_MINE} blocks to be able to prune")
self.generate(self.wallet, BLOCKS_TO_MINE)
- # we added BLOCKS_TO_MINE coinbase UTXOs to the cache
- possible_cache_sizes = {BLOCKS_TO_MINE}
- expected_flushes.append(
- {"mode": "NONE", "for_prune": True, "size_fn": lambda x: x == BLOCKS_TO_MINE})
+
+ self.log.info("test the utxocache:flush tracepoint API with pruning")
+ self.log.info("hook into the utxocache:flush tracepoint")
+ ctx = USDT(pid=self.nodes[0].process.pid)
+ ctx.enable_probe(probe="utxocache:flush",
+ fn_name="trace_utxocache_flush")
+ bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0)
+ bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
self.log.info(f"prune blockchain to trigger a flush for pruning")
+ expected_flushes.append({"mode": "NONE", "for_prune": True, "size": 0})
self.nodes[0].pruneblockchain(315)
bpf.perf_buffer_poll(timeout=500)
@@ -398,7 +403,6 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
self.log.info(
f"check that we don't expect additional flushes and that the handle_* function succeeded")
assert_equal(0, len(expected_flushes))
- assert_equal(0, len(possible_cache_sizes))
assert_equal(EXPECTED_HANDLE_FLUSH_SUCCESS, handle_flush_succeeds)
diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py
index d11809273b..fb1a91b914 100755
--- a/test/functional/interface_usdt_validation.py
+++ b/test/functional/interface_usdt_validation.py
@@ -94,7 +94,7 @@ class ValidationTracepointTest(BitcoinTestFramework):
expected_blocks = list()
self.log.info("hook into the validation:block_connected tracepoint")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="validation:block_connected",
fn_name="trace_block_connected")
bpf = BPF(text=validation_blockconnected_program,
diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py
index 89a5c83826..1f12e93982 100755
--- a/test/functional/mempool_package_limits.py
+++ b/test/functional/mempool_package_limits.py
@@ -6,28 +6,16 @@
from decimal import Decimal
-from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import (
COIN,
- CTransaction,
- CTxInWitness,
- tx_from_hex,
WITNESS_SCALE_FACTOR,
)
-from test_framework.script import (
- CScript,
- OP_TRUE,
-)
from test_framework.util import (
assert_equal,
)
-from test_framework.wallet import (
- bulk_transaction,
- create_child_with_parents,
- make_chain,
- DEFAULT_FEE,
-)
+from test_framework.wallet import MiniWallet
class MempoolPackageLimitsTest(BitcoinTestFramework):
def set_test_params(self):
@@ -35,19 +23,10 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
self.setup_clean_chain = True
def run_test(self):
- self.log.info("Generate blocks to create UTXOs")
- node = self.nodes[0]
- self.privkeys = [node.get_deterministic_priv_key().key]
- self.address = node.get_deterministic_priv_key().address
- self.coins = []
- # The last 100 coinbase transactions are premature
- for b in self.generatetoaddress(node, 200, self.address)[:100]:
- coinbase = node.getblock(blockhash=b, verbosity=2)["tx"][0]
- self.coins.append({
- "txid": coinbase["txid"],
- "amount": coinbase["vout"][0]["value"],
- "scriptPubKey": coinbase["vout"][0]["scriptPubKey"],
- })
+ self.wallet = MiniWallet(self.nodes[0])
+ # Add enough mature utxos to the wallet so that all txs spend confirmed coins.
+ self.generate(self.wallet, 35)
+ self.generate(self.nodes[0], COINBASE_MATURITY)
self.test_chain_limits()
self.test_desc_count_limits()
@@ -56,30 +35,22 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
self.test_anc_count_limits_2()
self.test_anc_count_limits_bushy()
- # The node will accept our (nonstandard) extra large OP_RETURN outputs
- self.restart_node(0, extra_args=["-acceptnonstdtxn=1"])
+ # The node will accept (nonstandard) extra large OP_RETURN outputs
+ self.restart_node(0, extra_args=["-datacarriersize=100000"])
self.test_anc_size_limits()
self.test_desc_size_limits()
def test_chain_limits_helper(self, mempool_count, package_count):
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
- first_coin = self.coins.pop()
- spk = None
- txid = first_coin["txid"]
chain_hex = []
- chain_txns = []
- value = first_coin["amount"]
-
- for i in range(mempool_count + package_count):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- if i < mempool_count:
- node.sendrawtransaction(txhex)
- assert_equal(node.getmempoolentry(txid)["ancestorcount"], i + 1)
- else:
- chain_hex.append(txhex)
- chain_txns.append(tx)
+
+ chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count)
+ # in-package transactions
+ for _ in range(package_count):
+ tx = self.wallet.create_self_transfer(utxo_to_spend=chaintip_utxo)
+ chaintip_utxo = tx["new_utxo"]
+ chain_hex.append(tx["hex"])
testres_too_long = node.testmempoolaccept(rawtxs=chain_hex)
for txres in testres_too_long:
assert_equal(txres["package-error"], "package-mempool-limits")
@@ -125,49 +96,20 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(0, node.getmempoolinfo()["size"])
self.log.info("Check that in-mempool and in-package descendants are calculated properly in packages")
# Top parent in mempool, M1
- first_coin = self.coins.pop()
- parent_value = (first_coin["amount"] - Decimal("0.0002")) / 2 # Deduct reasonable fee and make 2 outputs
- inputs = [{"txid": first_coin["txid"], "vout": 0}]
- outputs = [{self.address : parent_value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE : parent_value}]
- rawtx = node.createrawtransaction(inputs, outputs)
-
- parent_signed = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys)
- assert parent_signed["complete"]
- parent_tx = tx_from_hex(parent_signed["hex"])
- parent_txid = parent_tx.rehash()
- node.sendrawtransaction(parent_signed["hex"])
+ m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']
package_hex = []
-
- # Chain A
- spk = parent_tx.vout[0].scriptPubKey.hex()
- value = parent_value
- txid = parent_txid
- for i in range(12):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- if i < 11: # M2a... M12a
- node.sendrawtransaction(txhex)
- else: # Pa
- package_hex.append(txhex)
-
- # Chain B
- value = parent_value - Decimal("0.0001")
- rawtx_b = node.createrawtransaction([{"txid": parent_txid, "vout": 1}], {self.address : value})
- tx_child_b = tx_from_hex(rawtx_b) # M2b
- tx_child_b.wit.vtxinwit = [CTxInWitness()]
- tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
- tx_child_b_hex = tx_child_b.serialize().hex()
- node.sendrawtransaction(tx_child_b_hex)
- spk = tx_child_b.vout[0].scriptPubKey.hex()
- txid = tx_child_b.rehash()
- for i in range(12):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- if i < 11: # M3b... M13b
- node.sendrawtransaction(txhex)
- else: # Pb
- package_hex.append(txhex)
+ # Chain A (M2a... M12a)
+ chain_a_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=11, utxo_to_spend=m1_utxos[0])
+ # Pa
+ pa_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_a_tip_utxo)["hex"]
+ package_hex.append(pa_hex)
+
+ # Chain B (M2b... M13b)
+ chain_b_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12, utxo_to_spend=m1_utxos[1])
+ # Pb
+ pb_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_b_tip_utxo)["hex"]
+ package_hex.append(pb_hex)
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
@@ -200,41 +142,18 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
node = self.nodes[0]
package_hex = []
# M1
- first_coin_a = self.coins.pop()
- parent_value = (first_coin_a["amount"] - DEFAULT_FEE) / 2 # Deduct reasonable fee and make 2 outputs
- inputs = [{"txid": first_coin_a["txid"], "vout": 0}]
- outputs = [{self.address : parent_value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE : parent_value}]
- rawtx = node.createrawtransaction(inputs, outputs)
-
- parent_signed = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys)
- assert parent_signed["complete"]
- parent_tx = tx_from_hex(parent_signed["hex"])
- parent_txid = parent_tx.rehash()
- node.sendrawtransaction(parent_signed["hex"])
+ m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']
# Chain M2...M24
- spk = parent_tx.vout[0].scriptPubKey.hex()
- value = parent_value
- txid = parent_txid
- for i in range(23): # M2...M24
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- node.sendrawtransaction(txhex)
+ self.wallet.send_self_transfer_chain(from_node=node, chain_length=23, utxo_to_spend=m1_utxos[0])
# P1
- value_p1 = (parent_value - DEFAULT_FEE)
- rawtx_p1 = node.createrawtransaction([{"txid": parent_txid, "vout": 1}], [{self.address : value_p1}])
- tx_child_p1 = tx_from_hex(rawtx_p1)
- tx_child_p1.wit.vtxinwit = [CTxInWitness()]
- tx_child_p1.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
- tx_child_p1_hex = tx_child_p1.serialize().hex()
- txid_child_p1 = tx_child_p1.rehash()
- package_hex.append(tx_child_p1_hex)
- tx_child_p1_spk = tx_child_p1.vout[0].scriptPubKey.hex()
+ p1_tx = self.wallet.create_self_transfer(utxo_to_spend=m1_utxos[1])
+ package_hex.append(p1_tx["hex"])
# P2
- (_, tx_child_p2_hex, _, _) = make_chain(node, self.address, self.privkeys, txid_child_p1, value_p1, 0, tx_child_p1_spk)
- package_hex.append(tx_child_p2_hex)
+ p2_tx = self.wallet.create_self_transfer(utxo_to_spend=p1_tx["new_utxo"])
+ package_hex.append(p2_tx["hex"])
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
@@ -266,32 +185,21 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
package_hex = []
- parents_tx = []
- values = []
- scripts = []
+ pc_parent_utxos = []
self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages")
# Two chains of 13 transactions each
for _ in range(2):
- spk = None
- top_coin = self.coins.pop()
- txid = top_coin["txid"]
- value = top_coin["amount"]
- for i in range(13):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- if i < 12:
- node.sendrawtransaction(txhex)
- else: # Save the 13th transaction for the package
- package_hex.append(txhex)
- parents_tx.append(tx)
- scripts.append(spk)
- values.append(value)
+ chain_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)
+ # Save the 13th transaction for the package
+ tx = self.wallet.create_self_transfer(utxo_to_spend=chain_tip_utxo)
+ package_hex.append(tx["hex"])
+ pc_parent_utxos.append(tx["new_utxo"])
# Child Pc
- child_hex = create_child_with_parents(node, self.address, self.privkeys, parents_tx, values, scripts)
- package_hex.append(child_hex)
+ pc_hex = self.wallet.create_self_transfer_multi(utxos_to_spend=pc_parent_utxos)["hex"]
+ package_hex.append(pc_hex)
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(3, len(package_hex))
@@ -321,45 +229,29 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
"""
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
- parents_tx = []
- values = []
- scripts = []
+ pc_parent_utxos = []
self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages")
# Two chains of 12 transactions each
for _ in range(2):
- spk = None
- top_coin = self.coins.pop()
- txid = top_coin["txid"]
- value = top_coin["amount"]
- for i in range(12):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- value -= Decimal("0.0001")
- node.sendrawtransaction(txhex)
- if i == 11:
- # last 2 transactions will be the parents of Pc
- parents_tx.append(tx)
- values.append(value)
- scripts.append(spk)
+ chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)
+ # last 2 transactions will be the parents of Pc
+ pc_parent_utxos.append(chaintip_utxo)
# Child Pc
- pc_hex = create_child_with_parents(node, self.address, self.privkeys, parents_tx, values, scripts)
- pc_tx = tx_from_hex(pc_hex)
- pc_value = sum(values) - Decimal("0.0002")
- pc_spk = pc_tx.vout[0].scriptPubKey.hex()
+ pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=pc_parent_utxos)
# Child Pd
- (_, pd_hex, _, _) = make_chain(node, self.address, self.privkeys, pc_tx.rehash(), pc_value, 0, pc_spk)
+ pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0])
assert_equal(24, node.getmempoolinfo()["size"])
- testres_too_long = node.testmempoolaccept(rawtxs=[pc_hex, pd_hex])
+ testres_too_long = node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])
for txres in testres_too_long:
assert_equal(txres["package-error"], "package-mempool-limits")
# Clear mempool and check that the package passes now
self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_hex, pd_hex])])
+ assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])])
def test_anc_count_limits_bushy(self):
"""Create a tree with 20 transactions in the mempool and 6 in the package:
@@ -375,31 +267,18 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
package_hex = []
- parent_txns = []
- parent_values = []
- scripts = []
+ pc_parent_utxos = []
for _ in range(5): # Make package transactions P0 ... P4
- gp_tx = []
- gp_values = []
- gp_scripts = []
+ pc_grandparent_utxos = []
for _ in range(4): # Make mempool transactions M(4i+1)...M(4i+4)
- parent_coin = self.coins.pop()
- value = parent_coin["amount"]
- txid = parent_coin["txid"]
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value)
- gp_tx.append(tx)
- gp_values.append(value)
- gp_scripts.append(spk)
- node.sendrawtransaction(txhex)
+ pc_grandparent_utxos.append(self.wallet.send_self_transfer(from_node=node)["new_utxo"])
# Package transaction Pi
- pi_hex = create_child_with_parents(node, self.address, self.privkeys, gp_tx, gp_values, gp_scripts)
- package_hex.append(pi_hex)
- pi_tx = tx_from_hex(pi_hex)
- parent_txns.append(pi_tx)
- parent_values.append(Decimal(pi_tx.vout[0].nValue) / COIN)
- scripts.append(pi_tx.vout[0].scriptPubKey.hex())
+ pi_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=pc_grandparent_utxos)
+ package_hex.append(pi_tx["hex"])
+ pc_parent_utxos.append(pi_tx["new_utxos"][0])
# Package transaction PC
- package_hex.append(create_child_with_parents(node, self.address, self.privkeys, parent_txns, parent_values, scripts))
+ pc_hex = self.wallet.create_self_transfer_multi(utxos_to_spend=pc_parent_utxos)["hex"]
+ package_hex.append(pc_hex)
assert_equal(20, node.getmempoolinfo()["size"])
assert_equal(6, len(package_hex))
@@ -424,51 +303,30 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
"""
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
- parents_tx = []
- values = []
- scripts = []
+ parent_utxos = []
target_weight = WITNESS_SCALE_FACTOR * 1000 * 30 # 30KvB
high_fee = Decimal("0.003") # 10 sats/vB
self.log.info("Check that in-mempool and in-package ancestor size limits are calculated properly in packages")
# Mempool transactions A and B
for _ in range(2):
- spk = None
- top_coin = self.coins.pop()
- txid = top_coin["txid"]
- value = top_coin["amount"]
- (tx, _, _, _) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk, high_fee)
- bulked_tx = bulk_transaction(tx, node, target_weight, self.privkeys)
- node.sendrawtransaction(bulked_tx.serialize().hex())
- parents_tx.append(bulked_tx)
- values.append(Decimal(bulked_tx.vout[0].nValue) / COIN)
- scripts.append(bulked_tx.vout[0].scriptPubKey.hex())
+ bulked_tx = self.wallet.create_self_transfer(target_weight=target_weight)
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=bulked_tx["hex"])
+ parent_utxos.append(bulked_tx["new_utxo"])
# Package transaction C
- small_pc_hex = create_child_with_parents(node, self.address, self.privkeys, parents_tx, values, scripts, high_fee)
- pc_tx = bulk_transaction(tx_from_hex(small_pc_hex), node, target_weight, self.privkeys)
- pc_value = Decimal(pc_tx.vout[0].nValue) / COIN
- pc_spk = pc_tx.vout[0].scriptPubKey.hex()
- pc_hex = pc_tx.serialize().hex()
+ pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=int(high_fee * COIN), target_weight=target_weight)
# Package transaction D
- (small_pd, _, val, spk) = make_chain(node, self.address, self.privkeys, pc_tx.rehash(), pc_value, 0, pc_spk, high_fee)
- prevtxs = [{
- "txid": pc_tx.rehash(),
- "vout": 0,
- "scriptPubKey": spk,
- "amount": val,
- }]
- pd_tx = bulk_transaction(small_pd, node, target_weight, self.privkeys, prevtxs)
- pd_hex = pd_tx.serialize().hex()
+ pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_weight=target_weight)
assert_equal(2, node.getmempoolinfo()["size"])
- testres_too_heavy = node.testmempoolaccept(rawtxs=[pc_hex, pd_hex])
+ testres_too_heavy = node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])
for txres in testres_too_heavy:
assert_equal(txres["package-error"], "package-mempool-limits")
# Clear mempool and check that the package passes now
self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_hex, pd_hex])])
+ assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])])
def test_desc_size_limits(self):
"""Create 3 mempool transactions and 2 package transactions (25KvB each):
@@ -486,50 +344,18 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
high_fee = Decimal("0.0021") # 10 sats/vB
self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages")
# Top parent in mempool, Ma
- first_coin = self.coins.pop()
- parent_value = (first_coin["amount"] - high_fee) / 2 # Deduct fee and make 2 outputs
- inputs = [{"txid": first_coin["txid"], "vout": 0}]
- outputs = [{self.address : parent_value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE: parent_value}]
- rawtx = node.createrawtransaction(inputs, outputs)
- parent_tx = bulk_transaction(tx_from_hex(rawtx), node, target_weight, self.privkeys)
- node.sendrawtransaction(parent_tx.serialize().hex())
+ ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=int(high_fee / 2 * COIN), target_weight=target_weight)
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=ma_tx["hex"])
package_hex = []
for j in range(2): # Two legs (left and right)
# Mempool transaction (Mb and Mc)
- mempool_tx = CTransaction()
- spk = parent_tx.vout[j].scriptPubKey.hex()
- value = Decimal(parent_tx.vout[j].nValue) / COIN
- txid = parent_tx.rehash()
- prevtxs = [{
- "txid": txid,
- "vout": j,
- "scriptPubKey": spk,
- "amount": value,
- }]
- if j == 0: # normal key
- (tx_small, _, _, _) = make_chain(node, self.address, self.privkeys, txid, value, j, spk, high_fee)
- mempool_tx = bulk_transaction(tx_small, node, target_weight, self.privkeys, prevtxs)
- else: # OP_TRUE
- inputs = [{"txid": txid, "vout": 1}]
- outputs = {self.address: value - high_fee}
- small_tx = tx_from_hex(node.createrawtransaction(inputs, outputs))
- mempool_tx = bulk_transaction(small_tx, node, target_weight, None, prevtxs)
- node.sendrawtransaction(mempool_tx.serialize().hex())
+ mempool_tx = self.wallet.create_self_transfer(utxo_to_spend=ma_tx["new_utxos"][j], target_weight=target_weight)
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=mempool_tx["hex"])
# Package transaction (Pd and Pe)
- spk = mempool_tx.vout[0].scriptPubKey.hex()
- value = Decimal(mempool_tx.vout[0].nValue) / COIN
- txid = mempool_tx.rehash()
- (tx_small, _, _, _) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk, high_fee)
- prevtxs = [{
- "txid": txid,
- "vout": 0,
- "scriptPubKey": spk,
- "amount": value,
- }]
- package_tx = bulk_transaction(tx_small, node, target_weight, self.privkeys, prevtxs)
- package_hex.append(package_tx.serialize().hex())
+ package_tx = self.wallet.create_self_transfer(utxo_to_spend=mempool_tx["new_utxo"], target_weight=target_weight)
+ package_hex.append(package_tx["hex"])
assert_equal(3, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index 185011c2df..453a0920cc 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -111,7 +111,8 @@ class P2PPermissionsTests(BitcoinTestFramework):
'vout': 0,
}], outputs=[{
ADDRESS_BCRT1_P2WSH_OP_TRUE: 5,
- }]),
+ }],
+ replaceable=False),
)
tx.wit.vtxinwit = [CTxInWitness()]
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index db6954ccf6..311b0b67db 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -245,7 +245,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=P2P_SERVICES)
# self.old_node sets only NODE_NETWORK
self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
- # self.std_node is for testing node1 (fRequireStandard=true)
+ # self.std_node is for testing node1 (requires standard txs)
self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=P2P_SERVICES)
# self.std_wtx_node is for testing node1 with wtxid relay
self.std_wtx_node = self.nodes[1].add_p2p_connection(TestP2PConn(wtxidrelay=True), services=P2P_SERVICES)
@@ -1382,7 +1382,7 @@ class SegWitTest(BitcoinTestFramework):
tx3.vout.append(CTxOut(total_value - 1000, script_pubkey))
tx3.rehash()
- # First we test this transaction against fRequireStandard=true node
+ # First we test this transaction against std_node
# making sure the txid is added to the reject filter
self.std_node.announce_tx_and_wait_for_getdata(tx3)
test_transaction_acceptance(self.nodes[1], self.std_node, tx3, with_witness=True, accepted=False, reason="bad-txns-nonstandard-inputs")
@@ -1390,7 +1390,7 @@ class SegWitTest(BitcoinTestFramework):
self.std_node.announce_tx_and_wait_for_getdata(tx3, success=False)
# Spending a higher version witness output is not allowed by policy,
- # even with fRequireStandard=false.
+ # even with the node that accepts non-standard txs.
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False, reason="reserved for soft-fork upgrades")
# Building a block with the transaction must be valid, however.
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 23a581469e..43a73671a5 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -467,7 +467,7 @@ class PSBTTest(BitcoinTestFramework):
# Creator Tests
for creator in creators:
- created_tx = self.nodes[0].createpsbt(creator['inputs'], creator['outputs'])
+ created_tx = self.nodes[0].createpsbt(inputs=creator['inputs'], outputs=creator['outputs'], replaceable=False)
assert_equal(created_tx, creator['result'])
# Signer tests
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index fe61ff95f8..bfc835f272 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -29,6 +29,10 @@ logger = logging.getLogger("TestFramework.utils")
def assert_approx(v, vexp, vspan=0.00001):
"""Assert that `v` is within `vspan` of `vexp`"""
+ if isinstance(v, Decimal) or isinstance(vexp, Decimal):
+ v=Decimal(v)
+ vexp=Decimal(vexp)
+ vspan=Decimal(vspan)
if v < vexp - vspan:
raise AssertionError("%s < [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan)))
if v > vexp + vspan:
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 2164627781..374fda5c23 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -7,7 +7,6 @@
from copy import deepcopy
from decimal import Decimal
from enum import Enum
-from random import choice
from typing import (
Any,
List,
@@ -40,6 +39,7 @@ from test_framework.script import (
LegacySignatureHash,
LEAF_VERSION_TAPSCRIPT,
OP_NOP,
+ OP_RETURN,
OP_TRUE,
SIGHASH_ALL,
taproot_construct,
@@ -104,6 +104,18 @@ class MiniWallet:
def _create_utxo(self, *, txid, vout, value, height):
return {"txid": txid, "vout": vout, "value": value, "height": height}
+ def _bulk_tx(self, tx, target_weight):
+ """Pad a transaction with extra outputs until it reaches a target weight (or higher).
+ returns the tx
+ """
+ tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN, b'a'])))
+ dummy_vbytes = (target_weight - tx.get_weight() + 3) // 4
+ tx.vout[-1].scriptPubKey = CScript([OP_RETURN, b'a' * dummy_vbytes])
+ # Lower bound should always be off by at most 3
+ assert_greater_than_or_equal(tx.get_weight(), target_weight)
+ # Higher bound should always be off by at most 3 + 12 weight (for encoding the length)
+ assert_greater_than_or_equal(target_weight + 15, tx.get_weight())
+
def get_balance(self):
return sum(u['value'] for u in self._utxos)
@@ -235,6 +247,7 @@ class MiniWallet:
amount_per_output=0,
sequence=0,
fee_per_output=1000,
+ target_weight=0
):
"""
Create and return a transaction that spends the given UTXOs and creates a
@@ -265,6 +278,10 @@ class MiniWallet:
outputs_value_total = inputs_value_total - fee_per_output * num_outputs
for o in tx.vout:
o.nValue = amount_per_output or (outputs_value_total // num_outputs)
+
+ if target_weight:
+ self._bulk_tx(tx, target_weight)
+
txid = tx.rehash()
return {
"new_utxos": [self._create_utxo(
@@ -278,7 +295,7 @@ class MiniWallet:
"tx": tx,
}
- def create_self_transfer(self, *, fee_rate=Decimal("0.003"), fee=Decimal("0"), utxo_to_spend=None, locktime=0, sequence=0):
+ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), fee=Decimal("0"), utxo_to_spend=None, locktime=0, sequence=0, target_weight=0):
"""Create and return a tx with the specified fee. If fee is 0, use fee_rate, where the resulting fee may be exact or at most one satoshi higher than needed."""
utxo_to_spend = utxo_to_spend or self.get_utxo()
assert fee_rate >= 0
@@ -305,9 +322,13 @@ class MiniWallet:
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key]
else:
assert False
- tx_hex = tx.serialize().hex()
assert_equal(tx.get_vsize(), vsize)
+
+ if target_weight:
+ self._bulk_tx(tx, target_weight)
+
+ tx_hex = tx.serialize().hex()
new_utxo = self._create_utxo(txid=tx.rehash(), vout=0, value=send_value, height=0)
return {"txid": new_utxo["txid"], "wtxid": tx.getwtxid(), "hex": tx_hex, "tx": tx, "new_utxo": new_utxo}
@@ -317,6 +338,17 @@ class MiniWallet:
self.scan_tx(from_node.decoderawtransaction(tx_hex))
return txid
+ def send_self_transfer_chain(self, *, from_node, chain_length, utxo_to_spend=None):
+ """Create and send a "chain" of chain_length transactions. The nth transaction in
+ the chain is a child of the n-1th transaction and parent of the n+1th transaction.
+
+ Returns the chaintip (nth) utxo
+ """
+ chaintip_utxo = utxo_to_spend or self.get_utxo()
+ for _ in range(chain_length):
+ chaintip_utxo = self.send_self_transfer(utxo_to_spend=chaintip_utxo, from_node=from_node)["new_utxo"]
+ return chaintip_utxo
+
def getnewdestination(address_type='bech32m'):
"""Generate a random destination of the specified type and return the
@@ -409,23 +441,3 @@ def create_raw_chain(node, first_coin, address, privkeys, chain_length=25):
chain_txns.append(tx)
return (chain_hex, chain_txns)
-
-def bulk_transaction(tx, node, target_weight, privkeys, prevtxs=None):
- """Pad a transaction with extra outputs until it reaches a target weight (or higher).
- returns CTransaction object
- """
- tx_heavy = deepcopy(tx)
- assert_greater_than_or_equal(target_weight, tx_heavy.get_weight())
- while tx_heavy.get_weight() < target_weight:
- random_spk = "6a4d0200" # OP_RETURN OP_PUSH2 512 bytes
- for _ in range(512*2):
- random_spk += choice("0123456789ABCDEF")
- tx_heavy.vout.append(CTxOut(0, bytes.fromhex(random_spk)))
- # Re-sign the transaction
- if privkeys:
- signed = node.signrawtransactionwithkey(tx_heavy.serialize().hex(), privkeys, prevtxs)
- return tx_from_hex(signed["hex"])
- # OP_TRUE
- tx_heavy.wit.vtxinwit = [CTxInWitness()]
- tx_heavy.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
- return tx_heavy
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index e5784eb614..2b365d8d10 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -265,6 +265,8 @@ BASE_SCRIPTS = [
'wallet_implicitsegwit.py --legacy-wallet',
'rpc_named_arguments.py',
'feature_startupnotify.py',
+ 'wallet_simulaterawtx.py --legacy-wallet',
+ 'wallet_simulaterawtx.py --descriptors',
'wallet_listsinceblock.py --legacy-wallet',
'wallet_listsinceblock.py --descriptors',
'wallet_listdescriptors.py --descriptors',
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index f75877f256..7c16b6328d 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -25,7 +25,7 @@ class ListTransactionsTest(BitcoinTestFramework):
self.num_nodes = 3
# This test isn't testing txn relay/timing, so set whitelist on the
# peers for instant txn relay. This speeds up the test run time 2-3x.
- self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes
+ self.extra_args = [["-whitelist=noban@127.0.0.1", "-walletrbf=0"]] * self.num_nodes
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -146,7 +146,7 @@ class ListTransactionsTest(BitcoinTestFramework):
# Create tx2 using createrawtransaction
inputs = [{"txid": utxo_to_use["txid"], "vout": utxo_to_use["vout"]}]
outputs = {self.nodes[0].getnewaddress(): 0.999}
- tx2 = self.nodes[1].createrawtransaction(inputs, outputs)
+ tx2 = self.nodes[1].createrawtransaction(inputs=inputs, outputs=outputs, replaceable=False)
tx2_signed = self.nodes[1].signrawtransactionwithwallet(tx2)["hex"]
txid_2 = self.nodes[1].sendrawtransaction(tx2_signed)
@@ -178,7 +178,7 @@ class ListTransactionsTest(BitcoinTestFramework):
utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3)
inputs = [{"txid": txid_3, "vout": utxo_to_use["vout"]}]
outputs = {self.nodes[0].getnewaddress(): 0.997}
- tx4 = self.nodes[1].createrawtransaction(inputs, outputs)
+ tx4 = self.nodes[1].createrawtransaction(inputs=inputs, outputs=outputs, replaceable=False)
tx4_signed = self.nodes[1].signrawtransactionwithwallet(tx4)["hex"]
txid_4 = self.nodes[1].sendrawtransaction(tx4_signed)
diff --git a/test/functional/wallet_simulaterawtx.py b/test/functional/wallet_simulaterawtx.py
new file mode 100755
index 0000000000..a408b99515
--- /dev/null
+++ b/test/functional/wallet_simulaterawtx.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test simulaterawtransaction.
+"""
+
+from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_approx,
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+class SimulateTxTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def setup_network(self, split=False):
+ self.setup_nodes()
+
+ def run_test(self):
+ node = self.nodes[0]
+
+ self.generate(node, 1, sync_fun=self.no_op) # Leave IBD
+
+ node.createwallet(wallet_name='w0')
+ node.createwallet(wallet_name='w1')
+ node.createwallet(wallet_name='w2', disable_private_keys=True)
+ w0 = node.get_wallet_rpc('w0')
+ w1 = node.get_wallet_rpc('w1')
+ w2 = node.get_wallet_rpc('w2')
+
+ self.generatetoaddress(node, COINBASE_MATURITY + 1, w0.getnewaddress())
+ assert_equal(w0.getbalance(), 50.0)
+ assert_equal(w1.getbalance(), 0.0)
+
+ address1 = w1.getnewaddress()
+ address2 = w1.getnewaddress()
+
+ # Add address1 as watch-only to w2
+ w2.importpubkey(pubkey=w1.getaddressinfo(address1)["pubkey"])
+
+ tx1 = node.createrawtransaction([], [{address1: 5.0}])
+ tx2 = node.createrawtransaction([], [{address2: 10.0}])
+
+ # w0 should be unaffected, w2 should see +5 for tx1
+ assert_equal(w0.simulaterawtransaction([tx1])["balance_change"], 0.0)
+ assert_equal(w2.simulaterawtransaction([tx1])["balance_change"], 5.0)
+
+ # w1 should see +5 balance for tx1
+ assert_equal(w1.simulaterawtransaction([tx1])["balance_change"], 5.0)
+
+ # w0 should be unaffected, w2 should see +5 for both transactions
+ assert_equal(w0.simulaterawtransaction([tx1, tx2])["balance_change"], 0.0)
+ assert_equal(w2.simulaterawtransaction([tx1, tx2])["balance_change"], 5.0)
+
+ # w1 should see +15 balance for both transactions
+ assert_equal(w1.simulaterawtransaction([tx1, tx2])["balance_change"], 15.0)
+
+ # w0 funds transaction; it should now see a decrease in (tx fee and payment), and w1 should see the same as above
+ funding = w0.fundrawtransaction(tx1)
+ tx1 = funding["hex"]
+ tx1changepos = funding["changepos"]
+ bitcoin_fee = Decimal(funding["fee"])
+
+ # w0 sees fee + 5 btc decrease, w2 sees + 5 btc
+ assert_approx(w0.simulaterawtransaction([tx1])["balance_change"], -(Decimal("5") + bitcoin_fee))
+ assert_approx(w2.simulaterawtransaction([tx1])["balance_change"], Decimal("5"))
+
+ # w1 sees same as before
+ assert_equal(w1.simulaterawtransaction([tx1])["balance_change"], 5.0)
+
+ # same inputs (tx) more than once should error
+ assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w0.simulaterawtransaction, [tx1,tx1])
+
+ tx1ob = node.decoderawtransaction(tx1)
+ tx1hex = tx1ob["txid"]
+ tx1vout = 1 - tx1changepos
+ # tx3 spends new w1 UTXO paying to w0
+ tx3 = node.createrawtransaction([{"txid": tx1hex, "vout": tx1vout}], {w0.getnewaddress(): 4.9999})
+ # tx4 spends new w1 UTXO paying to w1
+ tx4 = node.createrawtransaction([{"txid": tx1hex, "vout": tx1vout}], {w1.getnewaddress(): 4.9999})
+
+ # on their own, both should fail due to missing input(s)
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx3])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx3])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx4])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx4])
+
+ # they should succeed when including tx1:
+ # wallet tx3 tx4
+ # w0 -5 - bitcoin_fee + 4.9999 -5 - bitcoin_fee
+ # w1 0 +4.9999
+ assert_approx(w0.simulaterawtransaction([tx1, tx3])["balance_change"], -Decimal("5") - bitcoin_fee + Decimal("4.9999"))
+ assert_approx(w1.simulaterawtransaction([tx1, tx3])["balance_change"], 0)
+ assert_approx(w0.simulaterawtransaction([tx1, tx4])["balance_change"], -Decimal("5") - bitcoin_fee)
+ assert_approx(w1.simulaterawtransaction([tx1, tx4])["balance_change"], Decimal("4.9999"))
+
+ # they should fail if attempting to include both tx3 and tx4
+ assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w0.simulaterawtransaction, [tx1, tx3, tx4])
+ assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w1.simulaterawtransaction, [tx1, tx3, tx4])
+
+ # send tx1 to avoid reusing same UTXO below
+ node.sendrawtransaction(w0.signrawtransactionwithwallet(tx1)["hex"])
+ self.generate(node, 1, sync_fun=self.no_op) # Confirm tx to trigger error below
+ self.sync_all()
+
+ # w0 funds transaction 2; it should now see a decrease in (tx fee and payment), and w1 should see the same as above
+ funding = w0.fundrawtransaction(tx2)
+ tx2 = funding["hex"]
+ bitcoin_fee2 = Decimal(funding["fee"])
+ assert_approx(w0.simulaterawtransaction([tx2])["balance_change"], -(Decimal("10") + bitcoin_fee2))
+ assert_approx(w1.simulaterawtransaction([tx2])["balance_change"], +(Decimal("10")))
+ assert_approx(w2.simulaterawtransaction([tx2])["balance_change"], 0)
+
+ # w0-w2 error due to tx1 already being mined
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx1, tx2])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx1, tx2])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w2.simulaterawtransaction, [tx1, tx2])
+
+if __name__ == '__main__':
+ SimulateTxTest().main()
diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py
index 7b7cfbfef5..c983dce619 100755
--- a/test/get_previous_releases.py
+++ b/test/get_previous_releases.py
@@ -20,66 +20,66 @@ import sys
import hashlib
SHA256_SUMS = {
- "0e2819135366f150d9906e294b61dff58fd1996ebd26c2f8e979d6c0b7a79580": "bitcoin-0.14.3-aarch64-linux-gnu.tar.gz",
- "d86fc90824a85c38b25c8488115178d5785dbc975f5ff674f9f5716bc8ad6e65": "bitcoin-0.14.3-arm-linux-gnueabihf.tar.gz",
- "1b0a7408c050e3d09a8be8e21e183ef7ee570385dc41216698cc3ab392a484e7": "bitcoin-0.14.3-osx64.tar.gz",
- "706e0472dbc933ed2757650d54cbcd780fd3829ebf8f609b32780c7eedebdbc9": "bitcoin-0.14.3-x86_64-linux-gnu.tar.gz",
+ "0e2819135366f150d9906e294b61dff58fd1996ebd26c2f8e979d6c0b7a79580": {"tag": "v0.14.3", "tarball": "bitcoin-0.14.3-aarch64-linux-gnu.tar.gz"},
+ "d86fc90824a85c38b25c8488115178d5785dbc975f5ff674f9f5716bc8ad6e65": {"tag": "v0.14.3", "tarball": "bitcoin-0.14.3-arm-linux-gnueabihf.tar.gz"},
+ "1b0a7408c050e3d09a8be8e21e183ef7ee570385dc41216698cc3ab392a484e7": {"tag": "v0.14.3", "tarball": "bitcoin-0.14.3-osx64.tar.gz"},
+ "706e0472dbc933ed2757650d54cbcd780fd3829ebf8f609b32780c7eedebdbc9": {"tag": "v0.14.3", "tarball": "bitcoin-0.14.3-x86_64-linux-gnu.tar.gz"},
#
- "d40f18b4e43c6e6370ef7db9131f584fbb137276ec2e3dba67a4b267f81cb644": "bitcoin-0.15.2-aarch64-linux-gnu.tar.gz",
- "54fb877a148a6ad189a1e1ab1ff8b11181e58ff2aaf430da55b3fd46ae549a6b": "bitcoin-0.15.2-arm-linux-gnueabihf.tar.gz",
- "87e9340ff3d382d543b2b69112376077f0c8b4f7450d372e83b68f5a1e22b2df": "bitcoin-0.15.2-osx64.tar.gz",
- "566be44190fd76daa01f13d428939dadfb8e3daacefc8fa17f433cad28f73bd5": "bitcoin-0.15.2-x86_64-linux-gnu.tar.gz",
+ "d40f18b4e43c6e6370ef7db9131f584fbb137276ec2e3dba67a4b267f81cb644": {"tag": "v0.15.2", "tarball": "bitcoin-0.15.2-aarch64-linux-gnu.tar.gz"},
+ "54fb877a148a6ad189a1e1ab1ff8b11181e58ff2aaf430da55b3fd46ae549a6b": {"tag": "v0.15.2", "tarball": "bitcoin-0.15.2-arm-linux-gnueabihf.tar.gz"},
+ "87e9340ff3d382d543b2b69112376077f0c8b4f7450d372e83b68f5a1e22b2df": {"tag": "v0.15.2", "tarball": "bitcoin-0.15.2-osx64.tar.gz"},
+ "566be44190fd76daa01f13d428939dadfb8e3daacefc8fa17f433cad28f73bd5": {"tag": "v0.15.2", "tarball": "bitcoin-0.15.2-x86_64-linux-gnu.tar.gz"},
#
- "0768c6c15caffbaca6524824c9563b42c24f70633c681c2744649158aa3fd484": "bitcoin-0.16.3-aarch64-linux-gnu.tar.gz",
- "fb2818069854a6ad20ea03b28b55dbd35d8b1f7d453e90b83eace5d0098a2a87": "bitcoin-0.16.3-arm-linux-gnueabihf.tar.gz",
- "78c3bff3b619a19aed575961ea43cc9e142959218835cf51aede7f0b764fc25d": "bitcoin-0.16.3-osx64.tar.gz",
- "5d422a9d544742bc0df12427383f9c2517433ce7b58cf672b9a9b17c2ef51e4f": "bitcoin-0.16.3-x86_64-linux-gnu.tar.gz",
+ "0768c6c15caffbaca6524824c9563b42c24f70633c681c2744649158aa3fd484": {"tag": "v0.16.3", "tarball": "bitcoin-0.16.3-aarch64-linux-gnu.tar.gz"},
+ "fb2818069854a6ad20ea03b28b55dbd35d8b1f7d453e90b83eace5d0098a2a87": {"tag": "v0.16.3", "tarball": "bitcoin-0.16.3-arm-linux-gnueabihf.tar.gz"},
+ "78c3bff3b619a19aed575961ea43cc9e142959218835cf51aede7f0b764fc25d": {"tag": "v0.16.3", "tarball": "bitcoin-0.16.3-osx64.tar.gz"},
+ "5d422a9d544742bc0df12427383f9c2517433ce7b58cf672b9a9b17c2ef51e4f": {"tag": "v0.16.3", "tarball": "bitcoin-0.16.3-x86_64-linux-gnu.tar.gz"},
#
- "5a6b35d1a348a402f2d2d6ab5aed653a1a1f13bc63aaaf51605e3501b0733b7a": "bitcoin-0.17.2-aarch64-linux-gnu.tar.gz",
- "d1913a5d19c8e8da4a67d1bd5205d03c8614dfd2e02bba2fe3087476643a729e": "bitcoin-0.17.2-arm-linux-gnueabihf.tar.gz",
- "a783ba20706dbfd5b47fbedf42165fce70fbbc7d78003305d964f6b3da14887f": "bitcoin-0.17.2-osx64.tar.gz",
- "943f9362b9f11130177839116f48f809d83478b4c28591d486ee9a7e35179da6": "bitcoin-0.17.2-x86_64-linux-gnu.tar.gz",
+ "5a6b35d1a348a402f2d2d6ab5aed653a1a1f13bc63aaaf51605e3501b0733b7a": {"tag": "v0.17.2", "tarball": "bitcoin-0.17.2-aarch64-linux-gnu.tar.gz"},
+ "d1913a5d19c8e8da4a67d1bd5205d03c8614dfd2e02bba2fe3087476643a729e": {"tag": "v0.17.2", "tarball": "bitcoin-0.17.2-arm-linux-gnueabihf.tar.gz"},
+ "a783ba20706dbfd5b47fbedf42165fce70fbbc7d78003305d964f6b3da14887f": {"tag": "v0.17.2", "tarball": "bitcoin-0.17.2-osx64.tar.gz"},
+ "943f9362b9f11130177839116f48f809d83478b4c28591d486ee9a7e35179da6": {"tag": "v0.17.2", "tarball": "bitcoin-0.17.2-x86_64-linux-gnu.tar.gz"},
#
- "88f343af72803b851c7da13874cc5525026b0b55e63e1b5e1298390c4688adc6": "bitcoin-0.18.1-aarch64-linux-gnu.tar.gz",
- "cc7d483e4b20c5dabd4dcaf304965214cf4934bcc029ca99cbc9af00d3771a1f": "bitcoin-0.18.1-arm-linux-gnueabihf.tar.gz",
- "b7bbcee7a7540f711b171d6981f939ca8482005fde22689bc016596d80548bb1": "bitcoin-0.18.1-osx64.tar.gz",
- "425ee5ec631ae8da71ebc1c3f5c0269c627cf459379b9b030f047107a28e3ef8": "bitcoin-0.18.1-riscv64-linux-gnu.tar.gz",
- "600d1db5e751fa85903e935a01a74f5cc57e1e7473c15fd3e17ed21e202cfe5a": "bitcoin-0.18.1-x86_64-linux-gnu.tar.gz",
+ "88f343af72803b851c7da13874cc5525026b0b55e63e1b5e1298390c4688adc6": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-aarch64-linux-gnu.tar.gz"},
+ "cc7d483e4b20c5dabd4dcaf304965214cf4934bcc029ca99cbc9af00d3771a1f": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-arm-linux-gnueabihf.tar.gz"},
+ "b7bbcee7a7540f711b171d6981f939ca8482005fde22689bc016596d80548bb1": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-osx64.tar.gz"},
+ "425ee5ec631ae8da71ebc1c3f5c0269c627cf459379b9b030f047107a28e3ef8": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-riscv64-linux-gnu.tar.gz"},
+ "600d1db5e751fa85903e935a01a74f5cc57e1e7473c15fd3e17ed21e202cfe5a": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-x86_64-linux-gnu.tar.gz"},
#
- "3a80431717842672df682bdb619e66523b59541483297772a7969413be3502ff": "bitcoin-0.19.1-aarch64-linux-gnu.tar.gz",
- "657f28213823d240dd3324d14829702f9ad6f0710f8bdd1c379cb3c447197f48": "bitcoin-0.19.1-arm-linux-gnueabihf.tar.gz",
- "1ae1b87de26487075cd2fd22e0d4ead87d969bd55c44f2f1d873ecdc6147ebb3": "bitcoin-0.19.1-osx64.tar.gz",
- "aa7a9563b48aa79252c8e7b6a41c07a5441bd9f14c5e4562cc72720ea6cb0ee5": "bitcoin-0.19.1-riscv64-linux-gnu.tar.gz",
- "5fcac9416e486d4960e1a946145566350ca670f9aaba99de6542080851122e4c": "bitcoin-0.19.1-x86_64-linux-gnu.tar.gz",
+ "3a80431717842672df682bdb619e66523b59541483297772a7969413be3502ff": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-aarch64-linux-gnu.tar.gz"},
+ "657f28213823d240dd3324d14829702f9ad6f0710f8bdd1c379cb3c447197f48": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-arm-linux-gnueabihf.tar.gz"},
+ "1ae1b87de26487075cd2fd22e0d4ead87d969bd55c44f2f1d873ecdc6147ebb3": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-osx64.tar.gz"},
+ "aa7a9563b48aa79252c8e7b6a41c07a5441bd9f14c5e4562cc72720ea6cb0ee5": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-riscv64-linux-gnu.tar.gz"},
+ "5fcac9416e486d4960e1a946145566350ca670f9aaba99de6542080851122e4c": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-x86_64-linux-gnu.tar.gz"},
#
- "60c93e3462c303eb080be7cf623f1a7684b37fd47a018ad3848bc23e13c84e1c": "bitcoin-0.20.1-aarch64-linux-gnu.tar.gz",
- "55b577e0fb306fb429d4be6c9316607753e8543e5946b542d75d876a2f08654c": "bitcoin-0.20.1-arm-linux-gnueabihf.tar.gz",
- "b9024dde373ea7dad707363e07ec7e265383204127539ae0c234bff3a61da0d1": "bitcoin-0.20.1-osx64.tar.gz",
- "fa71cb52ee5e0459cbf5248cdec72df27995840c796f58b304607a1ed4c165af": "bitcoin-0.20.1-riscv64-linux-gnu.tar.gz",
- "376194f06596ecfa40331167c39bc70c355f960280bd2a645fdbf18f66527397": "bitcoin-0.20.1-x86_64-linux-gnu.tar.gz",
+ "60c93e3462c303eb080be7cf623f1a7684b37fd47a018ad3848bc23e13c84e1c": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-aarch64-linux-gnu.tar.gz"},
+ "55b577e0fb306fb429d4be6c9316607753e8543e5946b542d75d876a2f08654c": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-arm-linux-gnueabihf.tar.gz"},
+ "b9024dde373ea7dad707363e07ec7e265383204127539ae0c234bff3a61da0d1": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-osx64.tar.gz"},
+ "fa71cb52ee5e0459cbf5248cdec72df27995840c796f58b304607a1ed4c165af": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-riscv64-linux-gnu.tar.gz"},
+ "376194f06596ecfa40331167c39bc70c355f960280bd2a645fdbf18f66527397": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-x86_64-linux-gnu.tar.gz"},
- "43416854330914992bbba2d0e9adf2a6fff4130be9af8ae2ef1186e743d9a3fe": "bitcoin-0.21.0-aarch64-linux-gnu.tar.gz",
- "f028af308eda45a3c4c90f9332f96b075bf21e3495c945ebce48597151808176": "bitcoin-0.21.0-arm-linux-gnueabihf.tar.gz",
- "695fb624fa6423f5da4f443b60763dd1d77488bfe5ef63760904a7b54e91298d": "bitcoin-0.21.0-osx64.tar.gz",
- "f8b2adfeae021a672effbc7bd40d5c48d6b94e53b2dd660f787340bf1a52e4e9": "bitcoin-0.21.0-riscv64-linux-gnu.tar.gz",
- "da7766775e3f9c98d7a9145429f2be8297c2672fe5b118fd3dc2411fb48e0032": "bitcoin-0.21.0-x86_64-linux-gnu.tar.gz",
+ "43416854330914992bbba2d0e9adf2a6fff4130be9af8ae2ef1186e743d9a3fe": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-aarch64-linux-gnu.tar.gz"},
+ "f028af308eda45a3c4c90f9332f96b075bf21e3495c945ebce48597151808176": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-arm-linux-gnueabihf.tar.gz"},
+ "695fb624fa6423f5da4f443b60763dd1d77488bfe5ef63760904a7b54e91298d": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-osx64.tar.gz"},
+ "f8b2adfeae021a672effbc7bd40d5c48d6b94e53b2dd660f787340bf1a52e4e9": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-riscv64-linux-gnu.tar.gz"},
+ "da7766775e3f9c98d7a9145429f2be8297c2672fe5b118fd3dc2411fb48e0032": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-x86_64-linux-gnu.tar.gz"},
- "ac718fed08570a81b3587587872ad85a25173afa5f9fbbd0c03ba4d1714cfa3e": "bitcoin-22.0-aarch64-linux-gnu.tar.gz",
- "b8713c6c5f03f5258b54e9f436e2ed6d85449aa24c2c9972f91963d413e86311": "bitcoin-22.0-arm-linux-gnueabihf.tar.gz",
- "2744d199c3343b2d94faffdfb2c94d75a630ba27301a70e47b0ad30a7e0155e9": "bitcoin-22.0-osx64.tar.gz",
- "2cca5f99007d060aca9d8c7cbd035dfe2f040dd8200b210ce32cdf858479f70d": "bitcoin-22.0-powerpc64-linux-gnu.tar.gz",
- "91b1e012975c5a363b5b5fcc81b5b7495e86ff703ec8262d4b9afcfec633c30d": "bitcoin-22.0-powerpc64le-linux-gnu.tar.gz",
- "9cc3a62c469fe57e11485fdd32c916f10ce7a2899299855a2e479256ff49ff3c": "bitcoin-22.0-riscv64-linux-gnu.tar.gz",
- "59ebd25dd82a51638b7a6bb914586201e67db67b919b2a1ff08925a7936d1b16": "bitcoin-22.0-x86_64-linux-gnu.tar.gz",
+ "ac718fed08570a81b3587587872ad85a25173afa5f9fbbd0c03ba4d1714cfa3e": {"tag": "v22.0", "tarball": "bitcoin-22.0-aarch64-linux-gnu.tar.gz"},
+ "b8713c6c5f03f5258b54e9f436e2ed6d85449aa24c2c9972f91963d413e86311": {"tag": "v22.0", "tarball": "bitcoin-22.0-arm-linux-gnueabihf.tar.gz"},
+ "2744d199c3343b2d94faffdfb2c94d75a630ba27301a70e47b0ad30a7e0155e9": {"tag": "v22.0", "tarball": "bitcoin-22.0-osx64.tar.gz"},
+ "2cca5f99007d060aca9d8c7cbd035dfe2f040dd8200b210ce32cdf858479f70d": {"tag": "v22.0", "tarball": "bitcoin-22.0-powerpc64-linux-gnu.tar.gz"},
+ "91b1e012975c5a363b5b5fcc81b5b7495e86ff703ec8262d4b9afcfec633c30d": {"tag": "v22.0", "tarball": "bitcoin-22.0-powerpc64le-linux-gnu.tar.gz"},
+ "9cc3a62c469fe57e11485fdd32c916f10ce7a2899299855a2e479256ff49ff3c": {"tag": "v22.0", "tarball": "bitcoin-22.0-riscv64-linux-gnu.tar.gz"},
+ "59ebd25dd82a51638b7a6bb914586201e67db67b919b2a1ff08925a7936d1b16": {"tag": "v22.0", "tarball": "bitcoin-22.0-x86_64-linux-gnu.tar.gz"},
- "06f4c78271a77752ba5990d60d81b1751507f77efda1e5981b4e92fd4d9969fb": "bitcoin-23.0-aarch64-linux-gnu.tar.gz",
- "952c574366aff76f6d6ad1c9ee45a361d64fa04155e973e926dfe7e26f9703a3": "bitcoin-23.0-arm-linux-gnueabihf.tar.gz",
- "7c8bc63731aa872b7b334a8a7d96e33536ad77d49029bad179b09dca32cd77ac": "bitcoin-23.0-arm64-apple-darwin.tar.gz",
- "2caa5898399e415f61d9af80a366a3008e5856efa15aaff74b88acf429674c99": "bitcoin-23.0-powerpc64-linux-gnu.tar.gz",
- "217dd0469d0f4962d22818c368358575f6a0abcba8804807bb75325eb2f28b19": "bitcoin-23.0-powerpc64le-linux-gnu.tar.gz",
- "078f96b1e92895009c798ab827fb3fde5f6719eee886bd0c0e93acab18ea4865": "bitcoin-23.0-riscv64-linux-gnu.tar.gz",
- "c816780583009a9dad426dc0c183c89be9da98906e1e2c7ebae91041c1aaaaf3": "bitcoin-23.0-x86_64-apple-darwin.tar.gz",
- "2cca490c1f2842884a3c5b0606f179f9f937177da4eadd628e3f7fd7e25d26d0": "bitcoin-23.0-x86_64-linux-gnu.tar.gz",
+ "06f4c78271a77752ba5990d60d81b1751507f77efda1e5981b4e92fd4d9969fb": {"tag": "v23.0", "tarball": "bitcoin-23.0-aarch64-linux-gnu.tar.gz"},
+ "952c574366aff76f6d6ad1c9ee45a361d64fa04155e973e926dfe7e26f9703a3": {"tag": "v23.0", "tarball": "bitcoin-23.0-arm-linux-gnueabihf.tar.gz"},
+ "7c8bc63731aa872b7b334a8a7d96e33536ad77d49029bad179b09dca32cd77ac": {"tag": "v23.0", "tarball": "bitcoin-23.0-arm64-apple-darwin.tar.gz"},
+ "2caa5898399e415f61d9af80a366a3008e5856efa15aaff74b88acf429674c99": {"tag": "v23.0", "tarball": "bitcoin-23.0-powerpc64-linux-gnu.tar.gz"},
+ "217dd0469d0f4962d22818c368358575f6a0abcba8804807bb75325eb2f28b19": {"tag": "v23.0", "tarball": "bitcoin-23.0-powerpc64le-linux-gnu.tar.gz"},
+ "078f96b1e92895009c798ab827fb3fde5f6719eee886bd0c0e93acab18ea4865": {"tag": "v23.0", "tarball": "bitcoin-23.0-riscv64-linux-gnu.tar.gz"},
+ "c816780583009a9dad426dc0c183c89be9da98906e1e2c7ebae91041c1aaaaf3": {"tag": "v23.0", "tarball": "bitcoin-23.0-x86_64-apple-darwin.tar.gz"},
+ "2cca490c1f2842884a3c5b0606f179f9f937177da4eadd628e3f7fd7e25d26d0": {"tag": "v23.0", "tarball": "bitcoin-23.0-x86_64-linux-gnu.tar.gz"},
}
@@ -135,7 +135,7 @@ def download_binary(tag, args) -> int:
hasher.update(afile.read())
tarballHash = hasher.hexdigest()
- if tarballHash not in SHA256_SUMS or SHA256_SUMS[tarballHash] != tarball:
+ if tarballHash not in SHA256_SUMS or SHA256_SUMS[tarballHash]['tarball'] != tarball:
if tarball in SHA256_SUMS.values():
print("Checksum did not match")
return 1
@@ -260,7 +260,12 @@ if __name__ == '__main__':
help='download release binary.')
parser.add_argument('-t', '--target-dir', action='store',
help='target directory.', default='releases')
- parser.add_argument('tags', nargs='+',
- help="release tags. e.g.: v0.18.1 v0.20.0rc2")
+ parser.add_argument('tags', nargs='*', default=set(
+ [v['tag'] for v in SHA256_SUMS.values()]
+ ),
+ help='release tags. e.g.: v0.18.1 v0.20.0rc2 '
+ '(if not specified, the full list needed for'
+ 'backwards compatibility tests will be used)'
+ )
args = parser.parse_args()
sys.exit(main(args))