aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build-aux/m4/bitcoin_qt.m495
-rw-r--r--ci/test/00_setup_env_mac.sh2
-rw-r--r--configure.ac4
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml2
-rw-r--r--depends/README.md2
-rw-r--r--depends/packages/libnatpmp.mk10
-rw-r--r--depends/packages/libxcb.mk11
-rw-r--r--doc/bitcoin-conf.md2
-rw-r--r--share/examples/bitcoin.conf14
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.test_fuzz.include2
-rw-r--r--src/Makefile.test_util.include2
-rw-r--r--src/interfaces/chain.h3
-rw-r--r--src/interfaces/node.h5
-rw-r--r--src/net.cpp6
-rw-r--r--src/net.h10
-rw-r--r--src/net_processing.cpp53
-rw-r--r--src/netbase.h17
-rw-r--r--src/node/interfaces.cpp8
-rw-r--r--src/qt/addresstablemodel.cpp44
-rw-r--r--src/qt/bantablemodel.cpp15
-rw-r--r--src/qt/clientmodel.cpp8
-rw-r--r--src/qt/forms/overviewpage.ui10
-rw-r--r--src/qt/peertablemodel.cpp41
-rw-r--r--src/qt/rpcconsole.cpp42
-rw-r--r--src/qt/rpcconsole.h5
-rw-r--r--src/qt/test/test_main.cpp7
-rw-r--r--src/qt/transactiontablemodel.cpp30
-rw-r--r--src/rpc/mining.cpp2
-rw-r--r--src/rpc/net.cpp8
-rw-r--r--src/script/interpreter.cpp6
-rw-r--r--src/test/fuzz/FuzzedDataProvider.h1
-rw-r--r--src/test/fuzz/connman.cpp2
-rw-r--r--src/test/fuzz/util.h9
-rw-r--r--src/test/versionbits_tests.cpp86
-rw-r--r--src/wallet/feebumper.cpp2
-rw-r--r--src/wallet/wallet.cpp27
-rw-r--r--src/wallet/wallet.h4
-rwxr-xr-xtest/functional/feature_taproot.py20
-rwxr-xr-xtest/functional/p2p_leak.py64
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py20
-rw-r--r--test/functional/test_framework/script.py6
-rwxr-xr-xtest/fuzz/test_runner.py54
43 files changed, 426 insertions, 337 deletions
diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4
index b559baba23..67ae03f3a9 100644
--- a/build-aux/m4/bitcoin_qt.m4
+++ b/build-aux/m4/bitcoin_qt.m4
@@ -111,9 +111,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
dnl For Qt5, we can check a header to find out whether Qt is build
dnl statically. When Qt is built statically, some plugins must be linked into
dnl the final binary as well.
- dnl With Qt5, languages moved into core and the WindowsIntegration plugin was
- dnl added.
- dnl _BITCOIN_QT_CHECK_STATIC_PLUGINS does a quick link-check and appends the
+ dnl _BITCOIN_QT_CHECK_STATIC_PLUGIN does a quick link-check and appends the
dnl results to QT_LIBS.
BITCOIN_QT_CHECK([
TEMP_CPPFLAGS=$CPPFLAGS
@@ -122,20 +120,31 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
CXXFLAGS="$PIC_FLAGS $CXXFLAGS"
_BITCOIN_QT_IS_STATIC
if test "x$bitcoin_cv_static_qt" = xyes; then
- _BITCOIN_QT_FIND_STATIC_PLUGINS
+ _BITCOIN_QT_CHECK_STATIC_LIBS
+
+ if test "x$qt_plugin_path" != x; then
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms"
+ if test -d "$qt_plugin_path/accessible"; then
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
+ fi
+ if test -d "$qt_plugin_path/platforms/android"; then
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms/android -lqtfreetype -lEGL"
+ fi
+ fi
+
AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static])
if test "x$TARGET_OS" != xandroid; then
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal])
+ _BITCOIN_QT_CHECK_STATIC_PLUGIN([QMinimalIntegrationPlugin], [-lqminimal])
AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists])
fi
if test "x$TARGET_OS" = xwindows; then
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows])
+ _BITCOIN_QT_CHECK_STATIC_PLUGIN([QWindowsIntegrationPlugin], [-lqwindows])
AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows])
elif test "x$TARGET_OS" = xlinux; then
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static])
+ _BITCOIN_QT_CHECK_STATIC_PLUGIN([QXcbIntegrationPlugin], [-lqxcb -lxcb-static])
AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb])
elif test "x$TARGET_OS" = xdarwin; then
- _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa])
+ _BITCOIN_QT_CHECK_STATIC_PLUGIN([QCocoaIntegrationPlugin], [-lqcocoa])
AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa])
elif test "x$TARGET_OS" = xandroid; then
QT_LIBS="-Wl,--export-dynamic,--undefined=JNI_OnLoad -lqtforandroid -ljnigraphics -landroid -lqtfreetype -lQt5EglSupport $QT_LIBS"
@@ -284,51 +293,49 @@ AC_DEFUN([_BITCOIN_QT_IS_STATIC],[
])
])
-dnl Internal. Check if the link-requirements for static plugins are met.
+dnl Internal. Check if the link-requirements for a static plugin are met.
+dnl
+dnl _BITCOIN_QT_CHECK_STATIC_PLUGIN(PLUGIN, LIBRARIES)
+dnl --------------------------------------------------
+dnl
dnl Requires: INCLUDES and LIBS must be populated as necessary.
-dnl Inputs: $1: A series of Q_IMPORT_PLUGIN().
+dnl Inputs: $1: A static plugin name.
dnl Inputs: $2: The libraries that resolve $1.
dnl Output: QT_LIBS is prepended or configure exits.
-AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_PLUGINS],[
- AC_MSG_CHECKING(for static Qt plugins: $2)
+AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_PLUGIN], [
+ AC_MSG_CHECKING([for $1 ($2)])
CHECK_STATIC_PLUGINS_TEMP_LIBS="$LIBS"
LIBS="$2${qt_lib_suffix} $QT_LIBS $LIBS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
- #define QT_STATICPLUGIN
- #include <QtPlugin>
- $1]],
- [[return 0;]])],
- [AC_MSG_RESULT(yes); QT_LIBS="$2${qt_lib_suffix} $QT_LIBS"],
- [AC_MSG_RESULT(no); BITCOIN_QT_FAIL(Could not resolve: $2)])
+ #include <QtPlugin>
+ Q_IMPORT_PLUGIN($1)
+ ]])],
+ [AC_MSG_RESULT([yes]); QT_LIBS="$2${qt_lib_suffix} $QT_LIBS"],
+ [AC_MSG_RESULT([no]); BITCOIN_QT_FAIL([$1 not found.])])
LIBS="$CHECK_STATIC_PLUGINS_TEMP_LIBS"
])
-dnl Internal. Find paths necessary for linking qt static plugins
-dnl Inputs: qt_plugin_path. optional.
-dnl Outputs: QT_LIBS is appended
-AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[
- if test "x$qt_plugin_path" != x; then
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms"
- if test -d "$qt_plugin_path/accessible"; then
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
- fi
- if test -d "$qt_plugin_path/platforms/android"; then
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms/android -lqtfreetype -lEGL"
- fi
- PKG_CHECK_MODULES([QTFONTDATABASE], [Qt5FontDatabaseSupport${qt_lib_suffix}], [QT_LIBS="-lQt5FontDatabaseSupport${qt_lib_suffix} $QT_LIBS"])
- PKG_CHECK_MODULES([QTEVENTDISPATCHER], [Qt5EventDispatcherSupport${qt_lib_suffix}], [QT_LIBS="-lQt5EventDispatcherSupport${qt_lib_suffix} $QT_LIBS"])
- PKG_CHECK_MODULES([QTTHEME], [Qt5ThemeSupport${qt_lib_suffix}], [QT_LIBS="-lQt5ThemeSupport${qt_lib_suffix} $QT_LIBS"])
- PKG_CHECK_MODULES([QTDEVICEDISCOVERY], [Qt5DeviceDiscoverySupport${qt_lib_suffix}], [QT_LIBS="-lQt5DeviceDiscoverySupport${qt_lib_suffix} $QT_LIBS"])
- PKG_CHECK_MODULES([QTACCESSIBILITY], [Qt5AccessibilitySupport${qt_lib_suffix}], [QT_LIBS="-lQt5AccessibilitySupport${qt_lib_suffix} $QT_LIBS"])
- PKG_CHECK_MODULES([QTFB], [Qt5FbSupport${qt_lib_suffix}], [QT_LIBS="-lQt5FbSupport${qt_lib_suffix} $QT_LIBS"])
- if test "x$TARGET_OS" = xlinux; then
- PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"])
- elif test "x$TARGET_OS" = xdarwin; then
- PKG_CHECK_MODULES([QTCLIPBOARD], [Qt5ClipboardSupport${qt_lib_suffix}], [QT_LIBS="-lQt5ClipboardSupport${qt_lib_suffix} $QT_LIBS"])
- PKG_CHECK_MODULES([QTGRAPHICS], [Qt5GraphicsSupport${qt_lib_suffix}], [QT_LIBS="-lQt5GraphicsSupport${qt_lib_suffix} $QT_LIBS"])
- PKG_CHECK_MODULES([QTCGL], [Qt5CglSupport${qt_lib_suffix}], [QT_LIBS="-lQt5CglSupport${qt_lib_suffix} $QT_LIBS"])
- fi
- fi
+dnl Internal. Check Qt static libs with PKG_CHECK_MODULES.
+dnl
+dnl _BITCOIN_QT_CHECK_STATIC_LIBS
+dnl -----------------------------
+dnl
+dnl Inputs: no inputs.
+dnl Outputs: QT_LIBS is prepended.
+AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_LIBS], [
+ PKG_CHECK_MODULES([QTFONTDATABASE], [Qt5FontDatabaseSupport${qt_lib_suffix}], [QT_LIBS="-lQt5FontDatabaseSupport${qt_lib_suffix} $QT_LIBS"])
+ PKG_CHECK_MODULES([QTEVENTDISPATCHER], [Qt5EventDispatcherSupport${qt_lib_suffix}], [QT_LIBS="-lQt5EventDispatcherSupport${qt_lib_suffix} $QT_LIBS"])
+ PKG_CHECK_MODULES([QTTHEME], [Qt5ThemeSupport${qt_lib_suffix}], [QT_LIBS="-lQt5ThemeSupport${qt_lib_suffix} $QT_LIBS"])
+ PKG_CHECK_MODULES([QTDEVICEDISCOVERY], [Qt5DeviceDiscoverySupport${qt_lib_suffix}], [QT_LIBS="-lQt5DeviceDiscoverySupport${qt_lib_suffix} $QT_LIBS"])
+ PKG_CHECK_MODULES([QTACCESSIBILITY], [Qt5AccessibilitySupport${qt_lib_suffix}], [QT_LIBS="-lQt5AccessibilitySupport${qt_lib_suffix} $QT_LIBS"])
+ PKG_CHECK_MODULES([QTFB], [Qt5FbSupport${qt_lib_suffix}], [QT_LIBS="-lQt5FbSupport${qt_lib_suffix} $QT_LIBS"])
+ if test "x$TARGET_OS" = xlinux; then
+ PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"])
+ elif test "x$TARGET_OS" = xdarwin; then
+ PKG_CHECK_MODULES([QTCLIPBOARD], [Qt5ClipboardSupport${qt_lib_suffix}], [QT_LIBS="-lQt5ClipboardSupport${qt_lib_suffix} $QT_LIBS"])
+ PKG_CHECK_MODULES([QTGRAPHICS], [Qt5GraphicsSupport${qt_lib_suffix}], [QT_LIBS="-lQt5GraphicsSupport${qt_lib_suffix} $QT_LIBS"])
+ PKG_CHECK_MODULES([QTCGL], [Qt5CglSupport${qt_lib_suffix}], [QT_LIBS="-lQt5CglSupport${qt_lib_suffix} $QT_LIBS"])
+ fi
])
dnl Internal. Find Qt libraries using pkg-config.
diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh
index 6da011d19b..645dcffd02 100644
--- a/ci/test/00_setup_env_mac.sh
+++ b/ci/test/00_setup_env_mac.sh
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_macos_cross
export DOCKER_NAME_TAG=ubuntu:20.04 # Check that Focal can cross-compile to macos (Focal is used in the gitian build as well)
export HOST=x86_64-apple-darwin18
-export PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools libtinfo5 python3-dev python3-setuptools xorriso"
+export PACKAGES="cmake imagemagick librsvg2-bin libz-dev libtiff-tools libtinfo5 python3-dev python3-setuptools xorriso"
export XCODE_VERSION=11.3.1
export XCODE_BUILD_ID=11C505
export RUN_UNIT_TESTS=false
diff --git a/configure.ac b/configure.ac
index c5bc7ebc7f..391a75eeed 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1669,6 +1669,9 @@ else
fi
AC_MSG_RESULT($use_natpmp_default)
AC_DEFINE_UNQUOTED([USE_NATPMP], [$natpmp_setting], [NAT-PMP support not compiled if undefined, otherwise value (0 or 1) determines default state])
+ if test x$TARGET_OS = xwindows; then
+ NATPMP_CPPFLAGS="-DSTATICLIB -DNATPMP_STATICLIB"
+ fi
else
AC_MSG_RESULT([no])
fi
@@ -1826,6 +1829,7 @@ AC_SUBST(SQLITE_LIBS)
AC_SUBST(TESTDEFS)
AC_SUBST(MINIUPNPC_CPPFLAGS)
AC_SUBST(MINIUPNPC_LIBS)
+AC_SUBST(NATPMP_CPPFLAGS)
AC_SUBST(NATPMP_LIBS)
AC_SUBST(EVENT_LIBS)
AC_SUBST(EVENT_PTHREADS_LIBS)
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 0dc531df0e..98c3888b45 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -21,9 +21,7 @@ packages:
- "bsdmainutils"
- "cmake"
- "imagemagick"
-- "libcap-dev"
- "libz-dev"
-- "libbz2-dev"
- "python3"
- "python3-dev"
- "python3-setuptools"
diff --git a/depends/README.md b/depends/README.md
index 9e9878c595..e72c666474 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -44,7 +44,7 @@ The paths are automatically configured and no other options are needed unless ta
#### For macOS cross compilation
- sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools libtinfo5 xorriso
+ sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libz-dev python3-setuptools libtinfo5 xorriso
#### For Win64 cross compilation
diff --git a/depends/packages/libnatpmp.mk b/depends/packages/libnatpmp.mk
index 391b9337b7..cdcf8c0bf2 100644
--- a/depends/packages/libnatpmp.mk
+++ b/depends/packages/libnatpmp.mk
@@ -1,11 +1,13 @@
package=libnatpmp
-$(package)_version=20150609
-$(package)_download_path=https://miniupnp.tuxfamily.org/files/
-$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=e1aa9c4c4219bc06943d6b2130f664daee213fb262fcb94dd355815b8f4536b0
+$(package)_version=4536032ae32268a45c073a4d5e91bbab4534773a
+$(package)_download_path=https://github.com/miniupnp/libnatpmp/archive
+$(package)_file_name=$($(package)_version).tar.gz
+$(package)_sha256_hash=543b460aab26acf91e11d15e17d8798f845304199eea2d76c2f444ec749c5383
define $(package)_set_vars
$(package)_build_opts=CC="$($(package)_cc)"
+ $(package)_build_opts_mingw32=CPPFLAGS=-DNATPMP_STATICLIB
+ $(package)_build_opts_darwin=LIBTOOL="$($(package)_libtool)"
$(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)"
endef
diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk
index 2204b38195..14abde9b0a 100644
--- a/depends/packages/libxcb.mk
+++ b/depends/packages/libxcb.mk
@@ -23,17 +23,12 @@ $(package)_config_opts += --disable-xv --disable-xvmc
endef
define $(package)_preprocess_cmds
- cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux &&\
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux && \
sed "s/pthread-stubs//" -i configure
endef
-# Don't install xcb headers to the default path in order to work around a qt
-# build issue: https://bugreports.qt.io/browse/QTBUG-34748
-# When using qt's internal libxcb, it may end up finding the real headers in
-# depends staging. Use a non-default path to avoid that.
-
define $(package)_config_cmds
- $($(package)_autoconf) --includedir=$(host_prefix)/include/xcb-shared
+ $($(package)_autoconf)
endef
define $(package)_build_cmds
@@ -45,5 +40,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- rm -rf share/man share/doc lib/*.la
+ rm -rf share lib/*.la
endef
diff --git a/doc/bitcoin-conf.md b/doc/bitcoin-conf.md
index f4a8edec75..9a312bc33c 100644
--- a/doc/bitcoin-conf.md
+++ b/doc/bitcoin-conf.md
@@ -27,7 +27,7 @@ Comments may appear in two ways:
### Network specific options
Network specific options can be:
-- placed into sections with headers `[main]` (not `[mainnet]`), `[test]` (not `[testnet]`) or `[regtest]`;
+- placed into sections with headers `[main]` (not `[mainnet]`), `[test]` (not `[testnet]`), `[signet]` or `[regtest]`;
- prefixed with a chain name; e.g., `regtest.maxmempool=100`.
Network specific options take precedence over non-network specific options.
diff --git a/share/examples/bitcoin.conf b/share/examples/bitcoin.conf
index 90a592cc63..5b7fc776a4 100644
--- a/share/examples/bitcoin.conf
+++ b/share/examples/bitcoin.conf
@@ -4,13 +4,16 @@
# Network-related settings:
-# Note that if you use testnet or regtest, particularly with the options
+# Note that if you use testnet, signet or regtest, particularly with the options
# addnode, connect, port, bind, rpcport, rpcbind or wallet, you will also
# want to read "[Sections]" further down.
-# Run on the test network instead of the real bitcoin network.
+# Run on the testnet network
#testnet=0
+# Run on a signet network
+#signet=0
+
# Run a regression test network
#regtest=0
@@ -57,7 +60,7 @@
# Listening mode, enabled by default except when 'connect' is being used
#listen=1
-# Port on which to listen for connections (default: 8333, testnet: 18333, regtest: 18444)
+# Port on which to listen for connections (default: 8333, testnet: 18333, signet: 38333, regtest: 18444)
#port=
# Maximum number of inbound+outbound connections.
@@ -155,7 +158,7 @@
#minimizetotray=1
# [Sections]
-# Most options apply to mainnet, testnet and regtest.
+# Most options apply to mainnet, testnet, signet and regtest.
# If you want to confine an option to just one network, you should add it in the
# relevant section below.
# EXCEPTIONS: The options addnode, connect, port, bind, rpcport, rpcbind and wallet
@@ -167,5 +170,8 @@
# Options only for testnet
[test]
+# Options only for signet
+[signet]
+
# Options only for regtest
[regtest]
diff --git a/src/Makefile.am b/src/Makefile.am
index b36d67bab0..56f561a172 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -303,7 +303,7 @@ libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# Contains code accessing mempool and chain state that is meant to be separated
# from wallet and gui code (see node/README.md). Shared code should go in
# libbitcoin_common or libbitcoin_util libraries, instead.
-libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
+libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrdb.cpp \
diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include
index 75fe68fcd1..2d772f2fca 100644
--- a/src/Makefile.test_fuzz.include
+++ b/src/Makefile.test_fuzz.include
@@ -12,7 +12,7 @@ TEST_FUZZ_H = \
test/fuzz/FuzzedDataProvider.h \
test/fuzz/util.h
-libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
+libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libtest_fuzz_a_SOURCES = \
test/fuzz/fuzz.cpp \
diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include
index 1abfb667a0..f7f393ccac 100644
--- a/src/Makefile.test_util.include
+++ b/src/Makefile.test_util.include
@@ -19,7 +19,7 @@ TEST_UTIL_H = \
test/util/validation.h \
test/util/wallet.h
-libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
+libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libtest_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libtest_util_a_SOURCES = \
test/util/blockfilter.cpp \
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 1a49518d69..ebc5466173 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -159,6 +159,9 @@ public:
//! Check if transaction is RBF opt in.
virtual RBFTransactionState isRBFOptIn(const CTransaction& tx) = 0;
+ //! Check if transaction is in mempool.
+ virtual bool isInMempool(const uint256& txid) = 0;
+
//! Check if transaction has descendants in mempool.
virtual bool hasDescendantsInMempool(const uint256& txid) = 0;
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 15f7ef6256..1dd1e92e2f 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -6,9 +6,10 @@
#define BITCOIN_INTERFACES_NODE_H
#include <amount.h> // For CAmount
-#include <net.h> // For CConnman::NumConnections
+#include <net.h> // For NodeId
#include <net_types.h> // For banmap_t
#include <netaddress.h> // For Network
+#include <netbase.h> // For ConnectionDirection
#include <support/allocators/secure.h> // For SecureString
#include <util/translation.h>
@@ -88,7 +89,7 @@ public:
virtual bool getProxy(Network net, proxyType& proxy_info) = 0;
//! Get number of connections.
- virtual size_t getNodeCount(CConnman::NumConnections flags) = 0;
+ virtual size_t getNodeCount(ConnectionDirection flags) = 0;
//! Get stats for connected nodes.
using NodesStats = std::vector<std::tuple<CNodeStats, bool, CNodeStateStats>>;
diff --git a/src/net.cpp b/src/net.cpp
index 513328897b..cf7d3e50ba 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2725,15 +2725,15 @@ bool CConnman::RemoveAddedNode(const std::string& strNode)
return false;
}
-size_t CConnman::GetNodeCount(NumConnections flags)
+size_t CConnman::GetNodeCount(ConnectionDirection flags)
{
LOCK(cs_vNodes);
- if (flags == CConnman::CONNECTIONS_ALL) // Shortcut if we want total
+ if (flags == ConnectionDirection::Both) // Shortcut if we want total
return vNodes.size();
int nNum = 0;
for (const auto& pnode : vNodes) {
- if (flags & (pnode->IsInboundConn() ? CONNECTIONS_IN : CONNECTIONS_OUT)) {
+ if (flags & (pnode->IsInboundConn() ? ConnectionDirection::In : ConnectionDirection::Out)) {
nNum++;
}
}
diff --git a/src/net.h b/src/net.h
index f1d22ffed0..beef47f045 100644
--- a/src/net.h
+++ b/src/net.h
@@ -17,6 +17,7 @@
#include <i2p.h>
#include <net_permissions.h>
#include <netaddress.h>
+#include <netbase.h>
#include <optional.h>
#include <policy/feerate.h>
#include <protocol.h>
@@ -801,13 +802,6 @@ class CConnman
{
public:
- enum NumConnections {
- CONNECTIONS_NONE = 0,
- CONNECTIONS_IN = (1U << 0),
- CONNECTIONS_OUT = (1U << 1),
- CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
- };
-
struct Options
{
ServiceFlags nLocalServices = NODE_NONE;
@@ -976,7 +970,7 @@ public:
*/
bool AddConnection(const std::string& address, ConnectionType conn_type);
- size_t GetNodeCount(NumConnections num);
+ size_t GetNodeCount(ConnectionDirection);
void GetNodeStats(std::vector<CNodeStats>& vstats);
bool DisconnectNode(const std::string& node);
bool DisconnectNode(const CSubNet& subnet);
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index d19e11f7b1..638c39e6be 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -491,17 +491,17 @@ struct CNodeState {
//! The peer's address
const CService address;
//! The best known block we know this peer has announced.
- const CBlockIndex *pindexBestKnownBlock;
+ const CBlockIndex* pindexBestKnownBlock{nullptr};
//! The hash of the last unknown block this peer has announced.
- uint256 hashLastUnknownBlock;
+ uint256 hashLastUnknownBlock{};
//! The last full block we both have.
- const CBlockIndex *pindexLastCommonBlock;
+ const CBlockIndex* pindexLastCommonBlock{nullptr};
//! The best header we have sent our peer.
- const CBlockIndex *pindexBestHeaderSent;
+ const CBlockIndex* pindexBestHeaderSent{nullptr};
//! Length of current-streak of unconnecting headers announcements
- int nUnconnectingHeaders;
+ int nUnconnectingHeaders{0};
//! Whether we've started headers synchronization with this peer.
- bool fSyncStarted;
+ bool fSyncStarted{false};
//! When to potentially disconnect peer for stalling headers download
std::chrono::microseconds m_headers_sync_timeout{0us};
//! Since when we're stalling block download progress (in microseconds), or 0.
@@ -509,29 +509,29 @@ struct CNodeState {
std::list<QueuedBlock> vBlocksInFlight;
//! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
std::chrono::microseconds m_downloading_since{0us};
- int nBlocksInFlight;
- int nBlocksInFlightValidHeaders;
+ int nBlocksInFlight{0};
+ int nBlocksInFlightValidHeaders{0};
//! Whether we consider this a preferred download peer.
- bool fPreferredDownload;
+ bool fPreferredDownload{false};
//! Whether this peer wants invs or headers (when possible) for block announcements.
- bool fPreferHeaders;
+ bool fPreferHeaders{false};
//! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
- bool fPreferHeaderAndIDs;
+ bool fPreferHeaderAndIDs{false};
/**
* Whether this peer will send us cmpctblocks if we request them.
* This is not used to gate request logic, as we really only care about fSupportsDesiredCmpctVersion,
* but is used as a flag to "lock in" the version of compact blocks (fWantsCmpctWitness) we send.
*/
- bool fProvidesHeaderAndIDs;
+ bool fProvidesHeaderAndIDs{false};
//! Whether this peer can give us witnesses
- bool fHaveWitness;
+ bool fHaveWitness{false};
//! Whether this peer wants witnesses in cmpctblocks/blocktxns
- bool fWantsCmpctWitness;
+ bool fWantsCmpctWitness{false};
/**
* If we've announced NODE_WITNESS to this peer: whether the peer sends witnesses in cmpctblocks/blocktxns,
* otherwise: whether this peer sends non-witnesses in cmpctblocks/blocktxns.
*/
- bool fSupportsDesiredCmpctVersion;
+ bool fSupportsDesiredCmpctVersion{false};
/** State used to enforce CHAIN_SYNC_TIMEOUT and EXTRA_PEER_CHECK_INTERVAL logic.
*
@@ -568,13 +568,13 @@ struct CNodeState {
bool m_protect;
};
- ChainSyncTimeoutState m_chain_sync;
+ ChainSyncTimeoutState m_chain_sync{0, nullptr, false, false};
//! Time of last new block announcement
- int64_t m_last_block_announcement;
+ int64_t m_last_block_announcement{0};
//! Whether this peer is an inbound connection
- bool m_is_inbound;
+ const bool m_is_inbound;
//! A rolling bloom filter of all announced tx CInvs to this peer.
CRollingBloomFilter m_recently_announced_invs = CRollingBloomFilter{INVENTORY_MAX_RECENT_RELAY, 0.000001};
@@ -585,23 +585,6 @@ struct CNodeState {
CNodeState(CAddress addrIn, bool is_inbound)
: address(addrIn), m_is_inbound(is_inbound)
{
- pindexBestKnownBlock = nullptr;
- hashLastUnknownBlock.SetNull();
- pindexLastCommonBlock = nullptr;
- pindexBestHeaderSent = nullptr;
- nUnconnectingHeaders = 0;
- fSyncStarted = false;
- nBlocksInFlight = 0;
- nBlocksInFlightValidHeaders = 0;
- fPreferredDownload = false;
- fPreferHeaders = false;
- fPreferHeaderAndIDs = false;
- fProvidesHeaderAndIDs = false;
- fHaveWitness = false;
- fWantsCmpctWitness = false;
- fSupportsDesiredCmpctVersion = false;
- m_chain_sync = { 0, nullptr, false, false };
- m_last_block_announcement = 0;
m_recently_announced_invs.reset();
}
};
diff --git a/src/netbase.h b/src/netbase.h
index b225f128e7..751f7eb3f0 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -18,6 +18,7 @@
#include <memory>
#include <stdint.h>
#include <string>
+#include <type_traits>
#include <vector>
extern int nConnectTimeout;
@@ -28,6 +29,22 @@ static const int DEFAULT_CONNECT_TIMEOUT = 5000;
//! -dns default
static const int DEFAULT_NAME_LOOKUP = true;
+enum class ConnectionDirection {
+ None = 0,
+ In = (1U << 0),
+ Out = (1U << 1),
+ Both = (In | Out),
+};
+static inline ConnectionDirection& operator|=(ConnectionDirection& a, ConnectionDirection b) {
+ using underlying = typename std::underlying_type<ConnectionDirection>::type;
+ a = ConnectionDirection(underlying(a) | underlying(b));
+ return a;
+}
+static inline bool operator&(ConnectionDirection a, ConnectionDirection b) {
+ using underlying = typename std::underlying_type<ConnectionDirection>::type;
+ return (underlying(a) & underlying(b));
+}
+
class proxyType
{
public:
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index ec976fe9bf..62ef72ef38 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -96,7 +96,7 @@ public:
bool shutdownRequested() override { return ShutdownRequested(); }
void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
- size_t getNodeCount(CConnman::NumConnections flags) override
+ size_t getNodeCount(ConnectionDirection flags) override
{
return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0;
}
@@ -526,6 +526,12 @@ public:
LOCK(m_node.mempool->cs);
return IsRBFOptIn(tx, *m_node.mempool);
}
+ bool isInMempool(const uint256& txid) override
+ {
+ if (!m_node.mempool) return false;
+ LOCK(m_node.mempool->cs);
+ return m_node.mempool->exists(txid);
+ }
bool hasDescendantsInMempool(const uint256& txid) override
{
if (!m_node.mempool) return false;
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index bb444f22b3..ee2462ed74 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -198,42 +198,38 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const
AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
- if(role == Qt::DisplayRole || role == Qt::EditRole)
- {
- switch(index.column())
- {
+ const auto column = static_cast<ColumnIndex>(index.column());
+ if (role == Qt::DisplayRole || role == Qt::EditRole) {
+ switch (column) {
case Label:
- if(rec->label.isEmpty() && role == Qt::DisplayRole)
- {
+ if (rec->label.isEmpty() && role == Qt::DisplayRole) {
return tr("(no label)");
- }
- else
- {
+ } else {
return rec->label;
}
case Address:
return rec->address;
- }
- }
- else if (role == Qt::FontRole)
- {
- QFont font;
- if(index.column() == Address)
- {
- font = GUIUtil::fixedPitchFont();
- }
- return font;
- }
- else if (role == TypeRole)
- {
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+ } else if (role == Qt::FontRole) {
+ switch (column) {
+ case Label:
+ return QFont();
+ case Address:
+ return GUIUtil::fixedPitchFont();
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+ } else if (role == TypeRole) {
switch(rec->type)
{
case AddressTableEntry::Sending:
return Send;
case AddressTableEntry::Receiving:
return Receive;
- default: break;
- }
+ case AddressTableEntry::Hidden:
+ return {};
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
return QVariant();
}
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index a01a7bc386..6cb4a4c546 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -23,15 +23,13 @@ bool BannedNodeLessThan::operator()(const CCombinedBan& left, const CCombinedBan
if (order == Qt::DescendingOrder)
std::swap(pLeft, pRight);
- switch(column)
- {
+ switch (static_cast<BanTableModel::ColumnIndex>(column)) {
case BanTableModel::Address:
return pLeft->subnet.ToString().compare(pRight->subnet.ToString()) < 0;
case BanTableModel::Bantime:
return pLeft->banEntry.nBanUntil < pRight->banEntry.nBanUntil;
- }
-
- return false;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
// private implementation
@@ -119,16 +117,17 @@ QVariant BanTableModel::data(const QModelIndex &index, int role) const
CCombinedBan *rec = static_cast<CCombinedBan*>(index.internalPointer());
+ const auto column = static_cast<ColumnIndex>(index.column());
if (role == Qt::DisplayRole) {
- switch(index.column())
- {
+ switch (column) {
case Address:
return QString::fromStdString(rec->subnet.ToString());
case Bantime:
QDateTime date = QDateTime::fromMSecsSinceEpoch(0);
date = date.addSecs(rec->banEntry.nBanUntil);
return QLocale::system().toString(date, QLocale::LongFormat);
- }
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
return QVariant();
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 56813b2d19..b244bc94f2 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -71,14 +71,14 @@ ClientModel::~ClientModel()
int ClientModel::getNumConnections(unsigned int flags) const
{
- CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE;
+ ConnectionDirection connections = ConnectionDirection::None;
if(flags == CONNECTIONS_IN)
- connections = CConnman::CONNECTIONS_IN;
+ connections = ConnectionDirection::In;
else if (flags == CONNECTIONS_OUT)
- connections = CConnman::CONNECTIONS_OUT;
+ connections = ConnectionDirection::Out;
else if (flags == CONNECTIONS_ALL)
- connections = CConnman::CONNECTIONS_ALL;
+ connections = ConnectionDirection::Both;
return m_node.getNodeCount(connections);
}
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index b82143e1ba..f85de0811a 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -68,7 +68,7 @@
</property>
<property name="maximumSize">
<size>
- <width>30</width>
+ <width>45</width>
<height>16777215</height>
</size>
</property>
@@ -89,9 +89,6 @@
<height>24</height>
</size>
</property>
- <property name="flat">
- <bool>true</bool>
- </property>
</widget>
</item>
<item>
@@ -406,7 +403,7 @@
</property>
<property name="maximumSize">
<size>
- <width>30</width>
+ <width>45</width>
<height>16777215</height>
</size>
</property>
@@ -427,9 +424,6 @@
<height>24</height>
</size>
</property>
- <property name="flat">
- <bool>true</bool>
- </property>
</widget>
</item>
<item>
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 448024d657..3459bf4cf8 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -23,8 +23,7 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
if (order == Qt::DescendingOrder)
std::swap(pLeft, pRight);
- switch(column)
- {
+ switch (static_cast<PeerTableModel::ColumnIndex>(column)) {
case PeerTableModel::NetNodeId:
return pLeft->nodeid < pRight->nodeid;
case PeerTableModel::Address:
@@ -41,9 +40,8 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
return pLeft->nRecvBytes < pRight->nRecvBytes;
case PeerTableModel::Subversion:
return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
- }
-
- return false;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
// private implementation
@@ -157,9 +155,9 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
+ const auto column = static_cast<ColumnIndex>(index.column());
if (role == Qt::DisplayRole) {
- switch(index.column())
- {
+ switch (column) {
case NetNodeId:
return (qint64)rec->nodeStats.nodeid;
case Address:
@@ -177,19 +175,24 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);
case Subversion:
return QString::fromStdString(rec->nodeStats.cleanSubVer);
- }
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
} else if (role == Qt::TextAlignmentRole) {
- switch (index.column()) {
- case ConnectionType:
- case Network:
- return QVariant(Qt::AlignCenter);
- case Ping:
- case Sent:
- case Received:
- return QVariant(Qt::AlignRight | Qt::AlignVCenter);
- default:
- return QVariant();
- }
+ switch (column) {
+ case NetNodeId:
+ case Address:
+ return {};
+ case ConnectionType:
+ case Network:
+ return QVariant(Qt::AlignCenter);
+ case Ping:
+ case Sent:
+ case Received:
+ return QVariant(Qt::AlignRight | Qt::AlignVCenter);
+ case Subversion:
+ return {};
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
} else if (role == StatsRole) {
switch (index.column()) {
case NetNodeId: return QVariant::fromValue(rec);
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 68adad4ebd..b258219894 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -474,9 +474,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
const QString list{"<ul><li>" + Join(CONNECTION_TYPE_DOC, QString("</li><li>")) + "</li></ul>"};
ui->peerConnectionTypeLabel->setToolTip(ui->peerConnectionTypeLabel->toolTip().arg(list));
const QString hb_list{"<ul><li>\""
- + tr("To") + "\" – " + tr("we selected the peer for high bandwidth relay") + "</li><li>\""
- + tr("From") + "\" – " + tr("the peer selected us for high bandwidth relay") + "</li><li>\""
- + tr("No") + "\" – " + tr("no high bandwidth relay selected") + "</li></ul>"};
+ + ts.to + "\" – " + tr("we selected the peer for high bandwidth relay") + "</li><li>\""
+ + ts.from + "\" – " + tr("the peer selected us for high bandwidth relay") + "</li><li>\""
+ + ts.no + "\" – " + tr("no high bandwidth relay selected") + "</li></ul>"};
ui->peerHighBandwidthLabel->setToolTip(ui->peerHighBandwidthLabel->toolTip().arg(hb_list));
ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir"));
@@ -619,10 +619,10 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
// create peer table context menu actions
QAction* disconnectAction = new QAction(tr("&Disconnect"), this);
- QAction* banAction1h = new QAction(tr("Ban for") + " " + tr("1 &hour"), this);
- QAction* banAction24h = new QAction(tr("Ban for") + " " + tr("1 &day"), this);
- QAction* banAction7d = new QAction(tr("Ban for") + " " + tr("1 &week"), this);
- QAction* banAction365d = new QAction(tr("Ban for") + " " + tr("1 &year"), this);
+ QAction* banAction1h = new QAction(ts.ban_for + " " + tr("1 &hour"), this);
+ QAction* banAction24h = new QAction(ts.ban_for + " " + tr("1 &day"), this);
+ QAction* banAction7d = new QAction(ts.ban_for + " " + tr("1 &week"), this);
+ QAction* banAction365d = new QAction(ts.ban_for + " " + tr("1 &year"), this);
// create peer table context menu
peersTableContextMenu = new QMenu(this);
@@ -1114,11 +1114,11 @@ void RPCConsole::updateDetailWidget()
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails);
ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
- ui->peerRelayTxes->setText(stats->nodeStats.fRelayTxes ? "Yes" : "No");
+ ui->peerRelayTxes->setText(stats->nodeStats.fRelayTxes ? ts.yes : ts.no);
QString bip152_hb_settings;
- if (stats->nodeStats.m_bip152_highbandwidth_to) bip152_hb_settings += "To";
- if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings == "" ? "From" : "/From");
- if (bip152_hb_settings == "") bip152_hb_settings = "No";
+ if (stats->nodeStats.m_bip152_highbandwidth_to) bip152_hb_settings = ts.to;
+ if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings.isEmpty() ? ts.from : QLatin1Char('/') + ts.from);
+ if (bip152_hb_settings.isEmpty()) bip152_hb_settings = ts.no;
ui->peerHighBandwidth->setText(bip152_hb_settings);
const int64_t time_now{GetSystemTimeInSeconds()};
ui->peerConnTime->setText(GUIUtil::formatDurationStr(time_now - stats->nodeStats.nTimeConnected));
@@ -1136,7 +1136,7 @@ void RPCConsole::updateDetailWidget()
ui->peerConnectionType->setText(GUIUtil::ConnectionTypeToQString(stats->nodeStats.m_conn_type, /* prepend_direction */ true));
ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network));
if (stats->nodeStats.m_permissionFlags == PF_NONE) {
- ui->peerPermissions->setText(tr("N/A"));
+ ui->peerPermissions->setText(ts.na);
} else {
QStringList permissions;
for (const auto& permission : NetPermissions::ToStrings(stats->nodeStats.m_permissionFlags)) {
@@ -1144,23 +1144,23 @@ void RPCConsole::updateDetailWidget()
}
ui->peerPermissions->setText(permissions.join(" & "));
}
- ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) : tr("N/A"));
+ ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) : ts.na);
// This check fails for example if the lock was busy and
// nodeStateStats couldn't be fetched.
if (stats->fNodeStateStatsAvailable) {
// Sync height is init to -1
- if (stats->nodeStateStats.nSyncHeight > -1)
+ if (stats->nodeStateStats.nSyncHeight > -1) {
ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight));
- else
- ui->peerSyncHeight->setText(tr("Unknown"));
-
+ } else {
+ ui->peerSyncHeight->setText(ts.unknown);
+ }
// Common height is init to -1
- if (stats->nodeStateStats.nCommonHeight > -1)
+ if (stats->nodeStateStats.nCommonHeight > -1) {
ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight));
- else
- ui->peerCommonHeight->setText(tr("Unknown"));
-
+ } else {
+ ui->peerCommonHeight->setText(ts.unknown);
+ }
ui->peerHeight->setText(QString::number(stats->nodeStateStats.m_starting_height));
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStateStats.m_ping_wait));
}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 27d4c42eb4..b9806e40c9 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -136,6 +136,11 @@ Q_SIGNALS:
void cmdRequest(const QString &command, const WalletModel* wallet_model);
private:
+ struct TranslatedStrings {
+ const QString yes{tr("Yes")}, no{tr("No")}, to{tr("To")}, from{tr("From")},
+ ban_for{tr("Ban for")}, na{tr("N/A")}, unknown{tr("Unknown")};
+ } const ts;
+
void startExecutor();
void setTrafficGraphRange(int mins);
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 9ef5fe8fc7..a1baf6a402 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -54,6 +54,13 @@ int main(int argc, char* argv[])
NodeContext node_context;
std::unique_ptr<interfaces::Node> node = interfaces::MakeNode(&node_context);
+ gArgs.ForceSetArg("-listen", "0");
+ gArgs.ForceSetArg("-listenonion", "0");
+ gArgs.ForceSetArg("-discover", "0");
+ gArgs.ForceSetArg("-dnsseed", "0");
+ gArgs.ForceSetArg("-fixedseeds", "0");
+ gArgs.ForceSetArg("-upnp", "0");
+ gArgs.ForceSetArg("-natpmp", "0");
bool fInvalid = false;
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index e6d483364c..a7556eed04 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -526,27 +526,30 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
return QVariant();
TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
- switch(role)
- {
+ const auto column = static_cast<ColumnIndex>(index.column());
+ switch (role) {
case RawDecorationRole:
- switch(index.column())
- {
+ switch (column) {
case Status:
return txStatusDecoration(rec);
case Watchonly:
return txWatchonlyDecoration(rec);
+ case Date: return {};
+ case Type: return {};
case ToAddress:
return txAddressDecoration(rec);
- }
- break;
+ case Amount: return {};
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
case Qt::DecorationRole:
{
QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
return platformStyle->TextColorIcon(icon);
}
case Qt::DisplayRole:
- switch(index.column())
- {
+ switch (column) {
+ case Status: return {};
+ case Watchonly: return {};
case Date:
return formatTxDate(rec);
case Type:
@@ -555,12 +558,11 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
return formatTxToAddress(rec, false);
case Amount:
return formatTxAmount(rec, true, BitcoinUnits::SeparatorStyle::ALWAYS);
- }
- break;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
case Qt::EditRole:
// Edit role is used for sorting, so return the unformatted values
- switch(index.column())
- {
+ switch (column) {
case Status:
return QString::fromStdString(rec->status.sortKey);
case Date:
@@ -573,8 +575,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
return formatTxToAddress(rec, true);
case Amount:
return qint64(rec->credit + rec->debit);
- }
- break;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
case Qt::ToolTipRole:
return formatTooltip(rec);
case Qt::TextAlignmentRole:
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 50987a735b..f29f556517 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -659,7 +659,7 @@ static RPCHelpMan getblocktemplate()
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
if (!Params().IsTestChain()) {
- if (node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) {
+ if (node.connman->GetNodeCount(ConnectionDirection::Both) == 0) {
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 6d33654c6f..cf4d46cf2c 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -57,7 +57,7 @@ static RPCHelpMan getconnectioncount()
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- return (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
+ return (int)node.connman->GetNodeCount(ConnectionDirection::Both);
},
};
}
@@ -630,9 +630,9 @@ static RPCHelpMan getnetworkinfo()
obj.pushKV("timeoffset", GetTimeOffset());
if (node.connman) {
obj.pushKV("networkactive", node.connman->GetNetworkActive());
- obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
- obj.pushKV("connections_in", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_IN));
- obj.pushKV("connections_out", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_OUT));
+ obj.pushKV("connections", (int)node.connman->GetNodeCount(ConnectionDirection::Both));
+ obj.pushKV("connections_in", (int)node.connman->GetNodeCount(ConnectionDirection::In));
+ obj.pushKV("connections_out", (int)node.connman->GetNodeCount(ConnectionDirection::Out));
}
obj.pushKV("networks", GetNetworksInfo());
obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index ecac3b9e7e..20a4ce48b0 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1834,7 +1834,7 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& program, const CScript& script, uint256& tapleaf_hash)
{
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
- //! The inner pubkey (x-only, so no Y coordinate parity).
+ //! The internal pubkey (x-only, so no Y coordinate parity).
const XOnlyPubKey p{uint256(std::vector<unsigned char>(control.begin() + 1, control.begin() + TAPROOT_CONTROL_BASE_SIZE))};
//! The output pubkey (taken from the scriptPubKey).
const XOnlyPubKey q{uint256(program)};
@@ -1852,9 +1852,9 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
}
k = ss_branch.GetSHA256();
}
- // Compute the tweak from the Merkle root and the inner pubkey.
+ // Compute the tweak from the Merkle root and the internal pubkey.
k = (CHashWriter(HASHER_TAPTWEAK) << MakeSpan(p) << k).GetSHA256();
- // Verify that the output pubkey matches the tweaked inner pubkey, after correcting for parity.
+ // Verify that the output pubkey matches the tweaked internal pubkey, after correcting for parity.
return q.CheckPayToContract(p, k, control[0] & 1);
}
diff --git a/src/test/fuzz/FuzzedDataProvider.h b/src/test/fuzz/FuzzedDataProvider.h
index 744a9d78ce..6cbfc39bc2 100644
--- a/src/test/fuzz/FuzzedDataProvider.h
+++ b/src/test/fuzz/FuzzedDataProvider.h
@@ -20,6 +20,7 @@
#include <cstdint>
#include <cstring>
#include <initializer_list>
+#include <limits>
#include <string>
#include <type_traits>
#include <utility>
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 663d4fee8b..ae77a45e44 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -95,7 +95,7 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
(void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
},
[&] {
- (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL}));
+ (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({ConnectionDirection::None, ConnectionDirection::In, ConnectionDirection::Out, ConnectionDirection::Both}));
},
[&] {
connman.MarkAddressGood(random_address);
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index d708dabb49..d8c536e8b1 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -10,6 +10,7 @@
#include <attributes.h>
#include <chainparamsbase.h>
#include <coins.h>
+#include <compat.h>
#include <consensus/consensus.h>
#include <merkleblock.h>
#include <net.h>
@@ -542,14 +543,22 @@ public:
{
}
+ FuzzedSock& operator=(Sock&& other) override
+ {
+ assert(false && "Not implemented yet.");
+ return *this;
+ }
+
SOCKET Get() const override
{
assert(false && "Not implemented yet.");
+ return INVALID_SOCKET;
}
SOCKET Release() override
{
assert(false && "Not implemented yet.");
+ return INVALID_SOCKET;
}
void Reset() override
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 50444f7bbe..8841a540f2 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -14,6 +14,18 @@
/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */
static int32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; }
+static const std::string StateName(ThresholdState state)
+{
+ switch (state) {
+ case ThresholdState::DEFINED: return "DEFINED";
+ case ThresholdState::STARTED: return "STARTED";
+ case ThresholdState::LOCKED_IN: return "LOCKED_IN";
+ case ThresholdState::ACTIVE: return "ACTIVE";
+ case ThresholdState::FAILED: return "FAILED";
+ } // no default case, so the compiler can warn about missing cases
+ return "";
+}
+
static const Consensus::Params paramsDummy = Consensus::Params();
class TestConditionChecker : public AbstractThresholdConditionChecker
@@ -38,6 +50,13 @@ public:
int64_t BeginTime(const Consensus::Params& params) const override { return Consensus::BIP9Deployment::ALWAYS_ACTIVE; }
};
+class TestNeverActiveConditionChecker : public TestConditionChecker
+{
+public:
+ int64_t BeginTime(const Consensus::Params& params) const override { return 0; }
+ int64_t EndTime(const Consensus::Params& params) const override { return 1230768000; }
+};
+
#define CHECKERS 6
class VersionBitsTester
@@ -51,6 +70,8 @@ class VersionBitsTester
TestConditionChecker checker[CHECKERS];
// Another 6 that assume always active activation
TestAlwaysActiveConditionChecker checker_always[CHECKERS];
+ // Another 6 that assume never active activation
+ TestNeverActiveConditionChecker checker_never[CHECKERS];
// Test counter (to identify failures)
int num;
@@ -65,6 +86,7 @@ public:
for (unsigned int i = 0; i < CHECKERS; i++) {
checker[i] = TestConditionChecker();
checker_always[i] = TestAlwaysActiveConditionChecker();
+ checker_never[i] = TestNeverActiveConditionChecker();
}
vpblock.clear();
return *this;
@@ -92,66 +114,40 @@ public:
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num));
BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == 0, strprintf("Test %i for StateSinceHeight (always active)", num));
- }
- }
- num++;
- return *this;
- }
- VersionBitsTester& TestDefined() {
- for (int i = 0; i < CHECKERS; i++) {
- if (InsecureRandBits(i) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::DEFINED, strprintf("Test %i for DEFINED", num));
- BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
+ // never active may go from DEFINED -> FAILED at the first period
+ const auto never_height = checker_never[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back());
+ BOOST_CHECK_MESSAGE(never_height == 0 || never_height == checker_never[i].Period(paramsDummy), strprintf("Test %i for StateSinceHeight (never active)", num));
}
}
num++;
return *this;
}
- VersionBitsTester& TestStarted() {
+ VersionBitsTester& TestState(ThresholdState exp) {
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::STARTED, strprintf("Test %i for STARTED", num));
- BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
+ const CBlockIndex* pindex = vpblock.empty() ? nullptr : vpblock.back();
+ ThresholdState got = checker[i].GetStateFor(pindex);
+ ThresholdState got_always = checker_always[i].GetStateFor(pindex);
+ ThresholdState got_never = checker_never[i].GetStateFor(pindex);
+ // nHeight of the next block. If vpblock is empty, the next (ie first)
+ // block should be the genesis block with nHeight == 0.
+ int height = pindex == nullptr ? 0 : pindex->nHeight + 1;
+ BOOST_CHECK_MESSAGE(got == exp, strprintf("Test %i for %s height %d (got %s)", num, StateName(exp), height, StateName(got)));
+ BOOST_CHECK_MESSAGE(got_always == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE height %d (got %s; always active case)", num, height, StateName(got_always)));
+ BOOST_CHECK_MESSAGE(got_never == ThresholdState::DEFINED|| got_never == ThresholdState::FAILED, strprintf("Test %i for DEFINED/FAILED height %d (got %s; never active case)", num, height, StateName(got_never)));
}
}
num++;
return *this;
}
- VersionBitsTester& TestLockedIn() {
- for (int i = 0; i < CHECKERS; i++) {
- if (InsecureRandBits(i) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::LOCKED_IN, strprintf("Test %i for LOCKED_IN", num));
- BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
- }
- }
- num++;
- return *this;
- }
-
- VersionBitsTester& TestActive() {
- for (int i = 0; i < CHECKERS; i++) {
- if (InsecureRandBits(i) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE", num));
- BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
- }
- }
- num++;
- return *this;
- }
-
- VersionBitsTester& TestFailed() {
- for (int i = 0; i < CHECKERS; i++) {
- if (InsecureRandBits(i) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::FAILED, strprintf("Test %i for FAILED", num));
- BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
- }
- }
- num++;
- return *this;
- }
+ VersionBitsTester& TestDefined() { return TestState(ThresholdState::DEFINED); }
+ VersionBitsTester& TestStarted() { return TestState(ThresholdState::STARTED); }
+ VersionBitsTester& TestLockedIn() { return TestState(ThresholdState::LOCKED_IN); }
+ VersionBitsTester& TestActive() { return TestState(ThresholdState::ACTIVE); }
+ VersionBitsTester& TestFailed() { return TestState(ThresholdState::FAILED); }
CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : nullptr; }
};
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 5e319d4f95..08adf09df4 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -190,7 +190,7 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
if (coin_control.m_feerate) {
// The user provided a feeRate argument.
// We calculate this here to avoid compiler warning on the cs_wallet lock
- const int64_t maxTxSize = CalculateMaximumSignedTxSize(*wtx.tx, &wallet);
+ const int64_t maxTxSize = CalculateMaximumSignedTxSize(*wtx.tx, &wallet).first;
Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, errors);
if (res != Result::OK) {
return res;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 08e480225d..58ab124061 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -791,6 +791,12 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
wtx.mapValue["replaced_by_txid"] = newHash.ToString();
+ // Refresh mempool status without waiting for transactionRemovedFromMempool
+ // notification so the wallet is in an internally consistent state and
+ // immediately knows the old transaction should not be considered trusted
+ // and is eligible to be abandoned
+ wtx.fInMempool = chain().isInMempool(originalHash);
+
WalletBatch batch(GetDatabase());
bool success = true;
@@ -1611,14 +1617,15 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri
return true;
}
-int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig)
+// Returns pair of vsize and weight
+std::pair<int64_t, int64_t> CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig)
{
std::vector<CTxOut> txouts;
for (const CTxIn& input : tx.vin) {
const auto mi = wallet->mapWallet.find(input.prevout.hash);
// Can not estimate size without knowing the input details
if (mi == wallet->mapWallet.end()) {
- return -1;
+ return std::make_pair(-1, -1);
}
assert(input.prevout.n < mi->second.tx->vout.size());
txouts.emplace_back(mi->second.tx->vout[input.prevout.n]);
@@ -1627,13 +1634,16 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall
}
// txouts needs to be in the order of tx.vin
-int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig)
+std::pair<int64_t, int64_t> CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig)
{
CMutableTransaction txNew(tx);
if (!wallet->DummySignTx(txNew, txouts, use_max_sig)) {
- return -1;
+ return std::make_pair(-1, -1);
}
- return GetVirtualTransactionSize(CTransaction(txNew));
+ CTransaction ctx(txNew);
+ int64_t vsize = GetVirtualTransactionSize(ctx);
+ int64_t weight = GetTransactionWeight(ctx);
+ return std::make_pair(vsize, weight);
}
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, bool use_max_sig)
@@ -2779,6 +2789,7 @@ bool CWallet::CreateTransactionInternal(
CMutableTransaction txNew;
FeeCalculation feeCalc;
CAmount nFeeNeeded;
+ std::pair<int64_t, int64_t> tx_sizes;
int nBytes;
{
std::set<CInputCoin> setCoins;
@@ -2962,7 +2973,8 @@ bool CWallet::CreateTransactionInternal(
txNew.vin.push_back(CTxIn(coin.outpoint,CScript()));
}
- nBytes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly);
+ tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly);
+ nBytes = tx_sizes.first;
if (nBytes < 0) {
error = _("Signing transaction failed");
return false;
@@ -3072,7 +3084,8 @@ bool CWallet::CreateTransactionInternal(
tx = MakeTransactionRef(std::move(txNew));
// Limit size
- if (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT)
+ if ((sign && GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT) ||
+ (!sign && tx_sizes.second > MAX_STANDARD_TX_WEIGHT))
{
error = _("Transaction too large");
return false;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index eb797938cd..3a76163dd2 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1334,8 +1334,8 @@ public:
// Use DummySignatureCreator, which inserts 71 byte signatures everywhere.
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// be IsAllFromMe).
-int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
-int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig = false);
+std::pair<int64_t, int64_t> CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
+std::pair<int64_t, int64_t> CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig = false);
//! Add wallet name to persistent configuration so it will be loaded on startup.
bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 5027a9828f..183a43abd4 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -177,17 +177,17 @@ def default_negflag(ctx):
"""Default expression for "negflag": tap.negflag."""
return get(ctx, "tap").negflag
-def default_pubkey_inner(ctx):
- """Default expression for "pubkey_inner": tap.inner_pubkey."""
- return get(ctx, "tap").inner_pubkey
+def default_pubkey_internal(ctx):
+ """Default expression for "pubkey_internal": tap.internal_pubkey."""
+ return get(ctx, "tap").internal_pubkey
def default_merklebranch(ctx):
"""Default expression for "merklebranch": tapleaf.merklebranch."""
return get(ctx, "tapleaf").merklebranch
def default_controlblock(ctx):
- """Default expression for "controlblock": combine leafversion, negflag, pubkey_inner, merklebranch."""
- return bytes([get(ctx, "leafversion") + get(ctx, "negflag")]) + get(ctx, "pubkey_inner") + get(ctx, "merklebranch")
+ """Default expression for "controlblock": combine leafversion, negflag, pubkey_internal, merklebranch."""
+ return bytes([get(ctx, "leafversion") + get(ctx, "negflag")]) + get(ctx, "pubkey_internal") + get(ctx, "merklebranch")
def default_sighash(ctx):
"""Default expression for "sighash": depending on mode, compute BIP341, BIP143, or legacy sighash."""
@@ -341,9 +341,9 @@ DEFAULT_CONTEXT = {
"tapleaf": default_tapleaf,
# The script to push, and include in the sighash, for a taproot script path spend.
"script_taproot": default_script_taproot,
- # The inner pubkey for a taproot script path spend (32 bytes).
- "pubkey_inner": default_pubkey_inner,
- # The negation flag of the inner pubkey for a taproot script path spend.
+ # The internal pubkey for a taproot script path spend (32 bytes).
+ "pubkey_internal": default_pubkey_internal,
+ # The negation flag of the internal pubkey for a taproot script path spend.
"negflag": default_negflag,
# The leaf version to include in the sighash (this does not affect the one in the control block).
"leafversion": default_leafversion,
@@ -780,8 +780,8 @@ def spenders_taproot_active():
add_spender(spenders, "spendpath/negflag", tap=tap, leaf="128deep", **SINGLE_SIG, key=secs[0], failure={"negflag": lambda ctx: 1 - default_negflag(ctx)}, **ERR_WITNESS_PROGRAM_MISMATCH)
# Test that bitflips in the Merkle branch invalidate it.
add_spender(spenders, "spendpath/bitflipmerkle", tap=tap, leaf="128deep", **SINGLE_SIG, key=secs[0], failure={"merklebranch": bitflipper(default_merklebranch)}, **ERR_WITNESS_PROGRAM_MISMATCH)
- # Test that bitflips in the inner pubkey invalidate it.
- add_spender(spenders, "spendpath/bitflippubkey", tap=tap, leaf="128deep", **SINGLE_SIG, key=secs[0], failure={"pubkey_inner": bitflipper(default_pubkey_inner)}, **ERR_WITNESS_PROGRAM_MISMATCH)
+ # Test that bitflips in the internal pubkey invalidate it.
+ add_spender(spenders, "spendpath/bitflippubkey", tap=tap, leaf="128deep", **SINGLE_SIG, key=secs[0], failure={"pubkey_internal": bitflipper(default_pubkey_internal)}, **ERR_WITNESS_PROGRAM_MISMATCH)
# Test that empty witnesses are invalid.
add_spender(spenders, "spendpath/emptywit", tap=tap, leaf="128deep", **SINGLE_SIG, key=secs[0], failure={"witness": []}, **ERR_EMPTY_WITNESS)
# Test that adding garbage to the control block invalidates it.
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 12b8b7baff..71d5ca92b3 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -4,8 +4,8 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test message sending before handshake completion.
-A node should never send anything other than VERSION/VERACK until it's
-received a VERACK.
+Before receiving a VERACK, a node should not send anything but VERSION/VERACK
+and feature negotiation messages (WTXIDRELAY, SENDADDRV2).
This test connects to a node and sends it a few messages, trying to entice it
into sending us something it shouldn't."""
@@ -35,10 +35,12 @@ class LazyPeer(P2PInterface):
super().__init__()
self.unexpected_msg = False
self.ever_connected = False
+ self.got_wtxidrelay = False
+ self.got_sendaddrv2 = False
def bad_message(self, message):
self.unexpected_msg = True
- self.log.info("should not have received message: %s" % message.msgtype)
+ print("should not have received message: %s" % message.msgtype)
def on_open(self):
self.ever_connected = True
@@ -64,6 +66,8 @@ class LazyPeer(P2PInterface):
def on_cmpctblock(self, message): self.bad_message(message)
def on_getblocktxn(self, message): self.bad_message(message)
def on_blocktxn(self, message): self.bad_message(message)
+ def on_wtxidrelay(self, message): self.got_wtxidrelay = True
+ def on_sendaddrv2(self, message): self.got_sendaddrv2 = True
# Peer that sends a version but not a verack.
@@ -94,32 +98,61 @@ class P2PVersionStore(P2PInterface):
class P2PLeakTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
+ self.extra_args = [['-peertimeout=4']]
+
+ def create_old_version(self, nversion):
+ old_version_msg = msg_version()
+ old_version_msg.nVersion = nversion
+ old_version_msg.strSubVer = P2P_SUBVERSION
+ old_version_msg.nServices = P2P_SERVICES
+ old_version_msg.relay = P2P_VERSION_RELAY
+ return old_version_msg
def run_test(self):
- # Another peer that never sends a version, nor any other messages. It shouldn't receive anything from the node.
+ self.log.info('Check that the node doesn\'t send unexpected messages before handshake completion')
+ # Peer that never sends a version, nor any other messages. It shouldn't receive anything from the node.
no_version_idle_peer = self.nodes[0].add_p2p_connection(LazyPeer(), send_version=False, wait_for_verack=False)
# Peer that sends a version but not a verack.
no_verack_idle_peer = self.nodes[0].add_p2p_connection(NoVerackIdlePeer(), wait_for_verack=False)
- # Wait until we got the verack in response to the version. Though, don't wait for the node to receive the
- # verack, since we never sent one
+ # Pre-wtxidRelay peer that sends a version but not a verack and does not support feature negotiation
+ # messages which start at nVersion == 70016
+ pre_wtxidrelay_peer = self.nodes[0].add_p2p_connection(NoVerackIdlePeer(), send_version=False, wait_for_verack=False)
+ pre_wtxidrelay_peer.send_message(self.create_old_version(70015))
+
+ # Wait until the peer gets the verack in response to the version. Though, don't wait for the node to receive the
+ # verack, since the peer never sent one
no_verack_idle_peer.wait_for_verack()
+ pre_wtxidrelay_peer.wait_for_verack()
no_version_idle_peer.wait_until(lambda: no_version_idle_peer.ever_connected)
no_verack_idle_peer.wait_until(lambda: no_verack_idle_peer.version_received)
+ pre_wtxidrelay_peer.wait_until(lambda: pre_wtxidrelay_peer.version_received)
# Mine a block and make sure that it's not sent to the connected peers
self.nodes[0].generate(nblocks=1)
- #Give the node enough time to possibly leak out a message
+ # Give the node enough time to possibly leak out a message
time.sleep(5)
- self.nodes[0].disconnect_p2ps()
+ # Make sure only expected messages came in
+ assert not no_version_idle_peer.unexpected_msg
+ assert not no_version_idle_peer.got_wtxidrelay
+ assert not no_version_idle_peer.got_sendaddrv2
- # Make sure no unexpected messages came in
- assert no_version_idle_peer.unexpected_msg == False
- assert no_verack_idle_peer.unexpected_msg == False
+ assert not no_verack_idle_peer.unexpected_msg
+ assert no_verack_idle_peer.got_wtxidrelay
+ assert no_verack_idle_peer.got_sendaddrv2
+
+ assert not pre_wtxidrelay_peer.unexpected_msg
+ assert not pre_wtxidrelay_peer.got_wtxidrelay
+ assert not pre_wtxidrelay_peer.got_sendaddrv2
+
+ # Expect peers to be disconnected due to timeout
+ assert not no_version_idle_peer.is_connected
+ assert not no_verack_idle_peer.is_connected
+ assert not pre_wtxidrelay_peer.is_connected
self.log.info('Check that the version message does not leak the local address of the node')
p2p_version_store = self.nodes[0].add_p2p_connection(P2PVersionStore())
@@ -134,13 +167,8 @@ class P2PLeakTest(BitcoinTestFramework):
self.log.info('Check that old peers are disconnected')
p2p_old_peer = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False)
- old_version_msg = msg_version()
- old_version_msg.nVersion = 31799
- old_version_msg.strSubVer = P2P_SUBVERSION
- old_version_msg.nServices = P2P_SERVICES
- old_version_msg.relay = P2P_VERSION_RELAY
- with self.nodes[0].assert_debug_log(['peer=3 using obsolete version 31799; disconnecting']):
- p2p_old_peer.send_message(old_version_msg)
+ with self.nodes[0].assert_debug_log(['peer=4 using obsolete version 31799; disconnecting']):
+ p2p_old_peer.send_message(self.create_old_version(31799))
p2p_old_peer.wait_for_disconnect()
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 569471dc87..6b300e7231 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -94,6 +94,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.test_address_reuse()
self.test_option_subtract_fee_from_outputs()
self.test_subtract_fee_with_presets()
+ self.test_transaction_too_large()
def test_change_position(self):
"""Ensure setting changePosition in fundraw with an exact match is handled properly."""
@@ -907,5 +908,24 @@ class RawTransactionsTest(BitcoinTestFramework):
signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx['hex'])
self.nodes[0].sendrawtransaction(signedtx['hex'])
+ def test_transaction_too_large(self):
+ self.log.info("Test fundrawtx where BnB solution would result in a too large transaction, but Knapsack would not")
+
+ self.nodes[0].createwallet("large")
+ wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ recipient = self.nodes[0].get_wallet_rpc("large")
+ outputs = {}
+ rawtx = recipient.createrawtransaction([], {wallet.getnewaddress(): 147.99899260})
+
+ # Make 1500 0.1 BTC outputs
+ # The amount that we target for funding is in the BnB range when these outputs are used.
+ # However if these outputs are selected, the transaction will end up being too large, so it shouldn't use BnB and instead fallback to Knapsack
+ # but that behavior is not implemented yet. For now we just check that we get an error.
+ for i in range(0, 1500):
+ outputs[recipient.getnewaddress()] = 0.1
+ wallet.sendmany("", outputs)
+ self.nodes[0].generate(10)
+ assert_raises_rpc_error(-4, "Transaction too large", recipient.fundrawtransaction, rawtx)
+
if __name__ == '__main__':
RawTransactionsTest().main()
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index c35533698c..3c9b8a6e69 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -826,11 +826,11 @@ def taproot_tree_helper(scripts):
# A TaprootInfo object has the following fields:
# - scriptPubKey: the scriptPubKey (witness v1 CScript)
-# - inner_pubkey: the inner pubkey (32 bytes)
-# - negflag: whether the pubkey in the scriptPubKey was negated from inner_pubkey+tweak*G (bool).
+# - internal_pubkey: the internal pubkey (32 bytes)
+# - negflag: whether the pubkey in the scriptPubKey was negated from internal_pubkey+tweak*G (bool).
# - tweak: the tweak (32 bytes)
# - leaves: a dict of name -> TaprootLeafInfo objects for all known leaves
-TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,inner_pubkey,negflag,tweak,leaves")
+TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,internal_pubkey,negflag,tweak,leaves")
# A TaprootLeafInfo object has the following fields:
# - script: the leaf script (CScript or bytes)
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 611061072f..eeff7a4515 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -27,7 +27,7 @@ def get_fuzz_env(*, target, source_dir):
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
- description='''Run the fuzz targets with all inputs from the seed_dir once.''',
+ description='''Run the fuzz targets with all inputs from the corpus_dir once.''',
)
parser.add_argument(
"-l",
@@ -54,8 +54,8 @@ def main():
help='How many targets to merge or execute in parallel.',
)
parser.add_argument(
- 'seed_dir',
- help='The seed corpus to run on (must contain subfolders for each fuzz target).',
+ 'corpus_dir',
+ help='The corpus to run on (must contain subfolders for each fuzz target).',
)
parser.add_argument(
'target',
@@ -64,15 +64,15 @@ def main():
)
parser.add_argument(
'--m_dir',
- help='Merge inputs from this directory into the seed_dir.',
+ help='Merge inputs from this directory into the corpus_dir.',
)
parser.add_argument(
'-g',
'--generate',
action='store_true',
- help='Create new corpus seeds (or extend the existing ones) by running'
+ help='Create new corpus (or extend the existing ones) by running'
' the given targets for a finite number of times. Outputs them to'
- ' the passed seed_dir.'
+ ' the passed corpus_dir.'
)
args = parser.parse_args()
@@ -119,19 +119,19 @@ def main():
logging.info("{} of {} detected fuzz target(s) selected: {}".format(len(test_list_selection), len(test_list_all), " ".join(test_list_selection)))
if not args.generate:
- test_list_seedless = []
+ test_list_missing_corpus = []
for t in test_list_selection:
- corpus_path = os.path.join(args.seed_dir, t)
+ corpus_path = os.path.join(args.corpus_dir, t)
if not os.path.exists(corpus_path) or len(os.listdir(corpus_path)) == 0:
- test_list_seedless.append(t)
- test_list_seedless.sort()
- if test_list_seedless:
+ test_list_missing_corpus.append(t)
+ test_list_missing_corpus.sort()
+ if test_list_missing_corpus:
logging.info(
- "Fuzzing harnesses lacking a seed corpus: {}".format(
- " ".join(test_list_seedless)
+ "Fuzzing harnesses lacking a corpus: {}".format(
+ " ".join(test_list_missing_corpus)
)
)
- logging.info("Please consider adding a fuzz seed corpus at https://github.com/bitcoin-core/qa-assets")
+ logging.info("Please consider adding a fuzz corpus at https://github.com/bitcoin-core/qa-assets")
try:
help_output = subprocess.run(
@@ -154,18 +154,18 @@ def main():
with ThreadPoolExecutor(max_workers=args.par) as fuzz_pool:
if args.generate:
- return generate_corpus_seeds(
+ return generate_corpus(
fuzz_pool=fuzz_pool,
src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
- seed_dir=args.seed_dir,
+ corpus_dir=args.corpus_dir,
targets=test_list_selection,
)
if args.m_dir:
merge_inputs(
fuzz_pool=fuzz_pool,
- corpus=args.seed_dir,
+ corpus=args.corpus_dir,
test_list=test_list_selection,
src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
@@ -175,7 +175,7 @@ def main():
run_once(
fuzz_pool=fuzz_pool,
- corpus=args.seed_dir,
+ corpus=args.corpus_dir,
test_list=test_list_selection,
src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
@@ -183,13 +183,13 @@ def main():
)
-def generate_corpus_seeds(*, fuzz_pool, src_dir, build_dir, seed_dir, targets):
- """Generates new corpus seeds.
+def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
+ """Generates new corpus.
- Run {targets} without input, and outputs the generated corpus seeds to
- {seed_dir}.
+ Run {targets} without input, and outputs the generated corpus to
+ {corpus_dir}.
"""
- logging.info("Generating corpus seeds to {}".format(seed_dir))
+ logging.info("Generating corpus to {}".format(corpus_dir))
def job(command, t):
logging.debug("Running '{}'\n".format(" ".join(command)))
@@ -205,12 +205,12 @@ def generate_corpus_seeds(*, fuzz_pool, src_dir, build_dir, seed_dir, targets):
futures = []
for target in targets:
- target_seed_dir = os.path.join(seed_dir, target)
- os.makedirs(target_seed_dir, exist_ok=True)
+ target_corpus_dir = os.path.join(corpus_dir, target)
+ os.makedirs(target_corpus_dir, exist_ok=True)
command = [
os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
"-runs=100000",
- target_seed_dir,
+ target_corpus_dir,
]
futures.append(fuzz_pool.submit(job, command, target))
@@ -219,7 +219,7 @@ def generate_corpus_seeds(*, fuzz_pool, src_dir, build_dir, seed_dir, targets):
def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir):
- logging.info("Merge the inputs from the passed dir into the seed_dir. Passed dir {}".format(merge_dir))
+ logging.info("Merge the inputs from the passed dir into the corpus_dir. Passed dir {}".format(merge_dir))
jobs = []
for t in test_list:
args = [