aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml4
-rw-r--r--Makefile.am2
-rw-r--r--REVIEWERS (renamed from CODEOWNERS)23
-rw-r--r--ci/test/00_setup_env_arm.sh2
-rw-r--r--ci/test/00_setup_env_mac.sh2
-rw-r--r--ci/test/00_setup_env_mac_host.sh2
-rw-r--r--ci/test/00_setup_env_win64.sh4
-rwxr-xr-xci/test/06_script_a.sh5
-rw-r--r--configure.ac9
-rwxr-xr-xcontrib/devtools/gen-manpages.sh16
-rwxr-xr-xcontrib/devtools/test-symbol-check.py125
-rw-r--r--depends/packages/bdb.mk1
-rw-r--r--depends/packages/qt.mk3
-rw-r--r--doc/developer-notes.md27
-rw-r--r--doc/shared-libraries.md3
-rw-r--r--src/bitcoin-tx.cpp16
-rw-r--r--src/bitcoin-wallet.cpp23
-rw-r--r--src/bitcoind.cpp10
-rw-r--r--src/init.cpp43
-rw-r--r--src/init.h2
-rw-r--r--src/interfaces/node.h3
-rw-r--r--src/net.h6
-rw-r--r--src/net_processing.cpp2
-rw-r--r--src/node/coinstats.cpp2
-rw-r--r--src/node/context.cpp1
-rw-r--r--src/node/context.h2
-rw-r--r--src/node/interfaces.cpp15
-rw-r--r--src/policy/fees.cpp19
-rw-r--r--src/policy/fees.h3
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/rpc/blockchain.cpp10
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/mining.cpp36
-rw-r--r--src/rpc/rawtransaction.cpp15
-rw-r--r--src/rpc/rawtransaction_util.cpp2
-rw-r--r--src/rpc/rawtransaction_util.h2
-rw-r--r--src/script/sigcache.cpp2
-rw-r--r--src/test/addrman_tests.cpp2
-rw-r--r--src/test/fuzz/net.cpp23
-rw-r--r--src/test/net_tests.cpp2
-rw-r--r--src/test/util/setup_common.cpp4
-rw-r--r--src/test/util_tests.cpp2
-rw-r--r--src/util/check.h20
-rw-r--r--src/validation.cpp11
-rw-r--r--src/validation.h2
-rw-r--r--src/wallet/feebumper.cpp2
-rw-r--r--src/wallet/interfaces.cpp4
-rw-r--r--src/wallet/walletutil.cpp2
-rwxr-xr-xtest/functional/feature_fee_estimation.py6
-rwxr-xr-xtest/functional/feature_taproot.py4
-rwxr-xr-xtest/functional/rpc_estimatefee.py2
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py14
-rwxr-xr-xtest/functional/rpc_txoutproof.py2
-rwxr-xr-xtest/functional/wallet_balance.py2
-rwxr-xr-xtest/functional/wallet_importmulti.py2
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py1
-rwxr-xr-xtest/lint/lint-circular-dependencies.sh1
57 files changed, 398 insertions, 156 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 3a9e49b231..8fa2e52dde 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -107,7 +107,7 @@ task:
FILE_ENV: "./ci/test/00_setup_env_native_msan.sh"
task:
- name: '[no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer] [focal]'
+ name: '[no depends, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer] [focal]'
<< : *GLOBAL_TASK_TEMPLATE
container:
image: ubuntu:focal
@@ -115,7 +115,7 @@ task:
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
task:
- name: '[no depends, only system libs, sanitizers: fuzzer,address,undefined] [focal]'
+ name: '[no depends, sanitizers: fuzzer,address,undefined] [focal]'
<< : *GLOBAL_TASK_TEMPLATE
container:
image: ubuntu:focal
diff --git a/Makefile.am b/Makefile.am
index c8af4228f3..ce8bff0f9a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -353,10 +353,12 @@ clean-local: clean-docs
test-security-check:
if TARGET_DARWIN
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_MACHO
+ $(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_MACHO
endif
if TARGET_WINDOWS
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_PE
endif
if TARGET_LINUX
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_ELF
+ $(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF
endif
diff --git a/CODEOWNERS b/REVIEWERS
index 24a80fb35d..fa9a8f525f 100644
--- a/CODEOWNERS
+++ b/REVIEWERS
@@ -1,20 +1,15 @@
# ==============================================================================
-# Bitcoin Core CODEOWNERS
+# Bitcoin Core REVIEWERS
# ==============================================================================
-# Configuration of code ownership and review approvals for the bitcoin/bitcoin
-# repo.
+# Configuration of automated review requests for the bitcoin/bitcoin repo
+# via DrahtBot.
-# Order is important; the last matching pattern takes the most precedence.
-# More info on how this file works can be found at:
-# https://help.github.com/articles/about-codeowners/
+# Order is not important; if a modified file or directory matches a fnmatch,
+# the reviewer will be mentioned in a PR comment requesting a review.
-# This file is called CODEOWNERS because it is a magic file for GitHub to
-# automatically suggest reviewers. In this project's case, the names below
-# should be thought of as code reviewers rather than owners. Regular
-# contributors are free to add their names to specific directories or files
-# provided that they are willing to provide a review when automatically
-# assigned.
+# Regular contributors are free to add their names to specific directories or
+# files provided that they are willing to provide a review.
# Absence from this list should not be interpreted as a discouragement to
# review a pull request. Peer review is always welcome and is a critical
@@ -23,12 +18,12 @@
# Maintainers
-# @laanwj
-# @sipa
# @fanquake
# @jonasschnelli
+# @laanwj
# @marcofalke
# @meshcollider
+# @sipa
# Docs
/doc/*[a-zA-Z-].md @harding
diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh
index 610e55c4c3..42783197a9 100644
--- a/ci/test/00_setup_env_arm.sh
+++ b/ci/test/00_setup_env_arm.sh
@@ -25,4 +25,4 @@ export RUN_FUNCTIONAL_TESTS=false
export GOAL="install"
# -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1"
# This could be removed once the ABI change warning does not show up by default
-export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi --enable-werror --with-boost-process"
+export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi --with-boost-process"
diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh
index 4a022f9b39..5bda37d46d 100644
--- a/ci/test/00_setup_env_mac.sh
+++ b/ci/test/00_setup_env_mac.sh
@@ -15,4 +15,4 @@ export XCODE_BUILD_ID=11C505
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export GOAL="deploy"
-export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --enable-werror --with-boost-process"
+export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --with-boost-process"
diff --git a/ci/test/00_setup_env_mac_host.sh b/ci/test/00_setup_env_mac_host.sh
index 906f51fc1a..274a0d1b7c 100644
--- a/ci/test/00_setup_env_mac_host.sh
+++ b/ci/test/00_setup_env_mac_host.sh
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export HOST=x86_64-apple-darwin18
export PIP_PACKAGES="zmq"
export GOAL="install"
-export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --enable-werror --with-boost-process"
+export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --with-boost-process"
export CI_OS_NAME="macos"
export NO_DEPENDS=1
export OSX_SDK=""
diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh
index 72cc3f63c4..affaaaa1aa 100644
--- a/ci/test/00_setup_env_win64.sh
+++ b/ci/test/00_setup_env_win64.sh
@@ -14,3 +14,7 @@ export RUN_FUNCTIONAL_TESTS=false
export RUN_SECURITY_TESTS="true"
export GOAL="deploy"
export BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests --without-boost-process"
+
+# Compiler for MinGW-w64 causes false -Wreturn-type warning.
+# See https://sourceforge.net/p/mingw-w64/bugs/306/
+export NO_WERROR=1
diff --git a/ci/test/06_script_a.sh b/ci/test/06_script_a.sh
index 17d765b862..d99068cb10 100755
--- a/ci/test/06_script_a.sh
+++ b/ci/test/06_script_a.sh
@@ -6,7 +6,10 @@
export LC_ALL=C.UTF-8
-BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$DEPENDS_DIR/$HOST --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib"
+BITCOIN_CONFIG_ALL="--enable-suppress-external-warnings --disable-dependency-tracking --prefix=$DEPENDS_DIR/$HOST --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib"
+if [ -z "$NO_WERROR" ]; then
+ BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-werror"
+fi
DOCKER_EXEC "ccache --zero-stats --max-size=$CCACHE_SIZE"
BEGIN_FOLD autogen
diff --git a/configure.ac b/configure.ac
index e89d86df8b..32d1138653 100644
--- a/configure.ac
+++ b/configure.ac
@@ -348,6 +348,7 @@ if test "x$enable_debug" = xyes; then
AX_CHECK_PREPROC_FLAG([-DDEBUG],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG"]],,[[$CXXFLAG_WERROR]])
AX_CHECK_PREPROC_FLAG([-DDEBUG_LOCKORDER],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG_LOCKORDER"]],,[[$CXXFLAG_WERROR]])
+ AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"]],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-ftrapv],[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -ftrapv"],,[[$CXXFLAG_WERROR]])
fi
@@ -641,9 +642,9 @@ case $host in
dnl It's safe to add these paths even if the functionality is disabled by
dnl the user (--without-wallet or --without-gui for example).
- bdb_prefix=$($BREW --prefix berkeley-db4 2>/dev/null)
qt5_prefix=$($BREW --prefix qt5 2>/dev/null)
- if test x$bdb_prefix != x && test "x$BDB_CFLAGS" = "x" && test "x$BDB_LIBS" = "x" && test "$use_bdb" != "no"; then
+ if $BREW list --versions berkeley-db4 >/dev/null && test "x$BDB_CFLAGS" = "x" && test "x$BDB_LIBS" = "x" && test "$use_bdb" != "no"; then
+ bdb_prefix=$($BREW --prefix berkeley-db4 2>/dev/null)
dnl This must precede the call to BITCOIN_FIND_BDB48 below.
BDB_CFLAGS="-I$bdb_prefix/include"
BDB_LIBS="-L$bdb_prefix/lib -ldb_cxx-4.8"
@@ -1189,6 +1190,8 @@ if test "x$enable_fuzz" = "xyes"; then
use_upnp=no
use_zmq=no
+ AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"]],,[[$CXXFLAG_WERROR]])
+
AC_MSG_CHECKING([whether main function is needed])
AX_CHECK_LINK_FLAG(
[[-fsanitize=$use_sanitizers]],
@@ -1695,7 +1698,9 @@ AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])])
AC_CONFIG_LINKS([contrib/devtools/security-check.py:contrib/devtools/security-check.py])
+AC_CONFIG_LINKS([contrib/devtools/symbol-check.py:contrib/devtools/symbol-check.py])
AC_CONFIG_LINKS([contrib/devtools/test-security-check.py:contrib/devtools/test-security-check.py])
+AC_CONFIG_LINKS([contrib/devtools/test-symbol-check.py:contrib/devtools/test-symbol-check.py])
AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py])
AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py])
AC_CONFIG_LINKS([test/fuzz/test_runner.py:test/fuzz/test_runner.py])
diff --git a/contrib/devtools/gen-manpages.sh b/contrib/devtools/gen-manpages.sh
index aa65953d83..3fdcda4fd4 100755
--- a/contrib/devtools/gen-manpages.sh
+++ b/contrib/devtools/gen-manpages.sh
@@ -18,6 +18,22 @@ BITCOINQT=${BITCOINQT:-$BINDIR/qt/bitcoin-qt}
[ ! -x $BITCOIND ] && echo "$BITCOIND not found or not executable." && exit 1
+# Don't allow man pages to be generated for binaries built from a dirty tree
+DIRTY=""
+for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $WALLET_TOOL $BITCOINQT; do
+ VERSION_OUTPUT=$($cmd --version)
+ if [[ $VERSION_OUTPUT == *"dirty"* ]]; then
+ DIRTY="${DIRTY}${cmd}\n"
+ fi
+done
+if [ -n "$DIRTY" ]
+then
+ echo -e "WARNING: the following binaries were built from a dirty tree:\n"
+ echo -e $DIRTY
+ echo "man pages generated from dirty binaries should NOT be committed."
+ echo "To properly generate man pages, please commit your changes to the above binaries, rebuild them, then run this script again."
+fi
+
# The autodetected version git tag can screw up manpage output a little bit
read -r -a BTCVER <<< "$($BITCOINCLI --version | head -n1 | awk -F'[ -]' '{ print $6, $7 }')"
diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py
new file mode 100755
index 0000000000..b07ec2ffdf
--- /dev/null
+++ b/contrib/devtools/test-symbol-check.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 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 script for symbol-check.py
+'''
+import subprocess
+import unittest
+
+def call_symbol_check(cc, source, executable, options):
+ subprocess.run([cc,source,'-o',executable] + options, check=True)
+ p = subprocess.run(['./contrib/devtools/symbol-check.py',executable], stdout=subprocess.PIPE, universal_newlines=True)
+ return (p.returncode, p.stdout.rstrip())
+
+def get_machine(cc):
+ p = subprocess.run([cc,'-dumpmachine'], stdout=subprocess.PIPE, universal_newlines=True)
+ return p.stdout.rstrip()
+
+class TestSymbolChecks(unittest.TestCase):
+ def test_ELF(self):
+ source = 'test1.c'
+ executable = 'test1'
+ cc = 'gcc'
+
+ # there's no way to do this test for RISC-V at the moment; bionic's libc is 2.27
+ # and we allow all symbols from 2.27.
+ if 'riscv' in get_machine(cc):
+ self.skipTest("test not available for RISC-V")
+
+ # memfd_create was introduced in GLIBC 2.27, so is newer than the upper limit of
+ # all but RISC-V but still available on bionic
+ with open(source, 'w', encoding="utf8") as f:
+ f.write('''
+ #define _GNU_SOURCE
+ #include <sys/mman.h>
+
+ int memfd_create(const char *name, unsigned int flags);
+
+ int main()
+ {
+ memfd_create("test", 0);
+ return 0;
+ }
+ ''')
+
+ self.assertEqual(call_symbol_check(cc, source, executable, []),
+ (1, executable + ': symbol memfd_create from unsupported version GLIBC_2.27\n' +
+ executable + ': failed IMPORTED_SYMBOLS'))
+
+ # -lutil is part of the libc6 package so a safe bet that it's installed
+ # it's also out of context enough that it's unlikely to ever become a real dependency
+ source = 'test2.c'
+ executable = 'test2'
+ with open(source, 'w', encoding="utf8") as f:
+ f.write('''
+ #include <utmp.h>
+
+ int main()
+ {
+ login(0);
+ return 0;
+ }
+ ''')
+
+ self.assertEqual(call_symbol_check(cc, source, executable, ['-lutil']),
+ (1, executable + ': NEEDED library libutil.so.1 is not allowed\n' +
+ executable + ': failed LIBRARY_DEPENDENCIES'))
+
+ # finally, check a conforming file that simply uses a math function
+ source = 'test3.c'
+ executable = 'test3'
+ with open(source, 'w', encoding="utf8") as f:
+ f.write('''
+ #include <math.h>
+
+ int main()
+ {
+ return (int)pow(2.0, 4.0);
+ }
+ ''')
+
+ self.assertEqual(call_symbol_check(cc, source, executable, ['-lm']),
+ (0, ''))
+
+ def test_MACHO(self):
+ source = 'test1.c'
+ executable = 'test1'
+ cc = 'clang'
+
+ with open(source, 'w', encoding="utf8") as f:
+ f.write('''
+ #include <expat.h>
+
+ int main()
+ {
+ XML_ExpatVersion();
+ return 0;
+ }
+
+ ''')
+
+ self.assertEqual(call_symbol_check(cc, source, executable, ['-lexpat']),
+ (1, 'libexpat.1.dylib is not in ALLOWED_LIBRARIES!\n' +
+ executable + ': failed DYNAMIC_LIBRARIES'))
+
+ source = 'test2.c'
+ executable = 'test2'
+ with open(source, 'w', encoding="utf8") as f:
+ f.write('''
+ #include <CoreGraphics/CoreGraphics.h>
+
+ int main()
+ {
+ CGMainDisplayID();
+ return 0;
+ }
+ ''')
+
+ self.assertEqual(call_symbol_check(cc, source, executable, ['-framework', 'CoreGraphics']),
+ (0, ''))
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk
index 9e533cc61b..d45ac3d03f 100644
--- a/depends/packages/bdb.mk
+++ b/depends/packages/bdb.mk
@@ -10,6 +10,7 @@ define $(package)_set_vars
$(package)_config_opts=--disable-shared --enable-cxx --disable-replication --enable-option-checking
$(package)_config_opts_mingw32=--enable-mingw
$(package)_config_opts_linux=--with-pic
+$(package)_config_opts_android=--with-pic
$(package)_cflags+=-Wno-error=implicit-function-declaration
$(package)_cxxflags=-std=c++17
$(package)_cppflags_mingw32=-DUNICODE -D_UNICODE
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index df0cf5893f..9630df302f 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -128,6 +128,9 @@ $(package)_config_opts_darwin += -device-option MAC_TARGET=$(host)
$(package)_config_opts_darwin += -device-option XCODE_VERSION=$(XCODE_VERSION)
endif
+# for macOS on Apple Silicon (ARM) see https://bugreports.qt.io/browse/QTBUG-85279
+$(package)_config_opts_arm_darwin += -device-option QMAKE_APPLE_DEVICE_ARCHS=arm64
+
$(package)_config_opts_linux = -qt-xkbcommon-x11
$(package)_config_opts_linux += -qt-xcb
$(package)_config_opts_linux += -no-xcb-xlib
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index fa188dbcd6..9cb416bb30 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -276,6 +276,33 @@ configure option adds `-DDEBUG_LOCKORDER` to the compiler flags. This inserts
run-time checks to keep track of which locks are held and adds warnings to the
`debug.log` file if inconsistencies are detected.
+### Assertions and Checks
+
+The util file `src/util/check.h` offers helpers to protect against coding and
+internal logic bugs. They must never be used to validate user, network or any
+other input.
+
+* `assert` or `Assert` should be used to document assumptions when any
+ violation would mean that it is not safe to continue program execution. The
+ code is always compiled with assertions enabled.
+ - For example, a nullptr dereference or any other logic bug in validation
+ code means the program code is faulty and must terminate immediately.
+* `CHECK_NONFATAL` should be used for recoverable internal logic bugs. On
+ failure, it will throw an exception, which can be caught to recover from the
+ error.
+ - For example, a nullptr dereference or any other logic bug in RPC code
+ means that the RPC code is faulty and can not be executed. However, the
+ logic bug can be shown to the user and the program can continue to run.
+* `Assume` should be used to document assumptions when program execution can
+ safely continue even if the assumption is violated. In debug builds it
+ behaves like `Assert`/`assert` to notify developers and testers about
+ nonfatal errors. In production it doesn't warn or log anything, though the
+ expression is always evaluated.
+ - For example it can be assumed that a variable is only initialized once,
+ but a failed assumption does not result in a fatal bug. A failed
+ assumption may or may not result in a slightly degraded user experience,
+ but it is safe to continue program execution.
+
### Valgrind suppressions file
Valgrind is a programming tool for memory debugging, memory leak detection, and
diff --git a/doc/shared-libraries.md b/doc/shared-libraries.md
index e960863a80..147e223711 100644
--- a/doc/shared-libraries.md
+++ b/doc/shared-libraries.md
@@ -41,9 +41,10 @@ The interface is defined in the C header `bitcoinconsensus.h` located in `src/sc
- `bitcoinconsensus_ERR_TX_SIZE_MISMATCH` - `txToLen` did not match with the size of `txTo`
- `bitcoinconsensus_ERR_DESERIALIZE` - An error deserializing `txTo`
- `bitcoinconsensus_ERR_AMOUNT_REQUIRED` - Input amount is required if WITNESS is used
+- `bitcoinconsensus_ERR_INVALID_FLAGS` - Script verification `flags` are invalid (i.e. not part of the libconsensus interface)
### Example Implementations
-- [NBitcoin](https://github.com/NicolasDorier/NBitcoin/blob/master/NBitcoin/Script.cs#L814) (.NET Bindings)
+- [NBitcoin](https://github.com/MetacoSA/NBitcoin/blob/5e1055cd7c4186dee4227c344af8892aea54faec/NBitcoin/Script.cs#L979-#L1031) (.NET Bindings)
- [node-libbitcoinconsensus](https://github.com/bitpay/node-libbitcoinconsensus) (Node.js Bindings)
- [java-libbitcoinconsensus](https://github.com/dexX7/java-libbitcoinconsensus) (Java Bindings)
- [bitcoinconsensus-php](https://github.com/Bit-Wasp/bitcoinconsensus-php) (PHP Bindings)
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index e22b3766cf..f87b9c1d16 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -40,6 +40,7 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman)
{
SetupHelpOptions(argsman);
+ argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -95,13 +96,16 @@ static int AppInitRawTx(int argc, char* argv[])
fCreateBlank = gArgs.GetBoolArg("-create", false);
- if (argc < 2 || HelpRequested(gArgs)) {
+ if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
// First part of help message is specific to this utility
- std::string strUsage = PACKAGE_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n\n" +
- "Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction\n" +
- "or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction\n" +
- "\n";
- strUsage += gArgs.GetHelpMessage();
+ std::string strUsage = PACKAGE_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n";
+ if (!gArgs.IsArgSet("-version")) {
+ strUsage += "\n"
+ "Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction\n"
+ "or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction\n"
+ "\n";
+ strUsage += gArgs.GetHelpMessage();
+ }
tfm::format(std::cout, "%s", strUsage);
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index b9c2fe2d34..d258f9f933 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -24,6 +24,7 @@ static void SetupWalletToolArgs(ArgsManager& argsman)
SetupHelpOptions(argsman);
SetupChainParamsBaseOptions(argsman);
+ argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-wallet=<wallet-name>", "Specify wallet name", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS);
argsman.AddArg("-debug=<category>", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
@@ -42,16 +43,18 @@ static bool WalletAppInit(int argc, char* argv[])
tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error_message);
return false;
}
- if (argc < 2 || HelpRequested(gArgs)) {
- std::string usage = strprintf("%s bitcoin-wallet version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n\n" +
- "bitcoin-wallet is an offline tool for creating and interacting with " PACKAGE_NAME " wallet files.\n" +
- "By default bitcoin-wallet will act on wallets in the default mainnet wallet directory in the datadir.\n" +
- "To change the target wallet, use the -datadir, -wallet and -testnet/-regtest arguments.\n\n" +
- "Usage:\n" +
- " bitcoin-wallet [options] <command>\n\n" +
- gArgs.GetHelpMessage();
-
- tfm::format(std::cout, "%s", usage);
+ if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
+ std::string strUsage = strprintf("%s bitcoin-wallet version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n";
+ if (!gArgs.IsArgSet("-version")) {
+ strUsage += "\n"
+ "bitcoin-wallet is an offline tool for creating and interacting with " PACKAGE_NAME " wallet files.\n"
+ "By default bitcoin-wallet will act on wallets in the default mainnet wallet directory in the datadir.\n"
+ "To change the target wallet, use the -datadir, -wallet and -testnet/-regtest arguments.\n\n"
+ "Usage:\n"
+ " bitcoin-wallet [options] <command>\n";
+ strUsage += "\n" + gArgs.GetHelpMessage();
+ }
+ tfm::format(std::cout, "%s", strUsage);
return false;
}
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 455a82e390..4c89db54cb 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -57,11 +57,11 @@ static bool AppInit(int argc, char* argv[])
if (HelpRequested(args) || args.IsArgSet("-version")) {
std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n";
- if (args.IsArgSet("-version")) {
- strUsage += FormatParagraph(LicenseInfo()) + "\n";
- } else {
- strUsage += "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n";
- strUsage += "\n" + args.GetHelpMessage();
+ if (!args.IsArgSet("-version")) {
+ strUsage += FormatParagraph(LicenseInfo()) + "\n"
+ "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n"
+ "\n";
+ strUsage += args.GetHelpMessage();
}
tfm::format(std::cout, "%s", strUsage);
diff --git a/src/init.cpp b/src/init.cpp
index 9137050323..371399de9e 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -85,7 +85,6 @@
#include <zmq/zmqrpc.h>
#endif
-static bool fFeeEstimatesInitialized = false;
static const bool DEFAULT_PROXYRANDOMIZE = true;
static const bool DEFAULT_REST_ENABLE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
@@ -99,8 +98,6 @@ static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
#define MIN_CORE_FILEDESCRIPTORS 150
#endif
-static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
-
static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map";
/**
@@ -236,17 +233,8 @@ void Shutdown(NodeContext& node)
DumpMempool(*node.mempool);
}
- if (fFeeEstimatesInitialized)
- {
- ::feeEstimator.FlushUnconfirmed();
- fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
- CAutoFile est_fileout(fsbridge::fopen(est_path, "wb"), SER_DISK, CLIENT_VERSION);
- if (!est_fileout.IsNull())
- ::feeEstimator.Write(est_fileout);
- else
- LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string());
- fFeeEstimatesInitialized = false;
- }
+ // Drop transactions we were still watching, and record fee estimations.
+ if (node.fee_estimator) node.fee_estimator->Flush();
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
if (node.chainman) {
@@ -304,6 +292,7 @@ void Shutdown(NodeContext& node)
globalVerifyHandle.reset();
ECC_Stop();
node.mempool.reset();
+ node.fee_estimator.reset();
node.chainman = nullptr;
node.scheduler.reset();
@@ -914,7 +903,7 @@ std::set<BlockFilterType> g_enabled_filter_types;
std::terminate();
};
-bool AppInitBasicSetup(ArgsManager& args)
+bool AppInitBasicSetup(const ArgsManager& args)
{
// ********************************************************* Step 1: setup
#ifdef _MSC_VER
@@ -1384,14 +1373,24 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
// is not yet setup and may end up being set up twice if we
// need to reindex later.
+ // see Step 2: parameter interactions for more information about these
+ fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN);
+ fDiscover = args.GetBoolArg("-discover", true);
+ g_relay_txes = !args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
+
assert(!node.banman);
node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman);
node.connman = MakeUnique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), args.GetBoolArg("-networkactive", true));
+ assert(!node.fee_estimator);
+ // Don't initialize fee estimation with old data if we don't relay transactions,
+ // as they would never get updated.
+ if (g_relay_txes) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
+
assert(!node.mempool);
int check_ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
- node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator, check_ratio);
+ node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), check_ratio);
assert(!node.chainman);
node.chainman = &g_chainman;
@@ -1473,11 +1472,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
}
- // see Step 2: parameter interactions for more information about these
- fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN);
- fDiscover = args.GetBoolArg("-discover", true);
- g_relay_txes = !args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
-
for (const std::string& strAddr : args.GetArgs("-externalip")) {
CService addrLocal;
if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
@@ -1785,13 +1779,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
return false;
}
- fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
- CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
- // Allowed to fail as this file IS missing on first startup.
- if (!est_filein.IsNull())
- ::feeEstimator.Read(est_filein);
- fFeeEstimatesInitialized = true;
-
// ********************************************************* Step 8: start indexers
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
g_txindex = MakeUnique<TxIndex>(nTxIndexCache, false, fReindex);
diff --git a/src/init.h b/src/init.h
index 679e875da1..c04d966d06 100644
--- a/src/init.h
+++ b/src/init.h
@@ -33,7 +33,7 @@ void InitParameterInteraction(ArgsManager& args);
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read.
*/
-bool AppInitBasicSetup(ArgsManager& args);
+bool AppInitBasicSetup(const ArgsManager& args);
/**
* Initialization: parameter interaction.
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 5079be038e..36f76aeb4f 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -151,9 +151,6 @@ public:
//! Get network active.
virtual bool getNetworkActive() = 0;
- //! Estimate smart fee.
- virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) = 0;
-
//! Get dust relay fee.
virtual CFeeRate getDustRelayFee() = 0;
diff --git a/src/net.h b/src/net.h
index 21ee5e7808..77aaaac5b1 100644
--- a/src/net.h
+++ b/src/net.h
@@ -24,14 +24,15 @@
#include <sync.h>
#include <threadinterrupt.h>
#include <uint256.h>
+#include <util/check.h>
#include <atomic>
+#include <condition_variable>
#include <cstdint>
#include <deque>
#include <map>
-#include <thread>
#include <memory>
-#include <condition_variable>
+#include <thread>
class CScheduler;
class CNode;
@@ -1131,6 +1132,7 @@ public:
void SetCommonVersion(int greatest_common_version)
{
+ Assume(m_greatest_common_version == INIT_PROTO_VERSION);
m_greatest_common_version = greatest_common_version;
}
int GetCommonVersion() const
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index f4ebd11d56..2f2924b262 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3786,7 +3786,7 @@ bool PeerManager::MaybeDiscourageAndDisconnect(CNode& pnode)
}
// Normal case: Disconnect the peer and discourage all nodes sharing the address
- LogPrintf("Disconnecting and discouraging peer %d!\n", peer_id);
+ LogPrint(BCLog::NET, "Disconnecting and discouraging peer %d!\n", peer_id);
if (m_banman) m_banman->Discourage(pnode.addr);
m_connman.DisconnectNode(pnode.addr);
return true;
diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp
index fb46ea1731..02e50c4dbe 100644
--- a/src/node/coinstats.cpp
+++ b/src/node/coinstats.cpp
@@ -112,7 +112,7 @@ bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, CoinStatsHashType hash_t
}
// The legacy hash serializes the hashBlock
-static void PrepareHash(CHashWriter& ss, CCoinsStats& stats)
+static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
{
ss << stats.hashBlock;
}
diff --git a/src/node/context.cpp b/src/node/context.cpp
index 49d0c37235..958221a913 100644
--- a/src/node/context.cpp
+++ b/src/node/context.cpp
@@ -8,6 +8,7 @@
#include <interfaces/chain.h>
#include <net.h>
#include <net_processing.h>
+#include <policy/fees.h>
#include <scheduler.h>
#include <txmempool.h>
diff --git a/src/node/context.h b/src/node/context.h
index 3228831ed1..9b611bf8f5 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -12,6 +12,7 @@
class ArgsManager;
class BanMan;
+class CBlockPolicyEstimator;
class CConnman;
class CScheduler;
class CTxMemPool;
@@ -36,6 +37,7 @@ class WalletClient;
struct NodeContext {
std::unique_ptr<CConnman> connman;
std::unique_ptr<CTxMemPool> mempool;
+ std::unique_ptr<CBlockPolicyEstimator> fee_estimator;
std::unique_ptr<PeerManager> peerman;
ChainstateManager* chainman{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
std::unique_ptr<BanMan> banman;
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index a8c8be05fb..da3e759e38 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -221,15 +221,6 @@ public:
}
}
bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
- CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override
- {
- FeeCalculation fee_calc;
- CFeeRate result = ::feeEstimator.estimateSmartFee(num_blocks, &fee_calc, conservative);
- if (returned_target) {
- *returned_target = fee_calc.returnedTarget;
- }
- return result;
- }
CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
{
@@ -601,11 +592,13 @@ public:
}
CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
{
- return ::feeEstimator.estimateSmartFee(num_blocks, calc, conservative);
+ if (!m_node.fee_estimator) return {};
+ return m_node.fee_estimator->estimateSmartFee(num_blocks, calc, conservative);
}
unsigned int estimateMaxBlocks() override
{
- return ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ if (!m_node.fee_estimator) return 0;
+ return m_node.fee_estimator->HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
}
CFeeRate mempoolMinFee() override
{
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 0f31093dbb..f6e378866c 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -10,6 +10,8 @@
#include <txmempool.h>
#include <util/system.h>
+static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
+
static constexpr double INF_FEERATE = 1e99;
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) {
@@ -489,6 +491,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
{
static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
size_t bucketIndex = 0;
+
for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
buckets.push_back(bucketBoundary);
bucketMap[bucketBoundary] = bucketIndex;
@@ -500,6 +503,13 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
+
+ // If the fee estimation file is present, read recorded estimations
+ fs::path est_filepath = GetDataDir() / FEE_ESTIMATES_FILENAME;
+ CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION);
+ if (est_file.IsNull() || !Read(est_file)) {
+ LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", est_filepath.string());
+ }
}
CBlockPolicyEstimator::~CBlockPolicyEstimator()
@@ -856,6 +866,15 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
return CFeeRate(llround(median));
}
+void CBlockPolicyEstimator::Flush() {
+ FlushUnconfirmed();
+
+ fs::path est_filepath = GetDataDir() / FEE_ESTIMATES_FILENAME;
+ CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION);
+ if (est_file.IsNull() || !Write(est_file)) {
+ LogPrintf("Failed to write fee estimates to %s\n", est_filepath.string());
+ }
+}
bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
{
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 8ea8816dc3..dd9f530c99 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -215,6 +215,9 @@ public:
/** Calculation of highest target that estimates are tracked for */
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const;
+ /** Drop still unconfirmed transactions and record current estimations, if the fee estimation file is present. */
+ void Flush();
+
private:
mutable RecursiveMutex m_cs_fee_estimator;
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 8a62c64d79..e765e643a3 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -35,7 +35,7 @@
#include <QSettings>
#include <QTextDocument>
-static const std::array<int, 9> confTargets = { {2, 4, 6, 12, 24, 48, 144, 504, 1008} };
+static constexpr std::array confTargets{2, 4, 6, 12, 24, 48, 144, 504, 1008};
int getConfTargetForIndex(int index) {
if (index+1 > static_cast<int>(confTargets.size())) {
return confTargets.back();
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 392073d047..57327e6004 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -17,6 +17,7 @@
#include <node/coinstats.h>
#include <node/context.h>
#include <node/utxo_snapshot.h>
+#include <policy/fees.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <policy/rbf.h>
@@ -81,6 +82,15 @@ ChainstateManager& EnsureChainman(const util::Ref& context)
return *node.chainman;
}
+CBlockPolicyEstimator& EnsureFeeEstimator(const util::Ref& context)
+{
+ NodeContext& node = EnsureNodeContext(context);
+ if (!node.fee_estimator) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled");
+ }
+ return *node.fee_estimator;
+}
+
/* Calculate the difficulty for a given block index.
*/
double GetDifficulty(const CBlockIndex* blockindex)
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 5b362bf211..91766aacc9 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -15,6 +15,7 @@ extern RecursiveMutex cs_main;
class CBlock;
class CBlockIndex;
+class CBlockPolicyEstimator;
class CTxMemPool;
class ChainstateManager;
class UniValue;
@@ -54,5 +55,6 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],
NodeContext& EnsureNodeContext(const util::Ref& context);
CTxMemPool& EnsureMemPool(const util::Ref& context);
ChainstateManager& EnsureChainman(const util::Ref& context);
+CBlockPolicyEstimator& EnsureFeeEstimator(const util::Ref& context);
#endif
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 7d45ad9434..965b278bfa 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1022,21 +1022,19 @@ static RPCHelpMan submitheader()
static RPCHelpMan estimatesmartfee()
{
return RPCHelpMan{"estimatesmartfee",
- "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
- "confirmation within conf_target blocks if possible and return the number of blocks\n"
- "for which the estimate is valid. Uses virtual transaction size as defined\n"
- "in BIP 141 (witness data is discounted).\n",
- {
- {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "CONSERVATIVE", "The fee estimate mode.\n"
+ "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
+ "confirmation within conf_target blocks if possible and return the number of blocks\n"
+ "for which the estimate is valid. Uses virtual transaction size as defined\n"
+ "in BIP 141 (witness data is discounted).\n",
+ {
+ {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
+ {"estimate_mode", RPCArg::Type::STR, /* default */ "conservative", "The fee estimate mode.\n"
" Whether to return a more conservative estimate which also satisfies\n"
" a longer history. A conservative estimate potentially returns a\n"
" higher feerate and is more likely to be sufficient for the desired\n"
" target, but is not as responsive to short term drops in the\n"
- " prevailing fee market. Must be one of:\n"
- " \"UNSET\"\n"
- " \"ECONOMICAL\"\n"
- " \"CONSERVATIVE\""},
+ " prevailing fee market. Must be one of (case insensitive):\n"
+ "\"" + FeeModes("\"\n\"") + "\""},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -1059,7 +1057,10 @@ static RPCHelpMan estimatesmartfee()
{
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
- unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+
+ CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context);
+
+ unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
bool conservative = true;
if (!request.params[1].isNull()) {
@@ -1073,7 +1074,7 @@ static RPCHelpMan estimatesmartfee()
UniValue result(UniValue::VOBJ);
UniValue errors(UniValue::VARR);
FeeCalculation feeCalc;
- CFeeRate feeRate = ::feeEstimator.estimateSmartFee(conf_target, &feeCalc, conservative);
+ CFeeRate feeRate = fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative);
if (feeRate != CFeeRate(0)) {
result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
} else {
@@ -1144,7 +1145,10 @@ static RPCHelpMan estimaterawfee()
{
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
- unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+
+ CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context);
+
+ unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
double threshold = 0.95;
if (!request.params[1].isNull()) {
@@ -1161,9 +1165,9 @@ static RPCHelpMan estimaterawfee()
EstimationResult buckets;
// Only output results for horizons which track the target
- if (conf_target > ::feeEstimator.HighestTargetTracked(horizon)) continue;
+ if (conf_target > fee_estimator.HighestTargetTracked(horizon)) continue;
- feeRate = ::feeEstimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
+ feeRate = fee_estimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
UniValue horizon_result(UniValue::VOBJ);
UniValue errors(UniValue::VARR);
UniValue passbucket(UniValue::VOBJ);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index c6d7fea443..f6ddaf379b 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -244,16 +244,15 @@ static RPCHelpMan gettxoutproof()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::set<uint256> setTxids;
- uint256 oneTxid;
UniValue txids = request.params[0].get_array();
+ if (txids.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txids' cannot be empty");
+ }
for (unsigned int idx = 0; idx < txids.size(); idx++) {
- const UniValue& txid = txids[idx];
- uint256 hash(ParseHashV(txid, "txid"));
- if (setTxids.count(hash)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txid.get_str());
+ auto ret = setTxids.insert(ParseHashV(txids[idx], "txid"));
+ if (!ret.second) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str());
}
- setTxids.insert(hash);
- oneTxid = hash;
}
CBlockIndex* pblockindex = nullptr;
@@ -287,7 +286,7 @@ static RPCHelpMan gettxoutproof()
LOCK(cs_main);
if (pblockindex == nullptr) {
- const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, oneTxid, Params().GetConsensus(), hashBlock);
+ const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, *setTxids.begin(), Params().GetConsensus(), hashBlock);
if (!tx || hashBlock.IsNull()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
}
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index f004ecc20c..122a92f084 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -286,7 +286,7 @@ void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore,
SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
}
-void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, std::map<int, std::string>& input_errors, UniValue& result)
+void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, std::string>& input_errors, UniValue& result)
{
// Make errors UniValue
UniValue vErrors(UniValue::VARR);
diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h
index 942314eccf..ce7d5834fa 100644
--- a/src/rpc/rawtransaction_util.h
+++ b/src/rpc/rawtransaction_util.h
@@ -25,7 +25,7 @@ class SigningProvider;
* @param result JSON object where signed transaction results accumulate
*/
void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType, UniValue& result);
-void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, std::map<int, std::string>& input_errors, UniValue& result);
+void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, std::string>& input_errors, UniValue& result);
/**
* Parse a prevtxs UniValue array and get the map of coins from it
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index c1786140de..582341bd3e 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -66,7 +66,7 @@ public:
return setValid.contains(entry, erase);
}
- void Set(uint256& entry)
+ void Set(const uint256& entry)
{
boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
setValid.insert(entry);
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 25fdd64568..37ff8a9afe 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -71,7 +71,7 @@ public:
}
// Simulates connection failure so that we can test eviction of offline nodes
- void SimConnFail(CService& addr)
+ void SimConnFail(const CService& addr)
{
LOCK(cs);
int64_t nLastSuccess = 1;
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index a0c8b7aac5..81e36b3f06 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -48,8 +48,9 @@ void test_one_input(const std::vector<uint8_t>& buffer)
fuzzed_data_provider.ConsumeRandomLengthString(32),
fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH}),
fuzzed_data_provider.ConsumeBool()};
+ node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral<int>());
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10)) {
case 0: {
node.CloseSocketDisconnect();
break;
@@ -59,10 +60,6 @@ void test_one_input(const std::vector<uint8_t>& buffer)
break;
}
case 2: {
- node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral<int>());
- break;
- }
- case 3: {
const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
if (!SanityCheckASMap(asmap)) {
break;
@@ -71,18 +68,18 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.copyStats(stats, asmap);
break;
}
- case 4: {
+ case 3: {
const CNode* add_ref_node = node.AddRef();
assert(add_ref_node == &node);
break;
}
- case 5: {
+ case 4: {
if (node.GetRefCount() > 0) {
node.Release();
}
break;
}
- case 6: {
+ case 5: {
if (node.m_addr_known == nullptr) {
break;
}
@@ -93,7 +90,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.AddAddressKnown(*addr_opt);
break;
}
- case 7: {
+ case 6: {
if (node.m_addr_known == nullptr) {
break;
}
@@ -105,7 +102,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.PushAddress(*addr_opt, fast_random_context);
break;
}
- case 8: {
+ case 7: {
const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
if (!inv_opt) {
break;
@@ -113,11 +110,11 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.AddKnownTx(inv_opt->hash);
break;
}
- case 9: {
+ case 8: {
node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider));
break;
}
- case 10: {
+ case 9: {
const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (!service_opt) {
break;
@@ -125,7 +122,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.SetAddrLocal(*service_opt);
break;
}
- case 11: {
+ case 10: {
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
bool complete;
node.ReceiveMsgBytes(b, complete);
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index b23fec9b95..cec4a8df61 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -75,7 +75,7 @@ public:
}
};
-static CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
+static CDataStream AddrmanToStream(const CAddrManSerializationMock& _addrman)
{
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
ssPeersIn << Params().MessageStart();
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index adf5970206..fffa29a1d3 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -16,6 +16,7 @@
#include <net.h>
#include <net_processing.h>
#include <noui.h>
+#include <policy/fees.h>
#include <pow.h>
#include <rpc/blockchain.h>
#include <rpc/register.h>
@@ -141,7 +142,8 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
- m_node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator, 1);
+ m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
+ m_node.mempool = std::make_unique<CTxMemPool>(m_node.fee_estimator.get(), 1);
m_node.chainman = &::g_chainman;
m_node.chainman->InitializeChainstate(*m_node.mempool);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 131508f5f8..a9ef0f73cc 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1860,7 +1860,7 @@ BOOST_AUTO_TEST_CASE(test_Capitalize)
BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff");
}
-static std::string SpanToStr(Span<const char>& span)
+static std::string SpanToStr(const Span<const char>& span)
{
return std::string(span.begin(), span.end());
}
diff --git a/src/util/check.h b/src/util/check.h
index 9edf394492..e7620d97a0 100644
--- a/src/util/check.h
+++ b/src/util/check.h
@@ -46,7 +46,7 @@ class NonFatalCheckError : public std::runtime_error
#error "Cannot compile without assertions!"
#endif
-/** Helper for Assert(). TODO remove in C++14 and replace `decltype(get_pure_r_value(val))` with `T` (templated lambda) */
+/** Helper for Assert() */
template <typename T>
T get_pure_r_value(T&& val)
{
@@ -54,6 +54,22 @@ T get_pure_r_value(T&& val)
}
/** Identity function. Abort if the value compares equal to zero */
-#define Assert(val) [&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); assert(#val && check); return std::forward<decltype(get_pure_r_value(val))>(check); }()
+#define Assert(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); assert(#val && check); return std::forward<decltype(get_pure_r_value(val))>(check); }())
+
+/**
+ * Assume is the identity function.
+ *
+ * - Should be used to run non-fatal checks. In debug builds it behaves like
+ * Assert()/assert() to notify developers and testers about non-fatal errors.
+ * In production it doesn't warn or log anything.
+ * - For fatal errors, use Assert().
+ * - For non-fatal errors in interactive sessions (e.g. RPC or command line
+ * interfaces), CHECK_NONFATAL() might be more appropriate.
+ */
+#ifdef ABORT_ON_FAILED_ASSUME
+#define Assume(val) Assert(val)
+#else
+#define Assume(val) ((void)(val))
+#endif
#endif // BITCOIN_UTIL_CHECK_H
diff --git a/src/validation.cpp b/src/validation.cpp
index a774e76fa9..2585345dee 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -22,7 +22,6 @@
#include <logging/timer.h>
#include <node/ui_interface.h>
#include <optional.h>
-#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/settings.h>
#include <pow.h>
@@ -148,8 +147,6 @@ arith_uint256 nMinimumChainWork;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
-CBlockPolicyEstimator feeEstimator;
-
// Internal stuff
namespace {
CBlockIndex* pindexBestInvalid = nullptr;
@@ -505,13 +502,13 @@ private:
// Run the script checks using our policy flags. As this can be slow, we should
// only invoke this on transactions that have otherwise passed policy checks.
- bool PolicyScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Re-run the script checks, using consensus flags, and try to cache the
// result in the scriptcache. This should be done after
// PolicyScriptChecks(). This requires that all inputs either be in our
// utxo set or in the mempool.
- bool ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Try to add the transaction to the mempool, removing any conflicts first.
// Returns true if the transaction is in the mempool after any size
@@ -921,7 +918,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return true;
}
-bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata)
+bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata)
{
const CTransaction& tx = *ws.m_ptx;
@@ -948,7 +945,7 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
return true;
}
-bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata)
+bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata)
{
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
diff --git a/src/validation.h b/src/validation.h
index ffb038ad75..6d8c6d431a 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -42,7 +42,6 @@ class CChainParams;
class CInv;
class CConnman;
class CScriptCheck;
-class CBlockPolicyEstimator;
class CTxMemPool;
class ChainstateManager;
class TxValidationState;
@@ -110,7 +109,6 @@ enum class SynchronizationState {
};
extern RecursiveMutex cs_main;
-extern CBlockPolicyEstimator feeEstimator;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
extern Mutex g_best_block_mutex;
extern std::condition_variable g_best_block_cv;
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 6cbad14de8..7a8bc0b7f3 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -111,7 +111,7 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
return feebumper::Result::OK;
}
-static CFeeRate EstimateFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CAmount old_fee, CCoinControl& coin_control)
+static CFeeRate EstimateFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CAmount old_fee, const CCoinControl& coin_control)
{
// Get the fee rate of the original transaction. This is calculated from
// the tx fee/vsize, so it may have been rounded down. Add 1 satoshi to the
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 3fbba9ab92..e8dbc20e56 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -77,7 +77,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
}
//! Construct wallet tx status struct.
-WalletTxStatus MakeWalletTxStatus(CWallet& wallet, const CWalletTx& wtx)
+WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
{
WalletTxStatus result;
result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height : std::numeric_limits<int>::max();
@@ -94,7 +94,7 @@ WalletTxStatus MakeWalletTxStatus(CWallet& wallet, const CWalletTx& wtx)
}
//! Construct wallet TxOut struct.
-WalletTxOut MakeWalletTxOut(CWallet& wallet,
+WalletTxOut MakeWalletTxOut(const CWallet& wallet,
const CWalletTx& wtx,
int n,
int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index 9be610e8bd..d6e6f015db 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -91,7 +91,7 @@ bool IsFeatureSupported(int wallet_version, int feature_version)
WalletFeature GetClosestWalletFeature(int version)
{
- const std::array<WalletFeature, 8> wallet_features{{FEATURE_LATEST, FEATURE_PRE_SPLIT_KEYPOOL, FEATURE_NO_DEFAULT_KEY, FEATURE_HD_SPLIT, FEATURE_HD, FEATURE_COMPRPUBKEY, FEATURE_WALLETCRYPT, FEATURE_BASE}};
+ static constexpr std::array wallet_features{FEATURE_LATEST, FEATURE_PRE_SPLIT_KEYPOOL, FEATURE_NO_DEFAULT_KEY, FEATURE_HD_SPLIT, FEATURE_HD, FEATURE_COMPRPUBKEY, FEATURE_WALLETCRYPT, FEATURE_BASE};
for (const WalletFeature& wf : wallet_features) {
if (version >= wf) return wf;
}
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 8a8a0c7614..8f522aee66 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -13,6 +13,7 @@ from test_framework.util import (
assert_equal,
assert_greater_than,
assert_greater_than_or_equal,
+ assert_raises_rpc_error,
satoshi_round,
)
@@ -262,6 +263,11 @@ class EstimateFeeTest(BitcoinTestFramework):
self.log.info("Final estimates after emptying mempools")
check_estimates(self.nodes[1], self.fees_per_kb)
+ self.log.info("Testing that fee estimation is disabled in blocksonly.")
+ self.restart_node(0, ["-blocksonly"])
+ assert_raises_rpc_error(-32603, "Fee estimation disabled",
+ self.nodes[0].estimatesmartfee, 2)
+
if __name__ == '__main__':
EstimateFeeTest().main()
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 116eb7e3d7..6ee2b72c11 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -1444,6 +1444,10 @@ class TaprootTest(BitcoinTestFramework):
self.nodes[1].generate(101)
self.test_spenders(self.nodes[1], spenders_taproot_active(), input_counts=[1, 2, 2, 2, 2, 3])
+ # Re-connect nodes in case they have been disconnected
+ self.disconnect_nodes(0, 1)
+ self.connect_nodes(0, 1)
+
# Transfer value of the largest 500 coins to pre-taproot node.
addr = self.nodes[0].getnewaddress()
diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py
index 3b76c7dd1e..81862ac69e 100755
--- a/test/functional/rpc_estimatefee.py
+++ b/test/functional/rpc_estimatefee.py
@@ -41,6 +41,8 @@ class EstimateFeeTest(BitcoinTestFramework):
self.nodes[0].estimatesmartfee(1)
# self.nodes[0].estimatesmartfee(1, None)
self.nodes[0].estimatesmartfee(1, 'ECONOMICAL')
+ self.nodes[0].estimatesmartfee(1, 'unset')
+ self.nodes[0].estimatesmartfee(1, 'conservative')
self.nodes[0].estimaterawfee(1)
self.nodes[0].estimaterawfee(1, None)
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index b962e1c3a5..2fbbdbbdf0 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -151,6 +151,19 @@ class SignRawTransactionsTest(BitcoinTestFramework):
assert_equal(rawTxSigned['errors'][1]['witness'], ["304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01", "025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"])
assert not rawTxSigned['errors'][0]['witness']
+ def test_fully_signed_tx(self):
+ self.log.info("Test signing a fully signed transaction does nothing")
+ self.nodes[0].walletpassphrase("password", 9999)
+ self.nodes[0].generate(101)
+ rawtx = self.nodes[0].createrawtransaction([], [{self.nodes[0].getnewaddress(): 10}])
+ fundedtx = self.nodes[0].fundrawtransaction(rawtx)
+ signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx["hex"])
+ assert_equal(signedtx["complete"], True)
+ signedtx2 = self.nodes[0].signrawtransactionwithwallet(signedtx["hex"])
+ assert_equal(signedtx2["complete"], True)
+ assert_equal(signedtx["hex"], signedtx2["hex"])
+ self.nodes[0].walletlock()
+
def witness_script_test(self):
self.log.info("Test signing transaction to P2SH-P2WSH addresses without wallet")
# Create a new P2SH-P2WSH 1-of-1 multisig address:
@@ -231,6 +244,7 @@ class SignRawTransactionsTest(BitcoinTestFramework):
self.witness_script_test()
self.OP_1NEGATE_test()
self.test_with_lock_outputs()
+ self.test_fully_signed_tx()
if __name__ == '__main__':
diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py
index 93fb62c5d6..2d6ce77613 100755
--- a/test/functional/rpc_txoutproof.py
+++ b/test/functional/rpc_txoutproof.py
@@ -78,7 +78,7 @@ class MerkleBlockTest(BitcoinTestFramework):
# We can't get a proof if we specify transactions from different blocks
assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[0].gettxoutproof, [txid1, txid3])
# Test empty list
- assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].gettxoutproof, [])
+ assert_raises_rpc_error(-8, "Parameter 'txids' cannot be empty", self.nodes[0].gettxoutproof, [])
# Test duplicate txid
assert_raises_rpc_error(-8, 'Invalid parameter, duplicated txid', self.nodes[0].gettxoutproof, [txid1, txid1])
diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py
index 0e786ca595..433b40faee 100755
--- a/test/functional/wallet_balance.py
+++ b/test/functional/wallet_balance.py
@@ -263,8 +263,6 @@ class WalletTest(BitcoinTestFramework):
self.log.info('Put txs back into mempool of node 1 (not node 0)')
self.nodes[0].invalidateblock(block_reorg)
self.nodes[1].invalidateblock(block_reorg)
- self.sync_blocks()
- self.nodes[0].syncwithvalidationinterfacequeue()
assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted
self.nodes[0].generatetoaddress(1, ADDRESS_WATCHONLY)
assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index f7fdd6e908..30206349ae 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -64,7 +64,7 @@ class ImportMultiTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- self.nodes[1].syncwithvalidationinterfacequeue()
+ self.nodes[1].syncwithvalidationinterfacequeue() # Sync the timestamp to the wallet, so that importmulti works
node0_address1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index 353deefcc1..78d88f8aa5 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -50,6 +50,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
block.solve()
node.submitblock(ToHex(block))
+ # Set correct m_best_block_time, which is used in ResendWalletTransactions
node.syncwithvalidationinterfacequeue()
now = int(time.time())
diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh
index 6bd02d45ac..c4ad00e954 100755
--- a/test/lint/lint-circular-dependencies.sh
+++ b/test/lint/lint-circular-dependencies.sh
@@ -20,7 +20,6 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"txmempool -> validation -> txmempool"
"wallet/fees -> wallet/wallet -> wallet/fees"
"wallet/wallet -> wallet/walletdb -> wallet/wallet"
- "policy/fees -> txmempool -> validation -> policy/fees"
)
EXIT_CODE=0