aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml2
-rw-r--r--build-aux/m4/bitcoin_qt.m415
-rw-r--r--build_msvc/bitcoin_config.h8
-rwxr-xr-xci/test/00_setup_env.sh2
-rw-r--r--ci/test/00_setup_env_i686_centos.sh2
-rw-r--r--ci/test/00_setup_env_mac.sh2
-rw-r--r--configure.ac5
-rwxr-xr-xcontrib/devtools/symbol-check.py10
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml1
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml1
-rw-r--r--contrib/guix/manifest.scm2
-rw-r--r--contrib/init/bitcoind.openrc7
-rw-r--r--depends/README.md2
-rw-r--r--depends/packages/libxcb.mk4
-rw-r--r--depends/packages/libxkbcommon.mk32
-rw-r--r--depends/packages/packages.mk4
-rw-r--r--depends/packages/qt.mk50
-rw-r--r--depends/packages/zlib.mk31
-rw-r--r--depends/patches/qt/drop_lrelease_dependency.patch2
-rw-r--r--depends/patches/qt/fix_android_jni_static.patch2
-rw-r--r--depends/patches/qt/fix_android_qmake_conf.patch24
-rw-r--r--depends/patches/qt/fix_configure_mac.patch50
-rw-r--r--depends/patches/qt/fix_lib_paths.patch193
-rw-r--r--depends/patches/qt/fix_mingw_cross_compile.patch25
-rw-r--r--depends/patches/qt/fix_no_printer.patch4
-rw-r--r--depends/patches/qt/fix_powerpc_libpng.patch23
-rw-r--r--depends/patches/qt/fix_qpainter_non_determinism.patch4
-rw-r--r--depends/patches/qt/fix_qt_pkgconfig.patch12
-rw-r--r--depends/patches/qt/fix_rcc_determinism.patch15
-rw-r--r--depends/patches/qt/fix_riscv64_arch.patch14
-rw-r--r--depends/patches/qt/freetype_back_compat.patch28
-rw-r--r--depends/patches/qt/no-xlib.patch17
-rw-r--r--depends/patches/qt/no_sdk_version_check.patch20
-rw-r--r--depends/patches/qt/xkb-default.patch26
-rw-r--r--doc/developer-notes.md5
-rw-r--r--doc/fuzzing.md19
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.test.include4
-rw-r--r--src/bench/coin_selection.cpp4
-rw-r--r--src/bitcoind.cpp123
-rw-r--r--src/chainparamsbase.cpp9
-rw-r--r--src/compat/glibc_compat.cpp7
-rw-r--r--src/compat/glibc_sanity.cpp45
-rw-r--r--src/compat/sanity.h1
-rw-r--r--src/httprpc.cpp2
-rw-r--r--src/index/blockfilterindex.cpp4
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/init.cpp15
-rw-r--r--src/init.h5
-rw-r--r--src/interfaces/handler.cpp5
-rw-r--r--src/miner.cpp12
-rw-r--r--src/miner.h4
-rw-r--r--src/net.cpp12
-rw-r--r--src/net_processing.cpp260
-rw-r--r--src/netbase.cpp245
-rw-r--r--src/netbase.h158
-rw-r--r--src/node/coin.cpp3
-rw-r--r--src/node/coinstats.cpp13
-rw-r--r--src/node/coinstats.h3
-rw-r--r--src/node/interfaces.cpp65
-rw-r--r--src/node/transaction.cpp7
-rw-r--r--src/qt/addressbookpage.cpp2
-rw-r--r--src/qt/bitcoin.cpp9
-rw-r--r--src/qt/guiutil.cpp20
-rw-r--r--src/qt/psbtoperationsdialog.cpp4
-rw-r--r--src/qt/qrimagewidget.cpp4
-rw-r--r--src/qt/receivecoinsdialog.cpp3
-rw-r--r--src/qt/sendcoinsdialog.cpp6
-rw-r--r--src/qt/transactionview.cpp4
-rw-r--r--src/qt/walletview.cpp2
-rw-r--r--src/rpc/blockchain.cpp155
-rw-r--r--src/rpc/mining.cpp170
-rw-r--r--src/rpc/request.h6
-rw-r--r--src/rpc/server.cpp33
-rw-r--r--src/rpc/server.h2
-rw-r--r--src/rpc/util.cpp19
-rw-r--r--src/rpc/util.h20
-rw-r--r--src/script/descriptor.cpp46
-rw-r--r--src/shutdown.cpp56
-rw-r--r--src/test/allocator_tests.cpp3
-rw-r--r--src/test/blockfilter_index_tests.cpp2
-rw-r--r--src/test/checkqueue_tests.cpp15
-rw-r--r--src/test/dbwrapper_tests.cpp5
-rw-r--r--src/test/denialofservice_tests.cpp13
-rw-r--r--src/test/fuzz/coins_view.cpp2
-rw-r--r--src/test/fuzz/descriptor_parse.cpp1
-rw-r--r--src/test/fuzz/eval_script.cpp1
-rw-r--r--src/test/fuzz/key.cpp1
-rw-r--r--src/test/fuzz/netbase_dns_lookup.cpp71
-rw-r--r--src/test/fuzz/parse_numbers.cpp3
-rw-r--r--src/test/fuzz/parse_univalue.cpp1
-rw-r--r--src/test/fuzz/process_message.cpp1
-rw-r--r--src/test/fuzz/process_messages.cpp1
-rw-r--r--src/test/fuzz/psbt.cpp1
-rw-r--r--src/test/fuzz/script.cpp1
-rw-r--r--src/test/fuzz/script_flags.cpp1
-rw-r--r--src/test/fuzz/signature_checker.cpp3
-rw-r--r--src/test/fuzz/util.h23
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp34
-rw-r--r--src/test/miner_tests.cpp38
-rw-r--r--src/test/net_tests.cpp11
-rw-r--r--src/test/rpc_tests.cpp1
-rw-r--r--src/test/sanity_tests.cpp1
-rw-r--r--src/test/util/logging.cpp1
-rw-r--r--src/test/util/mining.cpp2
-rw-r--r--src/test/util/setup_common.cpp11
-rw-r--r--src/test/util_tests.cpp61
-rw-r--r--src/test/validation_block_tests.cpp4
-rw-r--r--src/txdb.cpp5
-rw-r--r--src/txrequest.cpp3
-rw-r--r--src/util/memory.h20
-rw-r--r--src/util/system.cpp2
-rw-r--r--src/util/system.h1
-rw-r--r--src/util/tokenpipe.cpp108
-rw-r--r--src/util/tokenpipe.h127
-rw-r--r--src/validation.cpp18
-rw-r--r--src/validation.h9
-rw-r--r--src/wallet/bdb.cpp8
-rw-r--r--src/wallet/db.h3
-rw-r--r--src/wallet/init.cpp2
-rw-r--r--src/wallet/interfaces.cpp4
-rw-r--r--src/wallet/rpcdump.cpp4
-rw-r--r--src/wallet/rpcwallet.cpp2
-rw-r--r--src/wallet/salvage.cpp2
-rw-r--r--src/wallet/scriptpubkeyman.cpp18
-rw-r--r--src/wallet/sqlite.cpp5
-rw-r--r--src/wallet/test/coinselector_tests.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp8
-rw-r--r--src/wallet/walletdb.cpp6
-rw-r--r--src/zmq/zmqabstractnotifier.h3
-rwxr-xr-xtest/functional/feature_notifications.py54
-rwxr-xr-xtest/functional/wallet_groups.py16
133 files changed, 1749 insertions, 1232 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 7250d4ad94..097874b17a 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -10,7 +10,7 @@ environment:
QT_DOWNLOAD_URL: 'https://github.com/sipsorcery/qt_win_binary/releases/download/qt598x64_vs2019_v1681/qt598_x64_vs2019_1681.zip'
QT_DOWNLOAD_HASH: '00cf7327818c07d74e0b1a4464ffe987c2728b00d49d4bf333065892af0515c3'
QT_LOCAL_PATH: 'C:\Qt5.9.8_x64_static_vs2019'
- VCPKG_TAG: '2020.11-1'
+ VCPKG_TAG: '75522bb1f2e7d863078bcd06322348f053a9e33f'
install:
# Disable zmq test for now since python zmq library on Windows would cause Access violation sometimes.
# - cmd: pip install zmq
diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4
index 67ae03f3a9..1fd88db08f 100644
--- a/build-aux/m4/bitcoin_qt.m4
+++ b/build-aux/m4/bitcoin_qt.m4
@@ -123,7 +123,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
_BITCOIN_QT_CHECK_STATIC_LIBS
if test "x$qt_plugin_path" != x; then
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms"
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms -L$qt_plugin_path/styles"
if test -d "$qt_plugin_path/accessible"; then
QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
fi
@@ -138,13 +138,23 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists])
fi
if test "x$TARGET_OS" = xwindows; then
+ dnl Linking against wtsapi32 is required. See #17749 and
+ dnl https://bugreports.qt.io/browse/QTBUG-27097.
+ AX_CHECK_LINK_FLAG([-lwtsapi32], [QT_LIBS="$QT_LIBS -lwtsapi32"], [AC_MSG_ERROR([could not link against -lwtsapi32])])
_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
+ dnl workaround for https://bugreports.qt.io/browse/QTBUG-74874
+ AX_CHECK_LINK_FLAG([-lxcb-shm], [QT_LIBS="-lxcb-shm $QT_LIBS"], [AC_MSG_ERROR([could not link against -lxcb-shm])])
_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
+ AX_CHECK_LINK_FLAG([[-framework Carbon]],[QT_LIBS="$QT_LIBS -framework Carbon"],[AC_MSG_ERROR(could not link against Carbon framework)])
+ AX_CHECK_LINK_FLAG([[-framework IOSurface]],[QT_LIBS="$QT_LIBS -framework IOSurface"],[AC_MSG_ERROR(could not link against IOSurface framework)])
+ AX_CHECK_LINK_FLAG([[-framework Metal]],[QT_LIBS="$QT_LIBS -framework Metal"],[AC_MSG_ERROR(could not link against Metal framework)])
+ AX_CHECK_LINK_FLAG([[-framework QuartzCore]],[QT_LIBS="$QT_LIBS -framework QuartzCore"],[AC_MSG_ERROR(could not link against QuartzCore framework)])
_BITCOIN_QT_CHECK_STATIC_PLUGIN([QCocoaIntegrationPlugin], [-lqcocoa])
+ _BITCOIN_QT_CHECK_STATIC_PLUGIN([QMacStylePlugin], [-lqmacstyle])
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"
@@ -334,7 +344,8 @@ AC_DEFUN([_BITCOIN_QT_CHECK_STATIC_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"])
+ elif test "x$TARGET_OS" = xwindows; then
+ PKG_CHECK_MODULES([QTWINDOWSUIAUTOMATION], [Qt5WindowsUIAutomationSupport${qt_lib_suffix}], [QT_LIBS="-lQt5WindowsUIAutomationSupport${qt_lib_suffix} $QT_LIBS"])
fi
])
diff --git a/build_msvc/bitcoin_config.h b/build_msvc/bitcoin_config.h
index 40a30b9749..dd01cb29eb 100644
--- a/build_msvc/bitcoin_config.h
+++ b/build_msvc/bitcoin_config.h
@@ -92,9 +92,9 @@
don't. */
#define HAVE_DECL_BSWAP_64 0
-/* Define to 1 if you have the declaration of `daemon', and to 0 if you don't.
+/* Define to 1 if you have the declaration of `fork', and to 0 if you don't.
*/
-#define HAVE_DECL_DAEMON 0
+#define HAVE_DECL_FORK 0
/* Define to 1 if you have the declaration of `htobe16', and to 0 if you
don't. */
@@ -132,6 +132,10 @@
don't. */
#define HAVE_DECL_LE64TOH 0
+/* Define to 1 if you have the declaration of `setsid', and to 0 if you don't.
+ */
+#define HAVE_DECL_SETSID 0
+
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
don't. */
#define HAVE_DECL_STRERROR_R 0
diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh
index 72e29141a6..87cf8538f6 100755
--- a/ci/test/00_setup_env.sh
+++ b/ci/test/00_setup_env.sh
@@ -65,7 +65,7 @@ export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out/$HOST}
export BASE_BUILD_DIR=${BASE_BUILD_DIR:-$BASE_SCRATCH_DIR/build}
export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/releases/$HOST}
export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}
-export DOCKER_PACKAGES=${DOCKER_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps}
+export DOCKER_PACKAGES=${DOCKER_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps bison}
export GOAL=${GOAL:-install}
export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_SCRATCH_DIR}/qa-assets}
export PATH=${BASE_ROOT_DIR}/ci/retry:$PATH
diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh
index 1ec44a7a1a..07e7c2dc27 100644
--- a/ci/test/00_setup_env_i686_centos.sh
+++ b/ci/test/00_setup_env_i686_centos.sh
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_centos_8
export DOCKER_NAME_TAG=centos:8
-export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-zmq which patch lbzip2 dash rsync coreutils"
+export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-zmq which patch lbzip2 dash rsync coreutils bison"
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --with-boost-process"
export CONFIG_SHELL="/bin/dash"
diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh
index 645dcffd02..6ce3812447 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 librsvg2-bin libz-dev libtiff-tools libtinfo5 python3-dev python3-setuptools xorriso"
+export PACKAGES="cmake imagemagick librsvg2-bin libz-dev libtiff-tools libtinfo5 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 391a75eeed..0b176e6039 100644
--- a/configure.ac
+++ b/configure.ac
@@ -922,8 +922,9 @@ AC_CHECK_DECLS([getifaddrs, freeifaddrs],,,
)
AC_CHECK_DECLS([strnlen])
-dnl Check for daemon(3), unrelated to --with-daemon (although used by it)
-AC_CHECK_DECLS([daemon])
+dnl These are used for daemonization in bitcoind
+AC_CHECK_DECLS([fork])
+AC_CHECK_DECLS([setsid])
AC_CHECK_DECLS([pipe2])
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index b30ed62521..436f179d61 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -73,6 +73,8 @@ ELF_ALLOWED_LIBRARIES = {
'ld-linux-riscv64-lp64d.so.1', # 64-bit RISC-V dynamic linker
# bitcoin-qt only
'libxcb.so.1', # part of X11
+'libxkbcommon.so.0', # keyboard keymapping
+'libxkbcommon-x11.so.0', # keyboard keymapping
'libfontconfig.so.1', # font support
'libfreetype.so.6', # font parsing
'libdl.so.2' # programming interface to dynamic linker
@@ -98,10 +100,15 @@ MACHO_ALLOWED_LIBRARIES = {
'CoreGraphics', # 2D rendering
'CoreServices', # operating system services
'CoreText', # interface for laying out text and handling fonts.
+'CoreVideo', # video processing
'Foundation', # base layer functionality for apps/frameworks
'ImageIO', # read and write image file formats.
'IOKit', # user-space access to hardware devices and drivers.
+'IOSurface', # cross process image/drawing buffers
'libobjc.A.dylib', # Objective-C runtime library
+'Metal', # 3D graphics
+'Security', # access control and authentication
+'QuartzCore', # animation
}
PE_ALLOWED_LIBRARIES = {
@@ -116,12 +123,15 @@ PE_ALLOWED_LIBRARIES = {
'dwmapi.dll', # desktop window manager
'GDI32.dll', # graphics device interface
'IMM32.dll', # input method editor
+'NETAPI32.dll',
'ole32.dll', # component object model
'OLEAUT32.dll', # OLE Automation API
'SHLWAPI.dll', # light weight shell API
+'USERENV.dll',
'UxTheme.dll',
'VERSION.dll', # version checking
'WINMM.dll', # WinMM audio API
+'WTSAPI32.dll',
}
class CPPFilt(object):
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index b06fc782a3..52e2a0514a 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -11,6 +11,7 @@ packages:
- "autoconf"
- "automake"
- "binutils"
+- "bison"
- "bsdmainutils"
- "ca-certificates"
- "curl"
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 98c3888b45..c37ad5b842 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -23,7 +23,6 @@ packages:
- "imagemagick"
- "libz-dev"
- "python3"
-- "python3-dev"
- "python3-setuptools"
- "fonts-tuffy"
- "xorriso"
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index bd9f895dce..4228532cb1 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -3,6 +3,7 @@
(gnu packages autotools)
(gnu packages base)
(gnu packages bash)
+ (gnu packages bison)
(gnu packages cdrom)
(gnu packages check)
(gnu packages cmake)
@@ -219,6 +220,7 @@ chain for " target " development."))
autoconf
automake
pkg-config
+ bison
;; Scripting
perl
python-3
diff --git a/contrib/init/bitcoind.openrc b/contrib/init/bitcoind.openrc
index 86222295db..013a1a6070 100644
--- a/contrib/init/bitcoind.openrc
+++ b/contrib/init/bitcoind.openrc
@@ -60,16 +60,17 @@ start_pre() {
"${BITCOIND_PIDDIR}"
checkpath -f \
- -o ${BITCOIND_USER}:${BITCOIND_GROUP} \
+ -o "${BITCOIND_USER}:${BITCOIND_GROUP}" \
-m 0660 \
- ${BITCOIND_CONFIGFILE}
+ "${BITCOIND_CONFIGFILE}"
checkconfig || return 1
}
checkconfig()
{
- if ! grep -qs '^rpcpassword=' "${BITCOIND_CONFIGFILE}" ; then
+ if grep -qs '^rpcuser=' "${BITCOIND_CONFIGFILE}" && \
+ ! grep -qs '^rpcpassword=' "${BITCOIND_CONFIGFILE}" ; then
eerror ""
eerror "ERROR: You must set a secure rpcpassword to run bitcoind."
eerror "The setting must appear in ${BITCOIND_CONFIGFILE}"
diff --git a/depends/README.md b/depends/README.md
index e72c666474..a1d4a99084 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -54,7 +54,7 @@ The paths are automatically configured and no other options are needed unless ta
Common linux dependencies:
- sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 patch
+ sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 patch bison
For linux ARM cross compilation:
diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk
index 14abde9b0a..710f43959c 100644
--- a/depends/packages/libxcb.mk
+++ b/depends/packages/libxcb.mk
@@ -15,9 +15,9 @@ $(package)_config_opts += --disable-composite --disable-damage --disable-dpms
$(package)_config_opts += --disable-dri2 --disable-dri3 --disable-glx
$(package)_config_opts += --disable-present --disable-randr --disable-record
$(package)_config_opts += --disable-render --disable-resource --disable-screensaver
-$(package)_config_opts += --disable-shape --disable-shm --disable-sync
+$(package)_config_opts += --disable-shape --disable-sync
$(package)_config_opts += --disable-xevie --disable-xfixes --disable-xfree86-dri
-$(package)_config_opts += --disable-xinerama --disable-xinput --disable-xkb
+$(package)_config_opts += --disable-xinerama --disable-xinput
$(package)_config_opts += --disable-xprint --disable-selinux --disable-xtest
$(package)_config_opts += --disable-xv --disable-xvmc
endef
diff --git a/depends/packages/libxkbcommon.mk b/depends/packages/libxkbcommon.mk
new file mode 100644
index 0000000000..cdd5af194b
--- /dev/null
+++ b/depends/packages/libxkbcommon.mk
@@ -0,0 +1,32 @@
+package=libxkbcommon
+$(package)_version=0.8.4
+$(package)_download_path=https://xkbcommon.org/download/
+$(package)_file_name=$(package)-$($(package)_version).tar.xz
+$(package)_sha256_hash=60ddcff932b7fd352752d51a5c4f04f3d0403230a584df9a2e0d5ed87c486c8b
+$(package)_dependencies=libxcb
+
+define $(package)_set_vars
+$(package)_config_opts = --enable-option-checking --disable-dependency-tracking
+$(package)_config_opts += --disable-static --disable-docs
+endef
+
+define $(package)_preprocess_cmds
+ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux
+endef
+
+define $(package)_config_cmds
+ $($(package)_autoconf)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
+
+define $(package)_postprocess_cmds
+ rm -rf share/man share/doc lib/*.la
+endef
+
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 0f35ca0d2d..810068b686 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -1,10 +1,8 @@
packages:=boost libevent
-qt_packages = zlib
-
qrencode_packages = qrencode
-qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig
+qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon
qt_android_packages=qt
qt_darwin_packages=qt
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index 7d122ea5f9..0ac6f496c4 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -1,23 +1,21 @@
PACKAGE=qt
-$(package)_version=5.9.8
-$(package)_download_path=https://download.qt.io/official_releases/qt/5.9/$($(package)_version)/submodules
-$(package)_suffix=opensource-src-$($(package)_version).tar.xz
+$(package)_version=5.12.10
+$(package)_download_path=https://download.qt.io/official_releases/qt/5.12/$($(package)_version)/submodules
+$(package)_suffix=everywhere-src-$($(package)_version).tar.xz
$(package)_file_name=qtbase-$($(package)_suffix)
-$(package)_sha256_hash=9b9dec1f67df1f94bce2955c5604de992d529dde72050239154c56352da0907d
-$(package)_dependencies=zlib
-$(package)_linux_dependencies=freetype fontconfig libxcb
+$(package)_sha256_hash=8088f174e6d28e779516c083b6087b6a9e3c8322b4bc161fd1b54195e3c86940
+$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon
$(package)_qt_libs=corelib network widgets gui plugins testlib
-$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch
-$(package)_patches+= fix_rcc_determinism.patch fix_riscv64_arch.patch xkb-default.patch no-xlib.patch
+$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_no_printer.patch no-xlib.patch
$(package)_patches+= fix_android_qmake_conf.patch fix_android_jni_static.patch dont_hardcode_pwd.patch
-$(package)_patches+= freetype_back_compat.patch drop_lrelease_dependency.patch fix_powerpc_libpng.patch
-$(package)_patches+= fix_mingw_cross_compile.patch fix_qpainter_non_determinism.patch
+$(package)_patches+= drop_lrelease_dependency.patch no_sdk_version_check.patch
+$(package)_patches+= fix_qpainter_non_determinism.patch fix_lib_paths.patch
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
-$(package)_qttranslations_sha256_hash=fb5a47799754af73d3bf501fe513342cfe2fc37f64e80df5533f6110e804220c
+$(package)_qttranslations_sha256_hash=e1de58ed108b7e0a138815ea60fd46a2c4e1fc31396a707e5630e92de79c53de
$(package)_qttools_file_name=qttools-$($(package)_suffix)
-$(package)_qttools_sha256_hash=a97556eb7b2f30252cdd8a598c396cfce2b2f79d2bae883af6d3b26a2cdcc63c
+$(package)_qttools_sha256_hash=b0cfa6e7aac41b7c61fc59acc04843d7a98f9e1840370611751bcfc1834a636c
$(package)_extra_sources = $($(package)_qttranslations_file_name)
$(package)_extra_sources += $($(package)_qttools_file_name)
@@ -26,6 +24,7 @@ define $(package)_set_vars
$(package)_config_opts_release = -release
$(package)_config_opts_release += -silent
$(package)_config_opts_debug = -debug
+$(package)_config_opts_debug += -optimized-tools
$(package)_config_opts += -bindir $(build_prefix)/bin
$(package)_config_opts += -c++std c++1z
$(package)_config_opts += -confirm-license
@@ -49,7 +48,6 @@ $(package)_config_opts += -no-mtdev
$(package)_config_opts += -no-openssl
$(package)_config_opts += -no-openvg
$(package)_config_opts += -no-reduce-relocations
-$(package)_config_opts += -no-qml-debug
$(package)_config_opts += -no-sctp
$(package)_config_opts += -no-securetransport
$(package)_config_opts += -no-sql-db2
@@ -63,17 +61,15 @@ $(package)_config_opts += -no-sql-sqlite
$(package)_config_opts += -no-sql-sqlite2
$(package)_config_opts += -no-system-proxies
$(package)_config_opts += -no-use-gold-linker
-$(package)_config_opts += -no-xinput2
$(package)_config_opts += -nomake examples
$(package)_config_opts += -nomake tests
$(package)_config_opts += -opensource
-$(package)_config_opts += -optimized-tools
$(package)_config_opts += -pkg-config
$(package)_config_opts += -prefix $(host_prefix)
$(package)_config_opts += -qt-libpng
$(package)_config_opts += -qt-pcre
$(package)_config_opts += -qt-harfbuzz
-$(package)_config_opts += -system-zlib
+$(package)_config_opts += -qt-zlib
$(package)_config_opts += -static
$(package)_config_opts += -v
$(package)_config_opts += -no-feature-bearermanagement
@@ -94,10 +90,10 @@ $(package)_config_opts += -no-feature-printdialog
$(package)_config_opts += -no-feature-printer
$(package)_config_opts += -no-feature-printpreviewdialog
$(package)_config_opts += -no-feature-printpreviewwidget
-$(package)_config_opts += -no-feature-regularexpression
$(package)_config_opts += -no-feature-sessionmanager
$(package)_config_opts += -no-feature-socks5
$(package)_config_opts += -no-feature-sql
+$(package)_config_opts += -no-feature-sqlmodel
$(package)_config_opts += -no-feature-statemachine
$(package)_config_opts += -no-feature-syntaxhighlighter
$(package)_config_opts += -no-feature-textbrowser
@@ -115,6 +111,7 @@ $(package)_config_opts += -no-feature-xml
$(package)_config_opts_darwin = -no-dbus
$(package)_config_opts_darwin += -no-opengl
$(package)_config_opts_darwin += -pch
+$(package)_config_opts_darwin += -device-option QMAKE_MACOSX_DEPLOYMENT_TARGET=$(OSX_MIN_VERSION)
ifneq ($(build_os),darwin)
$(package)_config_opts_darwin += -xplatform macx-clang-linux
@@ -129,13 +126,13 @@ 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 = -qt-xcb
$(package)_config_opts_linux += -no-xcb-xlib
$(package)_config_opts_linux += -no-feature-xlib
$(package)_config_opts_linux += -system-freetype
$(package)_config_opts_linux += -fontconfig
$(package)_config_opts_linux += -no-opengl
+$(package)_config_opts_linux += -no-feature-vulkan
$(package)_config_opts_linux += -dbus-runtime
$(package)_config_opts_arm_linux += -platform linux-g++ -xplatform bitcoin-linux-g++
$(package)_config_opts_i686_linux = -xplatform linux-g++-32
@@ -220,21 +217,16 @@ endef
# 8. Adjust a regex in toolchain.prf, to accommodate Guix's usage of
# CROSS_LIBRARY_PATH. See #15277.
define $(package)_preprocess_cmds
- patch -p1 -i $($(package)_patch_dir)/freetype_back_compat.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_powerpc_libpng.patch && \
patch -p1 -i $($(package)_patch_dir)/drop_lrelease_dependency.patch && \
patch -p1 -i $($(package)_patch_dir)/dont_hardcode_pwd.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_configure_mac.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_rcc_determinism.patch && \
- patch -p1 -i $($(package)_patch_dir)/xkb-default.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_android_qmake_conf.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_riscv64_arch.patch && \
patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \
- patch -p1 -i $($(package)_patch_dir)/fix_mingw_cross_compile.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_qpainter_non_determinism.patch &&\
+ patch -p1 -i $($(package)_patch_dir)/no_sdk_version_check.patch && \
+ patch -p1 -i $($(package)_patch_dir)/fix_lib_paths.patch && \
sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \
mkdir -p qtbase/mkspecs/macx-clang-linux &&\
cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\
@@ -247,8 +239,8 @@ define $(package)_preprocess_cmds
sed -i.old "s|QMAKE_CFLAGS += |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \
sed -i.old "s|QMAKE_CXXFLAGS += |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \
sed -i.old "0,/^QMAKE_LFLAGS_/s|^QMAKE_LFLAGS_|!host_build: QMAKE_LFLAGS = $($(package)_ldflags)\n&|" qtbase/mkspecs/win32-g++/qmake.conf && \
- sed -i.old "s|QMAKE_CC = clang|QMAKE_CC = $($(package)_cc)|" qtbase/mkspecs/common/clang.conf && \
- sed -i.old "s|QMAKE_CXX = clang++|QMAKE_CXX = $($(package)_cxx)|" qtbase/mkspecs/common/clang.conf && \
+ sed -i.old "s|QMAKE_CC = \$$$$\$$$${CROSS_COMPILE}clang|QMAKE_CC = $($(package)_cc)|" qtbase/mkspecs/common/clang.conf && \
+ sed -i.old "s|QMAKE_CXX = \$$$$\$$$${CROSS_COMPILE}clang++|QMAKE_CXX = $($(package)_cxx)|" qtbase/mkspecs/common/clang.conf && \
sed -i.old "s/LIBRARY_PATH/(CROSS_)?\0/g" qtbase/mkspecs/features/toolchain.prf
endef
@@ -258,8 +250,6 @@ define $(package)_config_cmds
export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
cd qtbase && \
./configure $($(package)_config_opts) && \
- echo "host_build: QT_CONFIG ~= s/system-zlib/zlib" >> mkspecs/qconfig.pri && \
- echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \
cd .. && \
$(MAKE) -C qtbase sub-src-clean && \
qtbase/bin/qmake -o qttranslations/Makefile qttranslations/qttranslations.pro && \
diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk
deleted file mode 100644
index acb02020a8..0000000000
--- a/depends/packages/zlib.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-package=zlib
-$(package)_version=1.2.11
-$(package)_download_path=https://www.zlib.net
-$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
-
-define $(package)_set_vars
-$(package)_config_opts= CC="$($(package)_cc)"
-$(package)_config_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC"
-$(package)_config_opts+=RANLIB="$($(package)_ranlib)"
-$(package)_config_opts+=AR="$($(package)_ar)"
-$(package)_config_opts_darwin+=AR="$($(package)_libtool)"
-$(package)_config_opts_darwin+=ARFLAGS="-o"
-$(package)_config_opts_android+=CHOST=$(host)
-endef
-
-# zlib has its own custom configure script that takes in options like CC,
-# CFLAGS, RANLIB, AR, and ARFLAGS from the environment rather than from
-# command-line arguments.
-define $(package)_config_cmds
- env $($(package)_config_opts) ./configure --static --prefix=$(host_prefix)
-endef
-
-define $(package)_build_cmds
- $(MAKE) libz.a
-endef
-
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install
-endef
-
diff --git a/depends/patches/qt/drop_lrelease_dependency.patch b/depends/patches/qt/drop_lrelease_dependency.patch
index f6b2c9fc80..9b918af77c 100644
--- a/depends/patches/qt/drop_lrelease_dependency.patch
+++ b/depends/patches/qt/drop_lrelease_dependency.patch
@@ -14,7 +14,7 @@ diff --git a/qttranslations/translations/translations.pro b/qttranslations/trans
index 694544c..eff339d 100644
--- a/qttranslations/translations/translations.pro
+++ b/qttranslations/translations/translations.pro
-@@ -109,3 +109,2 @@ updateqm.commands = $$LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT}
+@@ -107,3 +107,2 @@ updateqm.commands = $$LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT}
silent:updateqm.commands = @echo lrelease ${QMAKE_FILE_IN} && $$updateqm.commands
-updateqm.depends = $$LRELEASE_EXE
updateqm.name = LRELEASE ${QMAKE_FILE_IN}
diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch
index 2f6ff00f40..f891da6ddf 100644
--- a/depends/patches/qt/fix_android_jni_static.patch
+++ b/depends/patches/qt/fix_android_jni_static.patch
@@ -1,6 +1,6 @@
--- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp
+++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp
-@@ -890,6 +890,14 @@
+@@ -897,6 +897,14 @@
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
diff --git a/depends/patches/qt/fix_android_qmake_conf.patch b/depends/patches/qt/fix_android_qmake_conf.patch
index 13bfff9776..3a8753fd1d 100644
--- a/depends/patches/qt/fix_android_qmake_conf.patch
+++ b/depends/patches/qt/fix_android_qmake_conf.patch
@@ -1,20 +1,10 @@
--- old/qtbase/mkspecs/android-clang/qmake.conf
+++ new/qtbase/mkspecs/android-clang/qmake.conf
-@@ -30,7 +30,7 @@
- QMAKE_CFLAGS += -target mips64el-none-linux-android
+@@ -47,7 +47,7 @@ ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so
+ ANDROID_USE_LLVM = true
- QMAKE_CFLAGS += -gcc-toolchain $$NDK_TOOLCHAIN_PATH
--QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a
-+QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a -nostdlib++
- QMAKE_CFLAGS += -DANDROID_HAS_WSTRING --sysroot=$$NDK_ROOT/sysroot \
- -isystem $$NDK_ROOT/sysroot/usr/include/$$NDK_TOOLS_PREFIX \
- -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++/include \
-@@ -40,7 +40,7 @@
- ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH
-
- ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so
--ANDROID_CXX_STL_LIBS = -lc++
-+ANDROID_CXX_STL_LIBS = -lc++_shared
-
- QMAKE_ARM_CFLAGS_RELEASE = -Oz
- QMAKE_ARM_CFLAGS_RELEASE_WITH_DEBUGINFO = -g -Oz
+ exists($$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so): \
+- ANDROID_CXX_STL_LIBS = -lc++
++ ANDROID_CXX_STL_LIBS = -lc++_shared
+ else: \
+ ANDROID_CXX_STL_LIBS = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so.$$replace(ANDROID_PLATFORM, "android-", "")
diff --git a/depends/patches/qt/fix_configure_mac.patch b/depends/patches/qt/fix_configure_mac.patch
deleted file mode 100644
index 0d7dd647de..0000000000
--- a/depends/patches/qt/fix_configure_mac.patch
+++ /dev/null
@@ -1,50 +0,0 @@
---- old/qtbase/mkspecs/features/mac/sdk.prf 2018-02-08 10:24:48.000000000 -0800
-+++ new/qtbase/mkspecs/features/mac/sdk.prf 2018-03-23 10:38:56.000000000 -0700
-@@ -8,21 +8,21 @@
- defineReplace(xcodeSDKInfo) {
- info = $$1
- equals(info, "Path"): \
-- info = --show-sdk-path
-+ infoarg = --show-sdk-path
- equals(info, "PlatformPath"): \
-- info = --show-sdk-platform-path
-+ infoarg = --show-sdk-platform-path
- equals(info, "SDKVersion"): \
-- info = --show-sdk-version
-+ infoarg = --show-sdk-version
- sdk = $$2
- isEmpty(sdk): \
- sdk = $$QMAKE_MAC_SDK
-
- isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}) {
-- QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$info 2>/dev/null")
-+ QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$infoarg 2>/dev/null")
- # --show-sdk-platform-path won't work for Command Line Tools; this is fine
- # only used by the XCTest backend to testlib
-- isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(info, "--show-sdk-platform-path")): \
-- error("Could not resolve SDK $$info for \'$$sdk\'")
-+ isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(infoarg, "--show-sdk-platform-path")): \
-+ error("Could not resolve SDK $$info for \'$$sdk\' using $$infoarg")
- cache(QMAKE_MAC_SDK.$${sdk}.$${info}, set stash, QMAKE_MAC_SDK.$${sdk}.$${info})
- }
-
---- old/qtbase/configure 2018-02-08 10:24:48.000000000 -0800
-+++ new/qtbase/configure 2018-03-23 05:42:29.000000000 -0700
-@@ -232,8 +232,13 @@
-
- sdk=$(getSingleQMakeVariable "QMAKE_MAC_SDK" "$1")
- if [ -z "$sdk" ]; then echo "QMAKE_MAC_SDK must be set when building on Mac" >&2; exit 1; fi
-- sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null)
-- if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi
-+ sysroot=$(getSingleQMakeVariable "QMAKE_MAC_SDK_PATH" "$1")
-+
-+ echo "sysroot pre-configured as $sysroot";
-+ if [ -z "$sysroot" ]; then
-+ sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null)
-+ if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi
-+ fi
-
- case "$sdk" in
- macosx*)
-
-
diff --git a/depends/patches/qt/fix_lib_paths.patch b/depends/patches/qt/fix_lib_paths.patch
new file mode 100644
index 0000000000..d1a15373f4
--- /dev/null
+++ b/depends/patches/qt/fix_lib_paths.patch
@@ -0,0 +1,193 @@
+--- old/qtbase/mkspecs/common/mac.conf
++++ new/qtbase/mkspecs/common/mac.conf
+@@ -14,7 +14,6 @@
+
+ QMAKE_RESOURCE = /Developer/Tools/Rez
+ QMAKE_EXTENSION_SHLIB = dylib
+-QMAKE_EXTENSIONS_AUX_SHLIB = tbd
+ QMAKE_LIBDIR =
+
+ # sdk.prf will prefix the proper SDK sysroot
+
+--- old/qtbase/mkspecs/features/qmake_use.prf
++++ new/qtbase/mkspecs/features/qmake_use.prf
+@@ -22,6 +22,8 @@
+ !defined(QMAKE_LIBS_$$nu, var): \
+ error("Library '$$lower($$replace(nu, _, -))' is not defined.")
+
++ QMAKE_LIBDIR += $$eval(QMAKE_LIBDIR_$$nu)
++
+ debug: \
+ LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu)
+ else: \
+
+--- old/qtbase/mkspecs/features/qt_configure.prf
++++ new/qtbase/mkspecs/features/qt_configure.prf
+@@ -526,98 +526,23 @@
+ return($$sysrootified)
+ }
+
+-# libs-var, libs, in-paths, out-paths-var
++# libs-var, libs, in-paths
+ defineTest(qtConfResolveLibs) {
+- ret = true
+- paths = $$3
+- out =
+- copy = false
+- for (l, 2) {
+- $$copy {
+- copy = false
+- out += $$l
+- } else: equals(l, "-s") {
+- # em++ flag to link libraries from emscripten-ports; passed on literally.
+- copy = true
+- out += $$l
+- } else: contains(l, "^-L.*") {
+- lp = $$replace(l, "^-L", )
+- gcc: lp = $$qtGccSysrootifiedPath($$lp)
+- !exists($$lp/.) {
+- qtLog("Library path $$val_escape(lp) is invalid.")
+- ret = false
+- } else {
+- paths += $$lp
+- }
+- } else: contains(l, "^-l.*") {
+- lib = $$replace(l, "^-l", )
+- lcan =
+- integrity:contains(lib, "^.*\\.a") {
+- # INTEGRITY compiler searches for exact filename
+- # if -l argument has .a suffix
+- lcan += $${lib}
+- } else: contains(lib, "^:.*") {
+- # Use exact filename when -l:filename syntax is used.
+- lib ~= s/^://
+- lcan += $${lib}
+- } else: unix {
+- # Under UNIX, we look for actual shared libraries, in addition
+- # to static ones.
+- shexts = $$QMAKE_EXTENSION_SHLIB $$QMAKE_EXTENSIONS_AUX_SHLIB
+- for (ext, shexts) {
+- lcan += $${QMAKE_PREFIX_SHLIB}$${lib}.$${ext}
+- }
+- lcan += \
+- $${QMAKE_PREFIX_STATICLIB}$${lib}.$${QMAKE_EXTENSION_STATICLIB}
+- } else {
+- # Under Windows, we look only for static libraries, as even for DLLs
+- # one actually links against a static import library.
+- mingw {
+- lcan += \
+- # MinGW supports UNIX-style library naming in addition to
+- # the MSVC style.
+- lib$${lib}.dll.a lib$${lib}.a \
+- # Fun fact: prefix-less libraries are also supported.
+- $${lib}.dll.a $${lib}.a
+- }
+- lcan += $${lib}.lib
+- }
+- l = $$qtConfFindInPathList($$lcan, $$paths $$EXTRA_LIBDIR $$QMAKE_DEFAULT_LIBDIRS)
+- isEmpty(l) {
+- qtLog("None of [$$val_escape(lcan)] found in [$$val_escape(paths)] and global paths.")
+- ret = false
+- } else {
+- out += $$l
+- }
+- } else {
+- out += $$l
+- }
+- }
+- $$1 = $$out
++ for (path, 3): \
++ pre_lflags += -L$$path
++ $$1 = $$pre_lflags $$2
+ export($$1)
+- !isEmpty(4) {
+- $$4 = $$paths
+- export($$4)
+- }
+- return($$ret)
+-}
+-
+-# source-var
+-defineTest(qtConfResolveAllLibs) {
+- ret = true
+- !qtConfResolveLibs($${1}.libs, $$eval($${1}.libs), , $${1}.libdirs): \
+- ret = false
+- for (b, $${1}.builds._KEYS_): \
+- !qtConfResolveLibs($${1}.builds.$${b}, $$eval($${1}.builds.$${b}), $$eval($${1}.libdirs), ): \
+- ret = false
+- return($$ret)
++ return(true)
+ }
+
+ # libs-var, in-paths, libs
+ defineTest(qtConfResolvePathLibs) {
+ ret = true
+- gcc: 2 = $$qtGccSysrootifiedPaths($$2)
+- for (libdir, 2) {
++ gcc: \
++ local_paths = $$qtGccSysrootifiedPaths($$2)
++ else: \
++ local_paths = $$2
++ for (libdir, local_paths) {
+ !exists($$libdir/.) {
+ qtLog("Library path $$val_escape(libdir) is invalid.")
+ ret = false
+@@ -667,8 +592,11 @@
+ # includes-var, in-paths, test-object-var
+ defineTest(qtConfResolvePathIncs) {
+ ret = true
+- gcc: 2 = $$qtGccSysrootifiedPaths($$2)
+- for (incdir, 2) {
++ gcc: \
++ local_paths = $$qtGccSysrootifiedPaths($$2)
++ else: \
++ local_paths = $$2
++ for (incdir, local_paths) {
+ !exists($$incdir/.) {
+ qtLog("Include path $$val_escape(incdir) is invalid.")
+ ret = false
+@@ -727,6 +655,7 @@
+ vars += $$eval(config.commandline.rev_assignments.$${iv})
+ defined(config.input.$${iv}, var) {
+ eval($${1}.builds.$${b} = $$eval(config.input.$${iv}))
++ export($${1}.builds.$${b})
+ $${1}.builds._KEYS_ *= $${b}
+ any = true
+ } else {
+@@ -741,11 +670,14 @@
+ export($${1}.builds._KEYS_)
+ # we also reset the generic libs, to avoid surprises.
+ $${1}.libs =
++ export($${1}.libs)
+ }
+
+ # direct libs. overwrites inline libs.
+- defined(config.input.$${input}.libs, var): \
++ defined(config.input.$${input}.libs, var) {
+ eval($${1}.libs = $$eval(config.input.$${input}.libs))
++ export($${1}.libs)
++ }
+
+ includes = $$eval(config.input.$${input}.incdir)
+
+@@ -754,6 +686,7 @@
+ !isEmpty(prefix) {
+ includes += $$prefix/include
+ $${1}.libs = -L$$prefix/lib $$eval($${1}.libs)
++ export($${1}.libs)
+ }
+
+ libdir = $$eval(config.input.$${input}.libdir)
+@@ -762,11 +695,9 @@
+ for (ld, libdir): \
+ libs += -L$$ld
+ $${1}.libs = $$libs $$eval($${1}.libs)
++ export($${1}.libs)
+ }
+
+- !qtConfResolveAllLibs($$1): \
+- return(false)
+-
+ !qtConfResolvePathIncs($${1}.includedir, $$includes, $$2): \
+ return(false)
+
diff --git a/depends/patches/qt/fix_mingw_cross_compile.patch b/depends/patches/qt/fix_mingw_cross_compile.patch
deleted file mode 100644
index 67f76f1d85..0000000000
--- a/depends/patches/qt/fix_mingw_cross_compile.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-commit 5a992a549adfe5a587bbcd6cd2b2cee47d236e27
-Author: fanquake <fanquake@gmail.com>
-Date: Fri Sep 4 08:13:44 2020 +0800
-
- Work around broken mingw cross-compilation
-
- See upstream issues:
- https://bugreports.qt.io/browse/QTBUG-63637
- https://bugreports.qt.io/browse/QTBUG-63659
- https://codereview.qt-project.org/q/8bebded9
-
- We should be able to drop this once we are building qt 5.10.1 or later.
-
- Added in #12971.
-
-diff --git a/qtbase/mkspecs/win32-g++/qmake.conf b/qtbase/mkspecs/win32-g++/qmake.conf
-index e071a0d1..ad229b10 100644
---- a/qtbase/mkspecs/win32-g++/qmake.conf
-+++ b/qtbase/mkspecs/win32-g++/qmake.conf
-@@ -87,3 +87,5 @@ QMAKE_NM = $${CROSS_COMPILE}nm -P
- include(../common/angle.conf)
-
- load(qt_config)
-+QMAKE_LINK_OBJECT_MAX = 10
-+QMAKE_LINK_OBJECT_SCRIPT = object_script
diff --git a/depends/patches/qt/fix_no_printer.patch b/depends/patches/qt/fix_no_printer.patch
index f868ca2577..1372356138 100644
--- a/depends/patches/qt/fix_no_printer.patch
+++ b/depends/patches/qt/fix_no_printer.patch
@@ -10,10 +10,10 @@
--- x/qtbase/src/plugins/plugins.pro
+++ y/qtbase/src/plugins/plugins.pro
-@@ -8,6 +8,3 @@ qtHaveModule(gui) {
- qtConfig(imageformatplugin): SUBDIRS *= imageformats
+@@ -9,6 +9,3 @@ qtHaveModule(gui) {
!android:qtConfig(library): SUBDIRS *= generic
}
+ qtHaveModule(widgets): SUBDIRS += styles
-
-!winrt:qtHaveModule(printsupport): \
- SUBDIRS += printsupport
diff --git a/depends/patches/qt/fix_powerpc_libpng.patch b/depends/patches/qt/fix_powerpc_libpng.patch
deleted file mode 100644
index d37b6c7776..0000000000
--- a/depends/patches/qt/fix_powerpc_libpng.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-commit 6f9feb773a43c5abfa3455da2e324180e789285b
-Author: fanquake <fanquake@gmail.com>
-Date: Tue Sep 15 21:44:31 2020 +0800
-
- Fix PowerPC build of libpng
-
- See https://bugreports.qt.io/browse/QTBUG-66388.
-
- Can be dropped when we are building qt 5.12.0 or later.
-
-diff --git a/qtbase/src/3rdparty/libpng/libpng.pro b/qtbase/src/3rdparty/libpng/libpng.pro
-index 577b61d8..a2f56669 100644
---- a/qtbase/src/3rdparty/libpng/libpng.pro
-+++ b/qtbase/src/3rdparty/libpng/libpng.pro
-@@ -10,7 +10,7 @@ MODULE_INCLUDEPATH = $$PWD
-
- load(qt_helper_lib)
-
--DEFINES += PNG_ARM_NEON_OPT=0
-+DEFINES += PNG_ARM_NEON_OPT=0 PNG_POWERPC_VSX_OPT=0
- SOURCES += \
- png.c \
- pngerror.c \
diff --git a/depends/patches/qt/fix_qpainter_non_determinism.patch b/depends/patches/qt/fix_qpainter_non_determinism.patch
index 3cfcc22f03..44c45187c5 100644
--- a/depends/patches/qt/fix_qpainter_non_determinism.patch
+++ b/depends/patches/qt/fix_qpainter_non_determinism.patch
@@ -22,7 +22,7 @@ diff --git a/qtbase/src/gui/painting/qpaintengine_raster.cpp b/qtbase/src/gui/pa
index 92ab6e8375..f018009e0b 100644
--- a/qtbase/src/gui/painting/qpaintengine_raster.cpp
+++ b/qtbase/src/gui/painting/qpaintengine_raster.cpp
-@@ -3971,22 +3971,23 @@ static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
+@@ -4128,22 +4128,23 @@ static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
const QSpan *clipEnd = clip->m_spans + clip->count;
while (available && spans < end ) {
@@ -51,7 +51,7 @@ index 92ab6e8375..f018009e0b 100644
int sx1 = spans->x;
int sx2 = sx1 + spans->len;
-@@ -4005,7 +4006,7 @@ static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
+@@ -4162,7 +4163,7 @@ static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
if (len) {
out->x = qMax(sx1, cx1);
out->len = qMin(sx2, cx2) - out->x;
diff --git a/depends/patches/qt/fix_qt_pkgconfig.patch b/depends/patches/qt/fix_qt_pkgconfig.patch
index 8c722ffb46..a5de2b4b9e 100644
--- a/depends/patches/qt/fix_qt_pkgconfig.patch
+++ b/depends/patches/qt/fix_qt_pkgconfig.patch
@@ -1,17 +1,17 @@
--- old/qtbase/mkspecs/features/qt_module.prf
+++ new/qtbase/mkspecs/features/qt_module.prf
-@@ -264,7 +264,7 @@
+@@ -269,7 +269,7 @@ load(qt_installs)
load(qt_targets)
# this builds on top of qt_common
--!internal_module:!lib_bundle:if(unix|mingw) {
+-!internal_module:if(unix|mingw) {
+if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) {
CONFIG += create_pc
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
host_build: \
-@@ -274,9 +274,9 @@
- QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_HEADERS/raw]
- QMAKE_PKGCONFIG_CFLAGS = -I${includedir}/$$MODULE_INCNAME
+@@ -284,9 +284,9 @@ load(qt_targets)
+ QMAKE_PKGCONFIG_CFLAGS = -D$$MODULE_DEFINE -I${includedir}/$$MODULE_INCNAME
+ }
QMAKE_PKGCONFIG_NAME = $$replace(TARGET, ^Qt, "Qt$$QT_MAJOR_VERSION ")
- QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION)
+ QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION)$$qtPlatformTargetSuffix()
@@ -20,4 +20,4 @@
+ QMAKE_PKGCONFIG_REQUIRES += $$replace(QT.$${i}.name, ^Qt, Qt$$section(QT.$${i}.VERSION, ., 0, 0))$$qtPlatformTargetSuffix()
isEmpty(QMAKE_PKGCONFIG_DESCRIPTION): \
QMAKE_PKGCONFIG_DESCRIPTION = $$replace(TARGET, ^Qt, "Qt ") module
- pclib_replace.match = $$lib_replace.match
+ !isEmpty(lib_replace0.match) {
diff --git a/depends/patches/qt/fix_rcc_determinism.patch b/depends/patches/qt/fix_rcc_determinism.patch
deleted file mode 100644
index c1b07fe23a..0000000000
--- a/depends/patches/qt/fix_rcc_determinism.patch
+++ /dev/null
@@ -1,15 +0,0 @@
---- old/qtbase/src/tools/rcc/rcc.cpp
-+++ new/qtbase/src/tools/rcc/rcc.cpp
-@@ -207,7 +207,11 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib)
- if (lib.formatVersion() >= 2) {
- // last modified time stamp
- const QDateTime lastModified = m_fileInfo.lastModified();
-- lib.writeNumber8(quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0));
-+ quint64 lastmod = quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0);
-+ static const quint64 sourceDate = 1000 * qgetenv("QT_RCC_SOURCE_DATE_OVERRIDE").toULongLong();
-+ if (sourceDate != 0)
-+ lastmod = sourceDate;
-+ lib.writeNumber8(lastmod);
- if (text || pass1)
- lib.writeChar('\n');
- }
diff --git a/depends/patches/qt/fix_riscv64_arch.patch b/depends/patches/qt/fix_riscv64_arch.patch
deleted file mode 100644
index e7f29f01f9..0000000000
--- a/depends/patches/qt/fix_riscv64_arch.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff --git a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h
-index 20bfd36..93729fa 100644
---- a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h
-+++ b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h
-@@ -65,7 +65,8 @@
- defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
- defined(__SH4__) || defined(__alpha__) || \
- defined(_MIPS_ARCH_MIPS32R2) || \
-- defined(__AARCH64EL__)
-+ defined(__AARCH64EL__) || defined(__aarch64__) || \
-+ defined(__riscv)
- #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
- #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
- #if defined(_WIN32)
diff --git a/depends/patches/qt/freetype_back_compat.patch b/depends/patches/qt/freetype_back_compat.patch
deleted file mode 100644
index 1ca55f1ce3..0000000000
--- a/depends/patches/qt/freetype_back_compat.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-commit 14bc77db61bf9d56f9b6c8b84aa02573605c19c6
-Author: fanquake <fanquake@gmail.com>
-Date: Tue Aug 18 15:15:08 2020 +0800
-
- Fix backwards compatibility with older Freetype versions at runtime
-
- A few years ago, libfreetype introduced FT_Get_Font_Format() as an alias
- for FT_Get_X11_Font_Format(), but FT_Get_X11_Font_Format() was kept for abi
- backwards-compatibility.
-
- Qt 5.9 introduced a call to FT_Get_Font_Format(). Replace it with FT_Get_X11_Font_Format()
- in order to remain compatible with older freetype, which is still used by e.g. Ubuntu Trusty.
-
- See #14348.
-
-diff --git a/qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
-index 3f543755..8ecc1c8c 100644
---- a/qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
-+++ b/qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
-@@ -898,7 +898,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
- }
- }
- #if defined(FT_FONT_FORMATS_H)
-- const char *fmt = FT_Get_Font_Format(face);
-+ const char *fmt = FT_Get_X11_Font_Format(face);
- if (fmt && qstrncmp(fmt, "CFF", 4) == 0) {
- FT_Bool no_stem_darkening = true;
- FT_Error err = FT_Property_Get(qt_getFreetype(), "cff", "no-stem-darkening", &no_stem_darkening);
diff --git a/depends/patches/qt/no-xlib.patch b/depends/patches/qt/no-xlib.patch
index fe82c2c73c..f4a6f09ee4 100644
--- a/depends/patches/qt/no-xlib.patch
+++ b/depends/patches/qt/no-xlib.patch
@@ -22,15 +22,15 @@ index 7c62c2e2b3..c05c6c0a07 100644
#include <xcb/xfixes.h>
#include <xcb/xcb_image.h>
-@@ -384,6 +386,7 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget)
- w->setCursor(c, isBitmapCursor);
+@@ -391,6 +393,7 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *window)
+ xcb_flush(xcb_connection());
}
+#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
static int cursorIdForShape(int cshape)
{
int cursorId = 0;
-@@ -437,6 +440,7 @@ static int cursorIdForShape(int cshape)
+@@ -444,6 +447,7 @@ static int cursorIdForShape(int cshape)
}
return cursorId;
}
@@ -38,7 +38,7 @@ index 7c62c2e2b3..c05c6c0a07 100644
xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
{
-@@ -558,7 +562,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape)
+@@ -556,7 +560,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape)
xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
{
xcb_connection_t *conn = xcb_connection();
@@ -48,22 +48,23 @@ index 7c62c2e2b3..c05c6c0a07 100644
xcb_cursor_t cursor = XCB_NONE;
// Try Xcursor first
-@@ -589,6 +595,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
+@@ -585,7 +591,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
+
// Non-standard X11 cursors are created from bitmaps
cursor = createNonStandardCursor(cshape);
-
+-
+#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
// Create a glpyh cursor if everything else failed
if (!cursor && cursorId) {
cursor = xcb_generate_id(conn);
-@@ -596,6 +603,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
+@@ -593,6 +599,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
cursorId, cursorId + 1,
0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0);
}
+#endif
if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) {
- const char *name = cursorNames[cshape];
+ const char *name = cursorNames[cshape].front();
--
2.22.0
diff --git a/depends/patches/qt/no_sdk_version_check.patch b/depends/patches/qt/no_sdk_version_check.patch
new file mode 100644
index 0000000000..b16635b572
--- /dev/null
+++ b/depends/patches/qt/no_sdk_version_check.patch
@@ -0,0 +1,20 @@
+commit f5eb142cd04be2bc4ca610ed3b5b7e8ce3520ee3
+Author: fanquake <fanquake@gmail.com>
+Date: Tue Jan 5 16:08:49 2021 +0800
+
+ Don't invoke macOS SDK version checking
+
+ This tries to use xcrun which is not available when cross-compiling.
+
+diff --git a/qtbase/mkspecs/features/mac/default_post.prf b/qtbase/mkspecs/features/mac/default_post.prf
+index 92a9112bca6..447e186eb26 100644
+--- a/qtbase/mkspecs/features/mac/default_post.prf
++++ b/qtbase/mkspecs/features/mac/default_post.prf
+@@ -8,7 +8,6 @@ contains(TEMPLATE, .*app) {
+ !macx-xcode:if(isEmpty(BUILDS)|build_pass) {
+ # Detect changes to the platform SDK
+ QMAKE_EXTRA_VARIABLES += QMAKE_MAC_SDK QMAKE_MAC_SDK_VERSION QMAKE_XCODE_DEVELOPER_PATH
+- QMAKE_EXTRA_INCLUDES += $$shell_quote($$PWD/sdk.mk)
+ }
+
+ # Detect incompatible SDK versions
diff --git a/depends/patches/qt/xkb-default.patch b/depends/patches/qt/xkb-default.patch
deleted file mode 100644
index 165abf3e2e..0000000000
--- a/depends/patches/qt/xkb-default.patch
+++ /dev/null
@@ -1,26 +0,0 @@
---- old/qtbase/src/gui/configure.pri 2018-06-06 17:28:10.000000000 -0400
-+++ new/qtbase/src/gui/configure.pri 2018-08-17 18:43:01.589384567 -0400
-@@ -43,18 +43,11 @@
- }
-
- defineTest(qtConfTest_xkbConfigRoot) {
-- qtConfTest_getPkgConfigVariable($${1}): return(true)
--
-- for (dir, $$list("/usr/share/X11/xkb", "/usr/local/share/X11/xkb")) {
-- exists($$dir) {
-- $${1}.value = $$dir
-- export($${1}.value)
-- $${1}.cache += value
-- export($${1}.cache)
-- return(true)
-- }
-- }
-- return(false)
-+ $${1}.value = "/usr/share/X11/xkb"
-+ export($${1}.value)
-+ $${1}.cache += value
-+ export($${1}.cache)
-+ return(true)
- }
-
- defineTest(qtConfTest_qpaDefaultPlatform) {
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 8f2d7af089..0a78cdff20 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -595,11 +595,6 @@ Common misconceptions are clarified in those sections:
- *Rationale*: This avoids memory and resource leaks, and ensures exception safety.
-- Use `MakeUnique()` to construct objects owned by `unique_ptr`s.
-
- - *Rationale*: `MakeUnique` is concise and ensures exception safety in complex expressions.
- `MakeUnique` is a temporary project local implementation of `std::make_unique` (C++14).
-
C++ data structures
--------------------
diff --git a/doc/fuzzing.md b/doc/fuzzing.md
index 87df2bbbb9..4d8825f4c2 100644
--- a/doc/fuzzing.md
+++ b/doc/fuzzing.md
@@ -108,33 +108,32 @@ Full configure that was tested on macOS Catalina with `brew` installed `llvm`:
Read the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html) for more information. This [libFuzzer tutorial](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) might also be of interest.
-# Fuzzing Bitcoin Core using american fuzzy lop (`afl-fuzz`)
+# Fuzzing Bitcoin Core using afl++
## Quickstart guide
-To quickly get started fuzzing Bitcoin Core using [`afl-fuzz`](https://github.com/google/afl):
+To quickly get started fuzzing Bitcoin Core using [afl++](https://github.com/AFLplusplus/AFLplusplus):
```sh
$ git clone https://github.com/bitcoin/bitcoin
$ cd bitcoin/
-$ git clone https://github.com/google/afl
-$ make -C afl/
-$ make -C afl/llvm_mode/
+$ git clone https://github.com/AFLplusplus/AFLplusplus
+$ make -C AFLplusplus/ source-only
$ ./autogen.sh
-# It is possible to compile with afl-gcc and afl-g++ instead of afl-clang. However, running afl-fuzz
-# may require more memory via the -m flag.
-$ CC=$(pwd)/afl/afl-clang-fast CXX=$(pwd)/afl/afl-clang-fast++ ./configure --enable-fuzz
+# If afl-clang-lto is not available, see
+# https://github.com/AFLplusplus/AFLplusplus#a-selecting-the-best-afl-compiler-for-instrumenting-the-target
+$ CC=$(pwd)/AFLplusplus/afl-clang-lto CXX=$(pwd)/AFLplusplus/afl-clang-lto++ ./configure --enable-fuzz
$ make
# For macOS you may need to ignore x86 compilation checks when running "make". If so,
# try compiling using: AFL_NO_X86=1 make
$ mkdir -p inputs/ outputs/
$ echo A > inputs/thin-air-input
-$ FUZZ=bech32 afl/afl-fuzz -i inputs/ -o outputs/ -- src/test/fuzz/fuzz
+$ FUZZ=bech32 AFLplusplus/afl-fuzz -i inputs/ -o outputs/ -- src/test/fuzz/fuzz
# You may have to change a few kernel parameters to test optimally - afl-fuzz
# will print an error and suggestion if so.
```
-Read the [`afl-fuzz` documentation](https://github.com/google/afl) for more information.
+Read the [afl++ documentation](https://github.com/AFLplusplus/AFLplusplus) for more information.
# Fuzzing Bitcoin Core using Honggfuzz
diff --git a/src/Makefile.am b/src/Makefile.am
index 56f561a172..a70ef65aa7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -240,7 +240,6 @@ BITCOIN_CORE_H = \
util/golombrice.h \
util/hasher.h \
util/macros.h \
- util/memory.h \
util/message.h \
util/moneystr.h \
util/rbf.h \
@@ -253,6 +252,7 @@ BITCOIN_CORE_H = \
util/system.h \
util/threadnames.h \
util/time.h \
+ util/tokenpipe.h \
util/trace.h \
util/translation.h \
util/ui_change_type.h \
@@ -553,7 +553,6 @@ libbitcoin_util_a_SOURCES = \
support/lockedpool.cpp \
chainparamsbase.cpp \
clientversion.cpp \
- compat/glibc_sanity.cpp \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
fs.cpp \
@@ -584,6 +583,7 @@ libbitcoin_util_a_SOURCES = \
util/strencodings.cpp \
util/string.cpp \
util/time.cpp \
+ util/tokenpipe.cpp \
$(BITCOIN_CORE_H)
if USE_LIBEVENT
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 133277baa6..24b2879789 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -252,6 +252,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/net.cpp \
test/fuzz/net_permissions.cpp \
test/fuzz/netaddress.cpp \
+ test/fuzz/netbase_dns_lookup.cpp \
test/fuzz/node_eviction.cpp \
test/fuzz/p2p_transport_deserializer.cpp \
test/fuzz/parse_hd_keypath.cpp \
@@ -296,7 +297,8 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/transaction.cpp \
test/fuzz/tx_in.cpp \
test/fuzz/tx_out.cpp \
- test/fuzz/txrequest.cpp
+ test/fuzz/txrequest.cpp \
+ test/fuzz/validation_load_mempool.cpp
endif # ENABLE_FUZZ_BINARY
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 3abfbfd784..376e70ffba 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -17,7 +17,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<st
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
tx.vout.resize(1);
tx.vout[0].nValue = nValue;
- wtxs.push_back(MakeUnique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx))));
+ wtxs.push_back(std::make_unique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx))));
}
// Simple benchmark for wallet coin selection. Note that it maybe be necessary
@@ -73,7 +73,7 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>
CMutableTransaction tx;
tx.vout.resize(nInput + 1);
tx.vout[nInput].nValue = nValue;
- std::unique_ptr<CWalletTx> wtx = MakeUnique<CWalletTx>(&testWallet, MakeTransactionRef(std::move(tx)));
+ std::unique_ptr<CWalletTx> wtx = std::make_unique<CWalletTx>(&testWallet, MakeTransactionRef(std::move(tx)));
set.emplace_back();
set.back().Insert(COutput(wtx.get(), nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0, false);
wtxn.emplace_back(std::move(wtx));
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index b7bcb534ef..32f06aec2c 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -20,6 +20,7 @@
#include <util/strencodings.h>
#include <util/system.h>
#include <util/threadnames.h>
+#include <util/tokenpipe.h>
#include <util/translation.h>
#include <util/url.h>
@@ -28,6 +29,79 @@
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
UrlDecodeFn* const URL_DECODE = urlDecode;
+#if HAVE_DECL_FORK
+
+/** Custom implementation of daemon(). This implements the same order of operations as glibc.
+ * Opens a pipe to the child process to be able to wait for an event to occur.
+ *
+ * @returns 0 if successful, and in child process.
+ * >0 if successful, and in parent process.
+ * -1 in case of error (in parent process).
+ *
+ * In case of success, endpoint will be one end of a pipe from the child to parent process,
+ * which can be used with TokenWrite (in the child) or TokenRead (in the parent).
+ */
+int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint)
+{
+ // communication pipe with child process
+ std::optional<TokenPipe> umbilical = TokenPipe::Make();
+ if (!umbilical) {
+ return -1; // pipe or pipe2 failed.
+ }
+
+ int pid = fork();
+ if (pid < 0) {
+ return -1; // fork failed.
+ }
+ if (pid != 0) {
+ // Parent process gets read end, closes write end.
+ endpoint = umbilical->TakeReadEnd();
+ umbilical->TakeWriteEnd().Close();
+
+ int status = endpoint.TokenRead();
+ if (status != 0) { // Something went wrong while setting up child process.
+ endpoint.Close();
+ return -1;
+ }
+
+ return pid;
+ }
+ // Child process gets write end, closes read end.
+ endpoint = umbilical->TakeWriteEnd();
+ umbilical->TakeReadEnd().Close();
+
+#if HAVE_DECL_SETSID
+ if (setsid() < 0) {
+ exit(1); // setsid failed.
+ }
+#endif
+
+ if (!nochdir) {
+ if (chdir("/") != 0) {
+ exit(1); // chdir failed.
+ }
+ }
+ if (!noclose) {
+ // Open /dev/null, and clone it into STDIN, STDOUT and STDERR to detach
+ // from terminal.
+ int fd = open("/dev/null", O_RDWR);
+ if (fd >= 0) {
+ bool err = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0;
+ // Don't close if fd<=2 to try to handle the case where the program was invoked without any file descriptors open.
+ if (fd > 2) close(fd);
+ if (err) {
+ exit(1); // dup2 failed.
+ }
+ } else {
+ exit(1); // open /dev/null failed.
+ }
+ }
+ endpoint.TokenWrite(0); // Success
+ return 0;
+}
+
+#endif
+
static bool AppInit(int argc, char* argv[])
{
NodeContext node;
@@ -59,6 +133,14 @@ static bool AppInit(int argc, char* argv[])
return true;
}
+#if HAVE_DECL_FORK
+ // Communication with parent after daemonizing. This is used for signalling in the following ways:
+ // - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
+ // that the parent process can quit, and whether it was successful/unsuccessful.
+ // - an unexpected shutdown of the child process creates an unexpected end of stream at the parent
+ // end, which is interpreted as failure to start.
+ TokenPipeEnd daemon_ep;
+#endif
util::Ref context{node};
try
{
@@ -105,24 +187,34 @@ static bool AppInit(int argc, char* argv[])
// InitError will have been called with detailed error, which ends up on console
return false;
}
- if (args.GetBoolArg("-daemon", false)) {
-#if HAVE_DECL_DAEMON
-#if defined(MAC_OSX)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
+ if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
+#if HAVE_DECL_FORK
tfm::format(std::cout, PACKAGE_NAME " starting\n");
// Daemonize
- if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
- return InitError(Untranslated(strprintf("daemon() failed: %s\n", strerror(errno))));
+ switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
+ case 0: // Child: continue.
+ // If -daemonwait is not enabled, immediately send a success token the parent.
+ if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
+ daemon_ep.TokenWrite(1);
+ daemon_ep.Close();
+ }
+ break;
+ case -1: // Error happened.
+ return InitError(Untranslated(strprintf("fork_daemon() failed: %s\n", strerror(errno))));
+ default: { // Parent: wait and exit.
+ int token = daemon_ep.TokenRead();
+ if (token) { // Success
+ exit(EXIT_SUCCESS);
+ } else { // fRet = false or token read error (premature exit).
+ tfm::format(std::cerr, "Error during initializaton - check debug.log for details\n");
+ exit(EXIT_FAILURE);
+ }
+ }
}
-#if defined(MAC_OSX)
-#pragma GCC diagnostic pop
-#endif
#else
return InitError(Untranslated("-daemon is not supported on this operating system\n"));
-#endif // HAVE_DECL_DAEMON
+#endif // HAVE_DECL_FORK
}
// Lock data directory after daemonization
if (!AppInitLockDataDirectory())
@@ -138,6 +230,13 @@ static bool AppInit(int argc, char* argv[])
PrintExceptionContinue(nullptr, "AppInit()");
}
+#if HAVE_DECL_FORK
+ if (daemon_ep.IsOpen()) {
+ // Signal initialization status to parent, then close pipe.
+ daemon_ep.TokenWrite(fRet);
+ daemon_ep.Close();
+ }
+#endif
if (fRet) {
WaitForShutdown();
}
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 2c517b58f8..1631176477 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -7,7 +7,6 @@
#include <tinyformat.h>
#include <util/system.h>
-#include <util/memory.h>
#include <assert.h>
@@ -44,13 +43,13 @@ const CBaseChainParams& BaseParams()
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
{
if (chain == CBaseChainParams::MAIN) {
- return MakeUnique<CBaseChainParams>("", 8332, 8334);
+ return std::make_unique<CBaseChainParams>("", 8332, 8334);
} else if (chain == CBaseChainParams::TESTNET) {
- return MakeUnique<CBaseChainParams>("testnet3", 18332, 18334);
+ return std::make_unique<CBaseChainParams>("testnet3", 18332, 18334);
} else if (chain == CBaseChainParams::SIGNET) {
- return MakeUnique<CBaseChainParams>("signet", 38332, 38334);
+ return std::make_unique<CBaseChainParams>("signet", 38332, 38334);
} else if (chain == CBaseChainParams::REGTEST) {
- return MakeUnique<CBaseChainParams>("regtest", 18443, 18445);
+ return std::make_unique<CBaseChainParams>("regtest", 18443, 18445);
}
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp
index 8a51f310f7..ff581d4a9e 100644
--- a/src/compat/glibc_compat.cpp
+++ b/src/compat/glibc_compat.cpp
@@ -9,13 +9,6 @@
#include <cstddef>
#include <cstdint>
-// Prior to GLIBC_2.14, memcpy was aliased to memmove.
-extern "C" void* memmove(void* a, const void* b, size_t c);
-extern "C" void* memcpy(void* a, const void* b, size_t c)
-{
- return memmove(a, b, c);
-}
-
#if defined(__i386__) || defined(__arm__)
extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
deleted file mode 100644
index 06d0dd6fba..0000000000
--- a/src/compat/glibc_sanity.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2009-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.
-
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
-#include <cstddef>
-
-extern "C" void* memcpy(void* a, const void* b, size_t c);
-void* memcpy_int(void* a, const void* b, size_t c)
-{
- return memcpy(a, b, c);
-}
-
-namespace
-{
-// trigger: Use the memcpy_int wrapper which calls our internal memcpy.
-// A direct call to memcpy may be optimized away by the compiler.
-// test: Fill an array with a sequence of integers. memcpy to a new empty array.
-// Verify that the arrays are equal. Use an odd size to decrease the odds of
-// the call being optimized away.
-template <unsigned int T>
-bool sanity_test_memcpy()
-{
- unsigned int memcpy_test[T];
- unsigned int memcpy_verify[T] = {};
- for (unsigned int i = 0; i != T; ++i)
- memcpy_test[i] = i;
-
- memcpy_int(memcpy_verify, memcpy_test, sizeof(memcpy_test));
-
- for (unsigned int i = 0; i != T; ++i) {
- if (memcpy_verify[i] != i)
- return false;
- }
- return true;
-}
-} // namespace
-
-bool glibc_sanity_test()
-{
- return sanity_test_memcpy<1025>();
-}
diff --git a/src/compat/sanity.h b/src/compat/sanity.h
index 909c4f6da8..8efa416102 100644
--- a/src/compat/sanity.h
+++ b/src/compat/sanity.h
@@ -5,7 +5,6 @@
#ifndef BITCOIN_COMPAT_SANITY_H
#define BITCOIN_COMPAT_SANITY_H
-bool glibc_sanity_test();
bool glibcxx_sanity_test();
#endif // BITCOIN_COMPAT_SANITY_H
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index cb8b220895..867ddb090e 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -301,7 +301,7 @@ bool StartHTTPRPC(const util::Ref& context)
}
struct event_base* eventBase = EventBase();
assert(eventBase);
- httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(eventBase);
+ httpRPCTimerInterface = std::make_unique<HTTPRPCTimerInterface>(eventBase);
RPCSetTimerInterface(httpRPCTimerInterface.get());
return true;
}
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index 4f61bbeabd..32271fb7ab 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -102,8 +102,8 @@ BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type,
fs::create_directories(path);
m_name = filter_name + " block filter index";
- m_db = MakeUnique<BaseIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
- m_filter_fileseq = MakeUnique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
+ m_db = std::make_unique<BaseIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
+ m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
}
bool BlockFilterIndex::Init()
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 6398b7edc8..f41985c344 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -192,7 +192,7 @@ bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator&
}
TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
- : m_db(MakeUnique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
+ : m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
{}
TxIndex::~TxIndex() {}
diff --git a/src/init.cpp b/src/init.cpp
index 8aa80eacca..67ca98ee6f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -580,8 +580,9 @@ void SetupServerArgs(NodeContext& node)
argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
-#if HAVE_DECL_DAEMON
- argsman.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+#if HAVE_DECL_FORK
+ argsman.AddArg("-daemon", strprintf("Run in the background as a daemon and accept commands (default: %d)", DEFAULT_DAEMON), ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
+ argsman.AddArg("-daemonwait", strprintf("Wait for initialization to be finished before exiting. This implies -daemon (default: %d)", DEFAULT_DAEMONWAIT), ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
#else
hidden_args.emplace_back("-daemon");
#endif
@@ -771,7 +772,7 @@ static bool InitSanityCheck()
return InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting."));
}
- if (!glibc_sanity_test() || !glibcxx_sanity_test())
+ if (!glibcxx_sanity_test())
return false;
if (!Random_SanityCheck()) {
@@ -1349,7 +1350,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
assert(!node.scheduler);
- node.scheduler = MakeUnique<CScheduler>();
+ node.scheduler = std::make_unique<CScheduler>();
// Start the lightweight task scheduler thread
node.scheduler->m_service_thread = std::thread([&] { TraceThread("scheduler", [&] { node.scheduler->serviceQueue(); }); });
@@ -1401,9 +1402,9 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)};
assert(!node.banman);
- node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
+ node.banman = std::make_unique<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));
+ node.connman = std::make_unique<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,
@@ -1799,7 +1800,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
// ********************************************************* Step 8: start indexers
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- g_txindex = MakeUnique<TxIndex>(nTxIndexCache, false, fReindex);
+ g_txindex = std::make_unique<TxIndex>(nTxIndexCache, false, fReindex);
g_txindex->Start();
}
diff --git a/src/init.h b/src/init.h
index c04d966d06..34bca09dd1 100644
--- a/src/init.h
+++ b/src/init.h
@@ -9,6 +9,11 @@
#include <memory>
#include <string>
+//! Default value for -daemon option
+static constexpr bool DEFAULT_DAEMON = false;
+//! Default value for -daemonwait option
+static constexpr bool DEFAULT_DAEMONWAIT = false;
+
class ArgsManager;
struct NodeContext;
namespace interfaces {
diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp
index 4134a4527f..c6bbbed445 100644
--- a/src/interfaces/handler.cpp
+++ b/src/interfaces/handler.cpp
@@ -4,7 +4,6 @@
#include <interfaces/handler.h>
-#include <util/memory.h>
#include <boost/signals2/connection.hpp>
#include <utility>
@@ -35,12 +34,12 @@ public:
std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection)
{
- return MakeUnique<HandlerImpl>(std::move(connection));
+ return std::make_unique<HandlerImpl>(std::move(connection));
}
std::unique_ptr<Handler> MakeHandler(std::function<void()> cleanup)
{
- return MakeUnique<CleanupHandler>(std::move(cleanup));
+ return std::make_unique<CleanupHandler>(std::move(cleanup));
}
} // namespace interfaces
diff --git a/src/miner.cpp b/src/miner.cpp
index 076d43c951..fbaef0f224 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -39,13 +39,13 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime;
}
-void RegenerateCommitments(CBlock& block)
+void RegenerateCommitments(CBlock& block, BlockManager& blockman)
{
CMutableTransaction tx{*block.vtx.at(0)};
tx.vout.erase(tx.vout.begin() + GetWitnessCommitmentIndex(block));
block.vtx.at(0) = MakeTransactionRef(tx);
- GenerateCoinbaseCommitment(block, WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock)), Params().GetConsensus());
+ GenerateCoinbaseCommitment(block, WITH_LOCK(::cs_main, assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman)); return blockman.LookupBlockIndex(block.hashPrevBlock)), Params().GetConsensus());
block.hashMerkleRoot = BlockMerkleRoot(block);
}
@@ -99,7 +99,7 @@ void BlockAssembler::resetBlock()
Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt};
Optional<int64_t> BlockAssembler::m_last_block_weight{nullopt};
-std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
+std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn)
{
int64_t nTimeStart = GetTimeMicros();
@@ -117,7 +117,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end
LOCK2(cs_main, m_mempool.cs);
- CBlockIndex* pindexPrev = ::ChainActive().Tip();
+ assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*chainstate.m_chain.Tip()));
+ CBlockIndex* pindexPrev = chainstate.m_chain.Tip();
assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
@@ -176,7 +177,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
BlockValidationState state;
- if (!TestBlockValidity(state, chainparams, ::ChainstateActive(), *pblock, pindexPrev, false, false)) {
+ assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
+ if (!TestBlockValidity(state, chainparams, chainstate, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
}
int64_t nTime2 = GetTimeMicros();
diff --git a/src/miner.h b/src/miner.h
index 9a2b7063f4..a67fec6dd8 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -158,7 +158,7 @@ public:
explicit BlockAssembler(const CTxMemPool& mempool, const CChainParams& params, const Options& options);
/** Construct a new block template with coinbase to scriptPubKeyIn */
- std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
+ std::unique_ptr<CBlockTemplate> CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn);
static Optional<int64_t> m_last_block_num_txs;
static Optional<int64_t> m_last_block_weight;
@@ -202,6 +202,6 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
-void RegenerateCommitments(CBlock& block);
+void RegenerateCommitments(CBlock& block, BlockManager& blockman);
#endif // BITCOIN_MINER_H
diff --git a/src/net.cpp b/src/net.cpp
index cf7d3e50ba..1e4a6a9aa7 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2466,11 +2466,11 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (semOutbound == nullptr) {
// initialize semaphore
- semOutbound = MakeUnique<CSemaphore>(std::min(m_max_outbound, nMaxConnections));
+ semOutbound = std::make_unique<CSemaphore>(std::min(m_max_outbound, nMaxConnections));
}
if (semAddnode == nullptr) {
// initialize semaphore
- semAddnode = MakeUnique<CSemaphore>(nMaxAddnode);
+ semAddnode = std::make_unique<CSemaphore>(nMaxAddnode);
}
//
@@ -2906,11 +2906,11 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const
hSocket = hSocketIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
if (conn_type_in != ConnectionType::BLOCK_RELAY) {
- m_tx_relay = MakeUnique<TxRelay>();
+ m_tx_relay = std::make_unique<TxRelay>();
}
if (RelayAddrsWithConn()) {
- m_addr_known = MakeUnique<CRollingBloomFilter>(5000, 0.001);
+ m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
}
for (const std::string &msg : getAllNetMessageTypes())
@@ -2923,8 +2923,8 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const
LogPrint(BCLog::NET, "Added connection peer=%d\n", id);
}
- m_deserializer = MakeUnique<V1TransportDeserializer>(V1TransportDeserializer(Params(), GetId(), SER_NETWORK, INIT_PROTO_VERSION));
- m_serializer = MakeUnique<V1TransportSerializer>(V1TransportSerializer());
+ m_deserializer = std::make_unique<V1TransportDeserializer>(V1TransportDeserializer(Params(), GetId(), SER_NETWORK, INIT_PROTO_VERSION));
+ m_serializer = std::make_unique<V1TransportSerializer>(V1TransportSerializer());
}
CNode::~CNode()
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 86bafe6d27..6ce984348c 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -472,6 +472,24 @@ private:
std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans);
/** Offset into vExtraTxnForCompact to insert the next tx */
size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0;
+
+ void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool CanDirectFetch(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman);
+ bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_params,
+ BlockFilterType filter_type, uint32_t start_height,
+ const uint256& stop_hash, uint32_t max_height_diff,
+ const CBlockIndex*& stop_index,
+ BlockFilterIndex*& filter_index);
+ void ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
+ CConnman& connman);
+ void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
+ CConnman& connman);
+ void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
+ CConnman& connman);
};
} // namespace
@@ -539,7 +557,7 @@ struct CNodeState {
* - its connection type is IsBlockOnlyConn() == false
* - it gave us a valid connecting header
* - we haven't reached MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT yet
- * - it has a better chain than we have
+ * - its chain tip has at least as much work as ours
*
* CHAIN_SYNC_TIMEOUT: if a peer's best known block has less work than our tip,
* set a timeout CHAIN_SYNC_TIMEOUT seconds in the future:
@@ -557,16 +575,16 @@ struct CNodeState {
*/
struct ChainSyncTimeoutState {
//! A timeout used for checking whether our peer has sufficiently synced
- int64_t m_timeout;
+ int64_t m_timeout{0};
//! A header with the work we require on our peer's chain
- const CBlockIndex * m_work_header;
+ const CBlockIndex* m_work_header{nullptr};
//! After timeout is reached, set to true after sending getheaders
- bool m_sent_getheaders;
+ bool m_sent_getheaders{false};
//! Whether this peer is protected from disconnection due to a bad/slow chain
- bool m_protect;
+ bool m_protect{false};
};
- ChainSyncTimeoutState m_chain_sync{0, nullptr, false, false};
+ ChainSyncTimeoutState m_chain_sync;
//! Time of last new block announcement
int64_t m_last_block_announcement{0};
@@ -580,11 +598,7 @@ struct CNodeState {
//! Whether this peer relays txs via wtxid
bool m_wtxid_relay{false};
- CNodeState(bool is_inbound)
- : m_is_inbound(is_inbound)
- {
- m_recently_announced_invs.reset();
- }
+ CNodeState(bool is_inbound) : m_is_inbound(is_inbound) {}
};
/** Map maintaining per-node state. */
@@ -665,41 +679,6 @@ bool PeerManagerImpl::MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, co
return true;
}
-/** Check whether the last unknown block a peer advertised is not yet known. */
-static void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
- CNodeState *state = State(nodeid);
- assert(state != nullptr);
-
- if (!state->hashLastUnknownBlock.IsNull()) {
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(state->hashLastUnknownBlock);
- if (pindex && pindex->nChainWork > 0) {
- if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
- state->pindexBestKnownBlock = pindex;
- }
- state->hashLastUnknownBlock.SetNull();
- }
- }
-}
-
-/** Update tracking information about which blocks a peer is assumed to have. */
-static void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
- CNodeState *state = State(nodeid);
- assert(state != nullptr);
-
- ProcessBlockAvailability(nodeid);
-
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
- if (pindex && pindex->nChainWork > 0) {
- // An actually better block was announced.
- if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
- state->pindexBestKnownBlock = pindex;
- }
- } else {
- // An unknown block was announced; just assume that the latest one is the best one.
- state->hashLastUnknownBlock = hash;
- }
-}
-
void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid)
{
AssertLockHeld(cs_main);
@@ -749,9 +728,9 @@ bool PeerManagerImpl::TipMayBeStale()
return m_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty();
}
-static bool CanDirectFetch(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+bool PeerManagerImpl::CanDirectFetch(const Consensus::Params &consensusParams)
{
- return ::ChainActive().Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;
+ return m_chainman.ActiveChain().Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;
}
static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -763,6 +742,41 @@ static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIV
return false;
}
+/** Check whether the last unknown block a peer advertised is not yet known. */
+void PeerManagerImpl::ProcessBlockAvailability(NodeId nodeid) {
+ CNodeState *state = State(nodeid);
+ assert(state != nullptr);
+
+ if (!state->hashLastUnknownBlock.IsNull()) {
+ const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(state->hashLastUnknownBlock);
+ if (pindex && pindex->nChainWork > 0) {
+ if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
+ state->pindexBestKnownBlock = pindex;
+ }
+ state->hashLastUnknownBlock.SetNull();
+ }
+ }
+}
+
+/** Update tracking information about which blocks a peer is assumed to have. */
+void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
+ CNodeState *state = State(nodeid);
+ assert(state != nullptr);
+
+ ProcessBlockAvailability(nodeid);
+
+ const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hash);
+ if (pindex && pindex->nChainWork > 0) {
+ // An actually better block was announced.
+ if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
+ state->pindexBestKnownBlock = pindex;
+ }
+ } else {
+ // An unknown block was announced; just assume that the latest one is the best one.
+ state->hashLastUnknownBlock = hash;
+ }
+}
+
void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller)
{
if (count == 0)
@@ -775,7 +789,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(nodeid);
- if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < ::ChainActive().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
// This peer has nothing interesting.
return;
}
@@ -783,7 +797,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
if (state->pindexLastCommonBlock == nullptr) {
// Bootstrap quickly by guessing a parent of our best tip is the forking point.
// Guessing wrong in either direction is not a problem.
- state->pindexLastCommonBlock = ::ChainActive()[std::min(state->pindexBestKnownBlock->nHeight, ::ChainActive().Height())];
+ state->pindexLastCommonBlock = m_chainman.ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight, m_chainman.ActiveChain().Height())];
}
// If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor
@@ -826,7 +840,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
// We wouldn't download this block or its descendants from this peer.
return;
}
- if (pindex->nStatus & BLOCK_HAVE_DATA || ::ChainActive().Contains(pindex)) {
+ if (pindex->nStatus & BLOCK_HAVE_DATA || m_chainman.ActiveChain().Contains(pindex)) {
if (pindex->HaveTxsDownloaded())
state->pindexLastCommonBlock = pindex;
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
@@ -1179,10 +1193,10 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
// active chain if they are no more than a month older (both in time, and in
// best equivalent proof of work) than the best header chain we know about and
// we fully-validated them at some point.
-static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams)
{
AssertLockHeld(cs_main);
- if (::ChainActive().Contains(pindex)) return true;
+ if (m_chainman.ActiveChain().Contains(pindex)) return true;
return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
(pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
@@ -1206,6 +1220,7 @@ PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& conn
m_stale_tip_check_time(0),
m_ignore_incoming_txs(ignore_incoming_txs)
{
+ assert(std::addressof(g_chainman) == std::addressof(m_chainman));
// Initialize global variables that cannot be constructed at startup.
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
@@ -1331,7 +1346,7 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
/**
* Update our best height and announce any block hashes which weren't previously
- * in ::ChainActive() to our peers.
+ * in m_chainman.ActiveChain() to our peers.
*/
void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
{
@@ -1393,7 +1408,7 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta
// the tip yet so we have no way to check this directly here. Instead we
// just check that there are currently no other blocks in flight.
else if (state.IsValid() &&
- !::ChainstateActive().IsInitialBlockDownload() &&
+ !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
if (it != mapBlockSource.end()) {
MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
@@ -1412,12 +1427,12 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta
bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid)
{
assert(recentRejects);
- if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip) {
+ if (m_chainman.ActiveChain().Tip()->GetBlockHash() != hashRecentRejectsChainTip) {
// If the chain tip has changed previously rejected transactions
// might be now valid, e.g. due to a nLockTime'd tx becoming valid,
// or a double-spend. Reset the rejects filter and give those
// txs a second chance.
- hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash();
+ hashRecentRejectsChainTip = m_chainman.ActiveChain().Tip()->GetBlockHash();
recentRejects->reset();
}
@@ -1433,9 +1448,9 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid)
return recentRejects->contains(hash) || m_mempool.exists(gtxid);
}
-bool static AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+bool PeerManagerImpl::AlreadyHaveBlock(const uint256& block_hash)
{
- return g_chainman.m_blockman.LookupBlockIndex(block_hash) != nullptr;
+ return m_chainman.m_blockman.LookupBlockIndex(block_hash) != nullptr;
}
void PeerManagerImpl::SendPings()
@@ -1514,7 +1529,7 @@ static void RelayAddress(const CNode& originator,
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
}
-void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman)
+void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman)
{
bool send = false;
std::shared_ptr<const CBlock> a_recent_block;
@@ -1531,7 +1546,7 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
bool need_activate_chain = false;
{
LOCK(cs_main);
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(inv.hash);
+ const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(inv.hash);
if (pindex) {
if (pindex->HaveTxsDownloaded() && !pindex->IsValid(BLOCK_VALID_SCRIPTS) &&
pindex->IsValid(BLOCK_VALID_TREE)) {
@@ -1546,13 +1561,13 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
} // release cs_main before calling ActivateBestChain
if (need_activate_chain) {
BlockValidationState state;
- if (!::ChainstateActive().ActivateBestChain(state, chainparams, a_recent_block)) {
+ if (!m_chainman.ActiveChainstate().ActivateBestChain(state, chainparams, a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString());
}
}
LOCK(cs_main);
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(inv.hash);
+ const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(inv.hash);
if (pindex) {
send = BlockRequestAllowed(pindex, consensusParams);
if (!send) {
@@ -1574,7 +1589,7 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
}
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
if (send && !pfrom.HasPermission(PF_NOBAN) && (
- (((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (::ChainActive().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
+ (((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (m_chainman.ActiveChain().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) {
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom.GetId());
@@ -1641,7 +1656,7 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
// instead we respond with the full, non-compact block.
bool fPeerWantsWitness = State(pfrom.GetId())->fWantsCmpctWitness;
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
- if (CanDirectFetch(consensusParams) && pindex->nHeight >= ::ChainActive().Height() - MAX_CMPCTBLOCK_DEPTH) {
+ if (CanDirectFetch(consensusParams) && pindex->nHeight >= m_chainman.ActiveChain().Height() - MAX_CMPCTBLOCK_DEPTH) {
if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) {
connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
} else {
@@ -1662,7 +1677,7 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
// and we want it right after the last block so they don't
// wait for other stuff first.
std::vector<CInv> vInv;
- vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash()));
+ vInv.push_back(CInv(MSG_BLOCK, m_chainman.ActiveChain().Tip()->GetBlockHash()));
connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv));
peer.m_continuation_block.SetNull();
}
@@ -1841,9 +1856,9 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// don't connect before giving DoS points
// - Once a headers message is received that is valid and does connect,
// nUnconnectingHeaders gets reset back to 0.
- if (!g_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
+ if (!m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++;
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256()));
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(),
@@ -1871,7 +1886,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// If we don't have the last header, then they'll have given us
// something new (if these headers are valid).
- if (!g_chainman.m_blockman.LookupBlockIndex(hashLastBlock)) {
+ if (!m_chainman.m_blockman.LookupBlockIndex(hashLastBlock)) {
received_new_header = true;
}
}
@@ -1899,27 +1914,27 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// because it is set in UpdateBlockAvailability. Some nullptr checks
// are still present, however, as belt-and-suspenders.
- if (received_new_header && pindexLast->nChainWork > ::ChainActive().Tip()->nChainWork) {
+ if (received_new_header && pindexLast->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
nodestate->m_last_block_announcement = GetTime();
}
if (nCount == MAX_HEADERS_RESULTS) {
// Headers message had its maximum size; the peer may have more headers.
- // TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue
+ // TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or pindexBestHeader, continue
// from there instead.
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256()));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexLast), uint256()));
}
bool fCanDirectFetch = CanDirectFetch(m_chainparams.GetConsensus());
// If this set of headers is valid and ends in a block with at least as
// much work as our tip, download as much as possible.
- if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && ::ChainActive().Tip()->nChainWork <= pindexLast->nChainWork) {
+ if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) {
std::vector<const CBlockIndex*> vToFetch;
const CBlockIndex *pindexWalk = pindexLast;
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
- while (pindexWalk && !::ChainActive().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
!mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
(!IsWitnessEnabled(pindexWalk->pprev, m_chainparams.GetConsensus()) || State(pfrom.GetId())->fHaveWitness)) {
@@ -1932,7 +1947,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// very large reorg at a time we think we're close to caught up to
// the main chain -- this shouldn't really happen. Bail out on the
// direct fetch and rely on parallel download instead.
- if (!::ChainActive().Contains(pindexWalk)) {
+ if (!m_chainman.ActiveChain().Contains(pindexWalk)) {
LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
pindexLast->GetBlockHash().ToString(),
pindexLast->nHeight);
@@ -1965,7 +1980,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
}
// If we're in IBD, we want outbound peers that will serve us a useful
// chain. Disconnect peers that are on chains with insufficient work.
- if (::ChainstateActive().IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
+ if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
// When nCount < MAX_HEADERS_RESULTS, we know we have no more
// headers to fetch from this peer.
if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
@@ -1973,7 +1988,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// us sync -- disconnect if it is an outbound disconnection
// candidate.
// Note: We compare their tip to nMinimumChainWork (rather than
- // ::ChainActive().Tip()) because we won't start block download
+ // m_chainman.ActiveChain().Tip()) because we won't start block download
// until we have a headers chain that has at least
// nMinimumChainWork, even if a peer has a chain past our tip,
// as an anti-DoS measure.
@@ -1990,7 +2005,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// thus always subject to eviction under the bad/lagging chain logic.
// See ChainSyncTimeoutState.
if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn() && nodestate->pindexBestKnownBlock != nullptr) {
- if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
+ if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId());
nodestate->m_chain_sync.m_protect = true;
++m_outbound_peers_with_protect_from_disconnect;
@@ -2021,7 +2036,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
const auto [porphanTx, from_peer] = m_orphanage.GetTx(orphanHash);
if (porphanTx == nullptr) continue;
- const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), m_mempool, porphanTx, false /* bypass_limits */);
+ const MempoolAcceptResult result = AcceptToMemoryPool(m_chainman.ActiveChainstate(), m_mempool, porphanTx, false /* bypass_limits */);
const TxValidationState& state = result.m_state;
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
@@ -2097,7 +2112,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
* @param[out] filter_index The filter index, if the request can be serviced.
* @return True if the request can be serviced.
*/
-static bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_params,
+bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_params,
BlockFilterType filter_type, uint32_t start_height,
const uint256& stop_hash, uint32_t max_height_diff,
const CBlockIndex*& stop_index,
@@ -2115,7 +2130,7 @@ static bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_par
{
LOCK(cs_main);
- stop_index = g_chainman.m_blockman.LookupBlockIndex(stop_hash);
+ stop_index = m_chainman.m_blockman.LookupBlockIndex(stop_hash);
// Check that the stop block exists and the peer would be allowed to fetch it.
if (!stop_index || !BlockRequestAllowed(stop_index, chain_params.GetConsensus())) {
@@ -2160,7 +2175,7 @@ static bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_par
* @param[in] chain_params Chain parameters
* @param[in] connman Pointer to the connection manager
*/
-static void ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
+void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman)
{
uint8_t filter_type_ser;
@@ -2202,7 +2217,7 @@ static void ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainPara
* @param[in] chain_params Chain parameters
* @param[in] connman Pointer to the connection manager
*/
-static void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
+void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman)
{
uint8_t filter_type_ser;
@@ -2257,7 +2272,7 @@ static void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainPar
* @param[in] chain_params Chain parameters
* @param[in] connman Pointer to the connection manager
*/
-static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
+void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman)
{
uint8_t filter_type_ser;
@@ -2440,7 +2455,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
//
// We skip this for block-relay-only peers to avoid potentially leaking
// information about our block-relay-only connections via address relay.
- if (fListen && !::ChainstateActive().IsInitialBlockDownload())
+ if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices());
FastRandomContext insecure_rand;
@@ -2757,7 +2772,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (best_block != nullptr) {
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), *best_block));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), *best_block));
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId());
}
@@ -2813,7 +2828,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
a_recent_block = most_recent_block;
}
BlockValidationState state;
- if (!::ChainstateActive().ActivateBestChain(state, m_chainparams, a_recent_block)) {
+ if (!m_chainman.ActiveChainstate().ActivateBestChain(state, m_chainparams, a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString());
}
}
@@ -2821,14 +2836,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LOCK(cs_main);
// Find the last block the caller has in the main chain
- const CBlockIndex* pindex = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator);
+ const CBlockIndex* pindex = m_chainman.m_blockman.FindForkInGlobalIndex(m_chainman.ActiveChain(), locator);
// Send the rest of the chain
if (pindex)
- pindex = ::ChainActive().Next(pindex);
+ pindex = m_chainman.ActiveChain().Next(pindex);
int nLimit = 500;
LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom.GetId());
- for (; pindex; pindex = ::ChainActive().Next(pindex))
+ for (; pindex; pindex = m_chainman.ActiveChain().Next(pindex))
{
if (pindex->GetBlockHash() == hashStop)
{
@@ -2838,7 +2853,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// If pruning, don't inv blocks unless we have on disk and are likely to still have
// for some reasonable time window (1 hour) that block relay might require.
const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / m_chainparams.GetConsensus().nPowTargetSpacing;
- if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= ::ChainActive().Tip()->nHeight - nPrunedBlocksLikelyToHave))
+ if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= m_chainman.ActiveChain().Tip()->nHeight - nPrunedBlocksLikelyToHave))
{
LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
break;
@@ -2874,13 +2889,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
{
LOCK(cs_main);
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(req.blockhash);
+ const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(req.blockhash);
if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) {
LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId());
return;
}
- if (pindex->nHeight >= ::ChainActive().Height() - MAX_BLOCKTXN_DEPTH) {
+ if (pindex->nHeight >= m_chainman.ActiveChain().Height() - MAX_BLOCKTXN_DEPTH) {
CBlock block;
bool ret = ReadBlockFromDisk(block, pindex, m_chainparams.GetConsensus());
assert(ret);
@@ -2918,7 +2933,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
LOCK(cs_main);
- if (::ChainstateActive().IsInitialBlockDownload() && !pfrom.HasPermission(PF_DOWNLOAD)) {
+ if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && !pfrom.HasPermission(PF_DOWNLOAD)) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom.GetId());
return;
}
@@ -2928,7 +2943,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (locator.IsNull())
{
// If locator is null, return the hashStop block
- pindex = g_chainman.m_blockman.LookupBlockIndex(hashStop);
+ pindex = m_chainman.m_blockman.LookupBlockIndex(hashStop);
if (!pindex) {
return;
}
@@ -2941,23 +2956,23 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
else
{
// Find the last block the caller has in the main chain
- pindex = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator);
+ pindex = m_chainman.m_blockman.FindForkInGlobalIndex(m_chainman.ActiveChain(), locator);
if (pindex)
- pindex = ::ChainActive().Next(pindex);
+ pindex = m_chainman.ActiveChain().Next(pindex);
}
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
std::vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS;
LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom.GetId());
- for (; pindex; pindex = ::ChainActive().Next(pindex))
+ for (; pindex; pindex = m_chainman.ActiveChain().Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
break;
}
- // pindex can be nullptr either if we sent ::ChainActive().Tip() OR
- // if our peer has ::ChainActive().Tip() (and thus we are sending an empty
+ // pindex can be nullptr either if we sent m_chainman.ActiveChain().Tip() OR
+ // if our peer has m_chainman.ActiveChain().Tip() (and thus we are sending an empty
// headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip.
//
@@ -2968,7 +2983,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// without the new block. By resetting the BestHeaderSent, we ensure we
// will re-announce the new block via headers (or compact blocks again)
// in the SendMessages logic.
- nodestate->pindexBestHeaderSent = pindex ? pindex : ::ChainActive().Tip();
+ nodestate->pindexBestHeaderSent = pindex ? pindex : m_chainman.ActiveChain().Tip();
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
return;
}
@@ -3036,7 +3051,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
- const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), m_mempool, ptx, false /* bypass_limits */);
+ const MempoolAcceptResult result = AcceptToMemoryPool(m_chainman.ActiveChainstate(), m_mempool, ptx, false /* bypass_limits */);
const TxValidationState& state = result.m_state;
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
@@ -3201,14 +3216,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
{
LOCK(cs_main);
- if (!g_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
+ if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
- if (!::ChainstateActive().IsInitialBlockDownload())
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
+ if (!m_chainman.ActiveChainstate().IsInitialBlockDownload())
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256()));
return;
}
- if (!g_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.GetHash())) {
+ if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.GetHash())) {
received_new_header = true;
}
}
@@ -3248,7 +3263,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// If this was a new header with more work than our tip, update the
// peer's last block announcement time
- if (received_new_header && pindex->nChainWork > ::ChainActive().Tip()->nChainWork) {
+ if (received_new_header && pindex->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
nodestate->m_last_block_announcement = GetTime();
}
@@ -3258,7 +3273,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
return;
- if (pindex->nChainWork <= ::ChainActive().Tip()->nChainWork || // We know something better
+ if (pindex->nChainWork <= m_chainman.ActiveChain().Tip()->nChainWork || // We know something better
pindex->nTx != 0) { // We had this block at some point, but pruned it
if (fAlreadyInFlight) {
// We requested this block for some reason, but our mempool will probably be useless
@@ -3282,7 +3297,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// We want to be a bit conservative just to be extra careful about DoS
// possibilities in compact block processing...
- if (pindex->nHeight <= ::ChainActive().Height() + 2) {
+ if (pindex->nHeight <= m_chainman.ActiveChain().Height() + 2) {
if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
(fAlreadyInFlight && blockInFlightIt->second.first == pfrom.GetId())) {
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;
@@ -3930,7 +3945,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
// their chain has more work than ours, we should sync to it,
// unless it's invalid, in which case we should find that out and
// disconnect from them elsewhere).
- if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork) {
+ if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork) {
if (state.m_chain_sync.m_timeout != 0) {
state.m_chain_sync.m_timeout = 0;
state.m_chain_sync.m_work_header = nullptr;
@@ -3942,7 +3957,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
// where we checked against our tip.
// Either way, set a new timeout based on current tip.
state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT;
- state.m_chain_sync.m_work_header = ::ChainActive().Tip();
+ state.m_chain_sync.m_work_header = m_chainman.ActiveChain().Tip();
state.m_chain_sync.m_sent_getheaders = false;
} else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) {
// No evidence yet that our peer has synced to a chain with work equal to that
@@ -3955,7 +3970,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
} else {
assert(state.m_chain_sync.m_work_header);
LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
- m_connman.PushMessage(&pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
+ m_connman.PushMessage(&pto, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
state.m_chain_sync.m_sent_getheaders = true;
constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes
// Bump the timeout to allow a response, which could clear the timeout
@@ -4192,7 +4207,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
auto current_time = GetTime<std::chrono::microseconds>();
if (fListen && pto->RelayAddrsWithConn() &&
- !::ChainstateActive().IsInitialBlockDownload() &&
+ !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
pto->m_next_local_addr_send < current_time) {
// If we've sent before, clear the bloom filter for the peer, so that our
// self-announcement will actually go out.
@@ -4253,7 +4268,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Start block sync
if (pindexBestHeader == nullptr)
- pindexBestHeader = ::ChainActive().Tip();
+ pindexBestHeader = m_chainman.ActiveChain().Tip();
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do.
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today.
@@ -4278,7 +4293,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height);
- m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexStart), uint256()));
+ m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexStart), uint256()));
}
}
@@ -4305,11 +4320,11 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
bool fFoundStartingHeader = false;
// Try to find first header that our peer doesn't have, and
// then send all headers past that one. If we come across any
- // headers that aren't on ::ChainActive(), give up.
+ // headers that aren't on m_chainman.ActiveChain(), give up.
for (const uint256& hash : peer->m_blocks_for_headers_relay) {
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
+ const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hash);
assert(pindex);
- if (::ChainActive()[pindex->nHeight] != pindex) {
+ if (m_chainman.ActiveChain()[pindex->nHeight] != pindex) {
// Bail out if we reorged away from this block
fRevertToInv = true;
break;
@@ -4399,15 +4414,15 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// in the past.
if (!peer->m_blocks_for_headers_relay.empty()) {
const uint256& hashToAnnounce = peer->m_blocks_for_headers_relay.back();
- const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hashToAnnounce);
+ const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hashToAnnounce);
assert(pindex);
// Warn if we're announcing a block that is not on the main chain.
// This should be very rare and could be optimized out.
// Just log for now.
- if (::ChainActive()[pindex->nHeight] != pindex) {
+ if (m_chainman.ActiveChain()[pindex->nHeight] != pindex) {
LogPrint(BCLog::NET, "Announcing block %s not on main chain (tip=%s)\n",
- hashToAnnounce.ToString(), ::ChainActive().Tip()->GetBlockHash().ToString());
+ hashToAnnounce.ToString(), m_chainman.ActiveChain().Tip()->GetBlockHash().ToString());
}
// If the peer's chain has this block, don't inv it back.
@@ -4637,7 +4652,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Message: getdata (blocks)
//
std::vector<CInv> vGetData;
- if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !::ChainstateActive().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !m_chainman.ActiveChainstate().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
std::vector<const CBlockIndex*> vToDownload;
NodeId staller = -1;
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
@@ -4726,4 +4741,3 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
} // release cs_main
return true;
}
-
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 88c36ed86c..ac2392ebed 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -42,6 +42,50 @@ bool fNameLookup = DEFAULT_NAME_LOOKUP;
int g_socks5_recv_timeout = 20 * 1000;
static std::atomic<bool> interruptSocks5Recv(false);
+std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup)
+{
+ addrinfo ai_hint{};
+ // We want a TCP port, which is a streaming socket type
+ ai_hint.ai_socktype = SOCK_STREAM;
+ ai_hint.ai_protocol = IPPROTO_TCP;
+ // We don't care which address family (IPv4 or IPv6) is returned
+ ai_hint.ai_family = AF_UNSPEC;
+ // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only
+ // return addresses whose family we have an address configured for.
+ //
+ // If we don't allow lookups, then use the AI_NUMERICHOST flag for
+ // getaddrinfo to only decode numerical network addresses and suppress
+ // hostname lookups.
+ ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
+
+ addrinfo* ai_res{nullptr};
+ const int n_err{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)};
+ if (n_err != 0) {
+ return {};
+ }
+
+ // Traverse the linked list starting with ai_trav.
+ addrinfo* ai_trav{ai_res};
+ std::vector<CNetAddr> resolved_addresses;
+ while (ai_trav != nullptr) {
+ if (ai_trav->ai_family == AF_INET) {
+ assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in));
+ resolved_addresses.emplace_back(reinterpret_cast<sockaddr_in*>(ai_trav->ai_addr)->sin_addr);
+ }
+ if (ai_trav->ai_family == AF_INET6) {
+ assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in6));
+ const sockaddr_in6* s6{reinterpret_cast<sockaddr_in6*>(ai_trav->ai_addr)};
+ resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
+ }
+ ai_trav = ai_trav->ai_next;
+ }
+ freeaddrinfo(ai_res);
+
+ return resolved_addresses;
+}
+
+DNSLookupFn g_dns_lookup{WrappedGetAddrInfo};
+
enum Network ParseNetwork(const std::string& net_in) {
std::string net = ToLower(net_in);
if (net == "ipv4") return NET_IPV4;
@@ -87,7 +131,7 @@ std::vector<std::string> GetNetworkNames(bool append_unroutable)
return names;
}
-bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
+static bool LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
vIP.clear();
@@ -109,73 +153,20 @@ bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, un
}
}
- struct addrinfo aiHint;
- memset(&aiHint, 0, sizeof(struct addrinfo));
-
- // We want a TCP port, which is a streaming socket type
- aiHint.ai_socktype = SOCK_STREAM;
- aiHint.ai_protocol = IPPROTO_TCP;
- // We don't care which address family (IPv4 or IPv6) is returned
- aiHint.ai_family = AF_UNSPEC;
- // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only
- // return addresses whose family we have an address configured for.
- //
- // If we don't allow lookups, then use the AI_NUMERICHOST flag for
- // getaddrinfo to only decode numerical network addresses and suppress
- // hostname lookups.
- aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
- struct addrinfo *aiRes = nullptr;
- int nErr = getaddrinfo(name.c_str(), nullptr, &aiHint, &aiRes);
- if (nErr)
- return false;
-
- // Traverse the linked list starting with aiTrav, add all non-internal
- // IPv4,v6 addresses to vIP while respecting nMaxSolutions.
- struct addrinfo *aiTrav = aiRes;
- while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
- {
- CNetAddr resolved;
- if (aiTrav->ai_family == AF_INET)
- {
- assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
- resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
- }
-
- if (aiTrav->ai_family == AF_INET6)
- {
- assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
- struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
- resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
+ for (const CNetAddr& resolved : dns_lookup_function(name, fAllowLookup)) {
+ if (nMaxSolutions > 0 && vIP.size() >= nMaxSolutions) {
+ break;
}
/* Never allow resolving to an internal address. Consider any such result invalid */
if (!resolved.IsInternal()) {
vIP.push_back(resolved);
}
-
- aiTrav = aiTrav->ai_next;
}
- freeaddrinfo(aiRes);
-
return (vIP.size() > 0);
}
-/**
- * Resolve a host string to its corresponding network addresses.
- *
- * @param name The string representing a host. Could be a name or a numerical
- * IP address (IPv6 addresses in their bracketed form are
- * allowed).
- * @param[out] vIP The resulting network addresses to which the specified host
- * string resolved.
- *
- * @returns Whether or not the specified host string successfully resolved to
- * any resulting network addresses.
- *
- * @see Lookup(const char *, std::vector<CService>&, int, bool, unsigned int)
- * for additional parameter descriptions.
- */
-bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
+bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
return false;
@@ -187,49 +178,23 @@ bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned in
strHost = strHost.substr(1, strHost.size() - 2);
}
- return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup);
+ return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
}
- /**
- * Resolve a host string to its first corresponding network address.
- *
- * @see LookupHost(const std::string&, std::vector<CNetAddr>&, unsigned int, bool) for
- * additional parameter descriptions.
- */
-bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup)
+bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
return false;
}
std::vector<CNetAddr> vIP;
- LookupHost(name, vIP, 1, fAllowLookup);
+ LookupHost(name, vIP, 1, fAllowLookup, dns_lookup_function);
if(vIP.empty())
return false;
addr = vIP.front();
return true;
}
-/**
- * Resolve a service string to its corresponding service.
- *
- * @param name The string representing a service. Could be a name or a
- * numerical IP address (IPv6 addresses should be in their
- * disambiguated bracketed form), optionally followed by a port
- * number. (e.g. example.com:8333 or
- * [2001:db8:85a3:8d3:1319:8a2e:370:7348]:420)
- * @param[out] vAddr The resulting services to which the specified service string
- * resolved.
- * @param portDefault The default port for resulting services if not specified
- * by the service string.
- * @param fAllowLookup Whether or not hostname lookups are permitted. If yes,
- * external queries may be performed.
- * @param nMaxSolutions The maximum number of results we want, specifying 0
- * means "as many solutions as we get."
- *
- * @returns Whether or not the service string successfully resolved to any
- * resulting services.
- */
-bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
+bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
{
if (name.empty() || !ValidAsCString(name)) {
return false;
@@ -239,7 +204,7 @@ bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefau
SplitHostPort(name, port, hostname);
std::vector<CNetAddr> vIP;
- bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup);
+ bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
if (!fRet)
return false;
vAddr.resize(vIP.size());
@@ -248,36 +213,20 @@ bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefau
return true;
}
-/**
- * Resolve a service string to its first corresponding service.
- *
- * @see Lookup(const char *, std::vector<CService>&, int, bool, unsigned int)
- * for additional parameter descriptions.
- */
-bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup)
+bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
return false;
}
std::vector<CService> vService;
- bool fRet = Lookup(name, vService, portDefault, fAllowLookup, 1);
+ bool fRet = Lookup(name, vService, portDefault, fAllowLookup, 1, dns_lookup_function);
if (!fRet)
return false;
addr = vService[0];
return true;
}
-/**
- * Resolve a service string with a numeric IP to its first corresponding
- * service.
- *
- * @returns The resulting CService if the resolution was successful, [::]:0
- * otherwise.
- *
- * @see Lookup(const char *, CService&, int, bool) for additional parameter
- * descriptions.
- */
-CService LookupNumeric(const std::string& name, int portDefault)
+CService LookupNumeric(const std::string& name, int portDefault, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
return {};
@@ -285,7 +234,7 @@ CService LookupNumeric(const std::string& name, int portDefault)
CService addr;
// "1.2:345" will fail to resolve the ip, but will still set the port.
// If the ip fails to resolve, re-init the result.
- if(!Lookup(name, addr, portDefault, false))
+ if(!Lookup(name, addr, portDefault, false, dns_lookup_function))
addr = CService();
return addr;
}
@@ -414,24 +363,6 @@ static std::string Socks5ErrorString(uint8_t err)
}
}
-/**
- * Connect to a specified destination service through an already connected
- * SOCKS5 proxy.
- *
- * @param strDest The destination fully-qualified domain name.
- * @param port The destination port.
- * @param auth The credentials with which to authenticate with the specified
- * SOCKS5 proxy.
- * @param sock The SOCKS5 proxy socket.
- *
- * @returns Whether or not the operation succeeded.
- *
- * @note The specified SOCKS5 proxy socket must already be connected to the
- * SOCKS5 proxy.
- *
- * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
- * Version 5</a>
- */
bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, const Sock& sock)
{
IntrRecvError recvr;
@@ -606,18 +537,6 @@ static void LogConnectFailure(bool manual_connection, const char* fmt, const Arg
}
}
-/**
- * Try to connect to the specified service on the specified socket.
- *
- * @param addrConnect The service to which to connect.
- * @param hSocket The socket on which to connect.
- * @param nTimeout Wait this many milliseconds for the connection to be
- * established.
- * @param manual_connection Whether or not the connection was manually requested
- * (e.g. through the addnode RPC)
- *
- * @returns Whether or not a connection was successfully made.
- */
bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
{
// Create a sockaddr from the specified service.
@@ -716,22 +635,6 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
return true;
}
-/**
- * Set the name proxy to use for all connections to nodes specified by a
- * hostname. After setting this proxy, connecting to a node specified by a
- * hostname won't result in a local lookup of said hostname, rather, connect to
- * the node by asking the name proxy for a proxy connection to the hostname,
- * effectively delegating the hostname lookup to the specified proxy.
- *
- * This delegation increases privacy for those who set the name proxy as they no
- * longer leak their external hostname queries to their DNS servers.
- *
- * @returns Whether or not the operation succeeded.
- *
- * @note SOCKS5's support for UDP-over-SOCKS5 has been considered, but no SOCK5
- * server in common use (most notably Tor) actually implements UDP
- * support, and a DNS resolver is beyond the scope of this project.
- */
bool SetNameProxy(const proxyType &addrProxy) {
if (!addrProxy.IsValid())
return false;
@@ -762,21 +665,6 @@ bool IsProxy(const CNetAddr &addr) {
return false;
}
-/**
- * Connect to a specified destination service through a SOCKS5 proxy by first
- * connecting to the SOCKS5 proxy.
- *
- * @param proxy The SOCKS5 proxy.
- * @param strDest The destination service to which to connect.
- * @param port The destination port.
- * @param sock The socket on which to connect to the SOCKS5 proxy.
- * @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
- * proxy to be established.
- * @param[out] outProxyConnectionFailed Whether or not the connection to the
- * SOCKS5 proxy failed.
- *
- * @returns Whether or not the operation succeeded.
- */
bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
{
// first connect to proxy server
@@ -800,18 +688,7 @@ bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int
return true;
}
-/**
- * Parse and resolve a specified subnet string into the appropriate internal
- * representation.
- *
- * @param strSubnet A string representation of a subnet of the form `network
- * address [ "/", ( CIDR-style suffix | netmask ) ]`(e.g.
- * `2001:db8::/32`, `192.0.2.0/255.255.255.0`, or `8.8.8.8`).
- * @param ret The resulting internal representation of a subnet.
- *
- * @returns Whether the operation succeeded or not.
- */
-bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
+bool LookupSubNet(const std::string& strSubnet, CSubNet& ret, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(strSubnet)) {
return false;
@@ -822,7 +699,7 @@ bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
std::string strAddress = strSubnet.substr(0, slash);
// TODO: Use LookupHost(const std::string&, CNetAddr&, bool) instead to just get
// one CNetAddr.
- if (LookupHost(strAddress, vIP, 1, false))
+ if (LookupHost(strAddress, vIP, 1, false, dns_lookup_function))
{
CNetAddr network = vIP[0];
if (slash != strSubnet.npos)
@@ -837,7 +714,7 @@ bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
else // If not a valid number, try full netmask syntax
{
// Never allow lookup for netmask
- if (LookupHost(strNetmask, vIP, 1, false)) {
+ if (LookupHost(strNetmask, vIP, 1, false, dns_lookup_function)) {
ret = CSubNet(network, vIP[0]);
return ret.IsValid();
}
diff --git a/src/netbase.h b/src/netbase.h
index 751f7eb3f0..e98a21ce1f 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -64,6 +64,11 @@ struct ProxyCredentials
std::string password;
};
+/**
+ * Wrapper for getaddrinfo(3). Do not use directly: call Lookup/LookupHost/LookupNumeric/LookupSubNet.
+ */
+std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup);
+
enum Network ParseNetwork(const std::string& net);
std::string GetNetworkName(enum Network net);
/** Return a vector of publicly routable Network names; optionally append NET_UNROUTABLE. */
@@ -71,15 +76,107 @@ std::vector<std::string> GetNetworkNames(bool append_unroutable = false);
bool SetProxy(enum Network net, const proxyType &addrProxy);
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
+/**
+ * Set the name proxy to use for all connections to nodes specified by a
+ * hostname. After setting this proxy, connecting to a node specified by a
+ * hostname won't result in a local lookup of said hostname, rather, connect to
+ * the node by asking the name proxy for a proxy connection to the hostname,
+ * effectively delegating the hostname lookup to the specified proxy.
+ *
+ * This delegation increases privacy for those who set the name proxy as they no
+ * longer leak their external hostname queries to their DNS servers.
+ *
+ * @returns Whether or not the operation succeeded.
+ *
+ * @note SOCKS5's support for UDP-over-SOCKS5 has been considered, but no SOCK5
+ * server in common use (most notably Tor) actually implements UDP
+ * support, and a DNS resolver is beyond the scope of this project.
+ */
bool SetNameProxy(const proxyType &addrProxy);
bool HaveNameProxy();
bool GetNameProxy(proxyType &nameProxyOut);
-bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup);
-bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup);
-bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup);
-bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions);
-CService LookupNumeric(const std::string& name, int portDefault = 0);
-bool LookupSubNet(const std::string& strSubnet, CSubNet& subnet);
+
+using DNSLookupFn = std::function<std::vector<CNetAddr>(const std::string&, bool)>;
+extern DNSLookupFn g_dns_lookup;
+
+/**
+ * Resolve a host string to its corresponding network addresses.
+ *
+ * @param name The string representing a host. Could be a name or a numerical
+ * IP address (IPv6 addresses in their bracketed form are
+ * allowed).
+ * @param[out] vIP The resulting network addresses to which the specified host
+ * string resolved.
+ *
+ * @returns Whether or not the specified host string successfully resolved to
+ * any resulting network addresses.
+ *
+ * @see Lookup(const std::string&, std::vector<CService>&, int, bool, unsigned int, DNSLookupFn)
+ * for additional parameter descriptions.
+ */
+bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Resolve a host string to its first corresponding network address.
+ *
+ * @see LookupHost(const std::string&, std::vector<CNetAddr>&, unsigned int, bool, DNSLookupFn)
+ * for additional parameter descriptions.
+ */
+bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Resolve a service string to its corresponding service.
+ *
+ * @param name The string representing a service. Could be a name or a
+ * numerical IP address (IPv6 addresses should be in their
+ * disambiguated bracketed form), optionally followed by a port
+ * number. (e.g. example.com:8333 or
+ * [2001:db8:85a3:8d3:1319:8a2e:370:7348]:420)
+ * @param[out] vAddr The resulting services to which the specified service string
+ * resolved.
+ * @param portDefault The default port for resulting services if not specified
+ * by the service string.
+ * @param fAllowLookup Whether or not hostname lookups are permitted. If yes,
+ * external queries may be performed.
+ * @param nMaxSolutions The maximum number of results we want, specifying 0
+ * means "as many solutions as we get."
+ *
+ * @returns Whether or not the service string successfully resolved to any
+ * resulting services.
+ */
+bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Resolve a service string to its first corresponding service.
+ *
+ * @see Lookup(const std::string&, std::vector<CService>&, int, bool, unsigned int, DNSLookupFn)
+ * for additional parameter descriptions.
+ */
+bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Resolve a service string with a numeric IP to its first corresponding
+ * service.
+ *
+ * @returns The resulting CService if the resolution was successful, [::]:0 otherwise.
+ *
+ * @see Lookup(const std::string&, std::vector<CService>&, int, bool, unsigned int, DNSLookupFn)
+ * for additional parameter descriptions.
+ */
+CService LookupNumeric(const std::string& name, int portDefault = 0, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Parse and resolve a specified subnet string into the appropriate internal
+ * representation.
+ *
+ * @param strSubnet A string representation of a subnet of the form `network
+ * address [ "/", ( CIDR-style suffix | netmask ) ]`(e.g.
+ * `2001:db8::/32`, `192.0.2.0/255.255.255.0`, or `8.8.8.8`).
+ * @param ret The resulting internal representation of a subnet.
+ *
+ * @returns Whether the operation succeeded or not.
+ */
+bool LookupSubNet(const std::string& strSubnet, CSubNet& subnet, DNSLookupFn dns_lookup_function = g_dns_lookup);
/**
* Create a TCP socket in the given address family.
@@ -93,14 +190,61 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family);
*/
extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
-bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout, bool manual_connection);
+/**
+ * Try to connect to the specified service on the specified socket.
+ *
+ * @param addrConnect The service to which to connect.
+ * @param hSocket The socket on which to connect.
+ * @param nTimeout Wait this many milliseconds for the connection to be
+ * established.
+ * @param manual_connection Whether or not the connection was manually requested
+ * (e.g. through the addnode RPC)
+ *
+ * @returns Whether or not a connection was successfully made.
+ */
+bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection);
+
+/**
+ * Connect to a specified destination service through a SOCKS5 proxy by first
+ * connecting to the SOCKS5 proxy.
+ *
+ * @param proxy The SOCKS5 proxy.
+ * @param strDest The destination service to which to connect.
+ * @param port The destination port.
+ * @param sock The socket on which to connect to the SOCKS5 proxy.
+ * @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
+ * proxy to be established.
+ * @param[out] outProxyConnectionFailed Whether or not the connection to the
+ * SOCKS5 proxy failed.
+ *
+ * @returns Whether or not the operation succeeded.
+ */
bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
+
/** Disable or enable blocking-mode for a socket */
bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking);
/** Set the TCP_NODELAY flag on a socket */
bool SetSocketNoDelay(const SOCKET& hSocket);
void InterruptSocks5(bool interrupt);
+/**
+ * Connect to a specified destination service through an already connected
+ * SOCKS5 proxy.
+ *
+ * @param strDest The destination fully-qualified domain name.
+ * @param port The destination port.
+ * @param auth The credentials with which to authenticate with the specified
+ * SOCKS5 proxy.
+ * @param sock The SOCKS5 proxy socket.
+ *
+ * @returns Whether or not the operation succeeded.
+ *
+ * @note The specified SOCKS5 proxy socket must already be connected to the
+ * SOCKS5 proxy.
+ *
+ * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
+ * Version 5</a>
+ */
bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, const Sock& socket);
#endif // BITCOIN_NETBASE_H
diff --git a/src/node/coin.cpp b/src/node/coin.cpp
index f4f86cdbe9..263dcff657 100644
--- a/src/node/coin.cpp
+++ b/src/node/coin.cpp
@@ -12,7 +12,8 @@ void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins)
{
assert(node.mempool);
LOCK2(cs_main, node.mempool->cs);
- CCoinsViewCache& chain_view = ::ChainstateActive().CoinsTip();
+ assert(std::addressof(::ChainstateActive()) == std::addressof(node.chainman->ActiveChainstate()));
+ CCoinsViewCache& chain_view = node.chainman->ActiveChainstate().CoinsTip();
CCoinsViewMemPool mempool_view(&chain_view, *node.mempool);
for (auto& coin : coins) {
if (!mempool_view.GetCoin(coin.first, coin.second)) {
diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp
index 06fcc33725..88bdba5953 100644
--- a/src/node/coinstats.cpp
+++ b/src/node/coinstats.cpp
@@ -83,7 +83,7 @@ static void ApplyStats(CCoinsStats& stats, T& hash_obj, const uint256& hash, con
//! Calculate statistics about the unspent transaction output set
template <typename T>
-static bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point)
+static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point)
{
stats = CCoinsStats();
std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
@@ -92,7 +92,8 @@ static bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const
stats.hashBlock = pcursor->GetBestBlock();
{
LOCK(cs_main);
- stats.nHeight = g_chainman.m_blockman.LookupBlockIndex(stats.hashBlock)->nHeight;
+ assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman));
+ stats.nHeight = blockman.LookupBlockIndex(stats.hashBlock)->nHeight;
}
PrepareHash(hash_obj, stats);
@@ -126,19 +127,19 @@ static bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const
return true;
}
-bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, CoinStatsHashType hash_type, const std::function<void()>& interruption_point)
+bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, CoinStatsHashType hash_type, const std::function<void()>& interruption_point)
{
switch (hash_type) {
case(CoinStatsHashType::HASH_SERIALIZED): {
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
- return GetUTXOStats(view, stats, ss, interruption_point);
+ return GetUTXOStats(view, blockman, stats, ss, interruption_point);
}
case(CoinStatsHashType::MUHASH): {
MuHash3072 muhash;
- return GetUTXOStats(view, stats, muhash, interruption_point);
+ return GetUTXOStats(view, blockman, stats, muhash, interruption_point);
}
case(CoinStatsHashType::NONE): {
- return GetUTXOStats(view, stats, nullptr, interruption_point);
+ return GetUTXOStats(view, blockman, stats, nullptr, interruption_point);
}
} // no default case, so the compiler can warn about missing cases
assert(false);
diff --git a/src/node/coinstats.h b/src/node/coinstats.h
index f02b95235f..83f228aa7e 100644
--- a/src/node/coinstats.h
+++ b/src/node/coinstats.h
@@ -8,6 +8,7 @@
#include <amount.h>
#include <uint256.h>
+#include <validation.h>
#include <cstdint>
#include <functional>
@@ -36,6 +37,6 @@ struct CCoinsStats
};
//! Calculate statistics about the unspent transaction output set
-bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const CoinStatsHashType hash_type, const std::function<void()>& interruption_point = {});
+bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, const CoinStatsHashType hash_type, const std::function<void()>& interruption_point = {});
#endif // BITCOIN_NODE_COINSTATS_H
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 62ef72ef38..9406ef07c5 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -182,18 +182,21 @@ public:
int getNumBlocks() override
{
LOCK(::cs_main);
- return ::ChainActive().Height();
+ assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain()));
+ return m_context->chainman->ActiveChain().Height();
}
uint256 getBestBlockHash() override
{
- const CBlockIndex* tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip());
+ assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain()));
+ const CBlockIndex* tip = WITH_LOCK(::cs_main, return m_context->chainman->ActiveChain().Tip());
return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash();
}
int64_t getLastBlockTime() override
{
LOCK(::cs_main);
- if (::ChainActive().Tip()) {
- return ::ChainActive().Tip()->GetBlockTime();
+ assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain()));
+ if (m_context->chainman->ActiveChain().Tip()) {
+ return m_context->chainman->ActiveChain().Tip()->GetBlockTime();
}
return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
}
@@ -202,11 +205,15 @@ public:
const CBlockIndex* tip;
{
LOCK(::cs_main);
- tip = ::ChainActive().Tip();
+ assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain()));
+ tip = m_context->chainman->ActiveChain().Tip();
}
return GuessVerificationProgress(Params().TxData(), tip);
}
- bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
+ bool isInitialBlockDownload() override {
+ assert(std::addressof(::ChainstateActive()) == std::addressof(m_context->chainman->ActiveChainstate()));
+ return m_context->chainman->ActiveChainstate().IsInitialBlockDownload();
+ }
bool getReindex() override { return ::fReindex; }
bool getImporting() override { return ::fImporting; }
void setNetworkActive(bool active) override
@@ -231,7 +238,8 @@ public:
bool getUnspentOutput(const COutPoint& output, Coin& coin) override
{
LOCK(::cs_main);
- return ::ChainstateActive().CoinsTip().GetCoin(output, coin);
+ assert(std::addressof(::ChainstateActive()) == std::addressof(m_context->chainman->ActiveChainstate()));
+ return m_context->chainman->ActiveChainstate().CoinsTip().GetCoin(output, coin);
}
WalletClient& walletClient() override
{
@@ -441,13 +449,15 @@ public:
bool checkFinalTx(const CTransaction& tx) override
{
LOCK(cs_main);
- return CheckFinalTx(::ChainActive().Tip(), tx);
+ assert(std::addressof(::ChainActive()) == std::addressof(m_node.chainman->ActiveChain()));
+ return CheckFinalTx(m_node.chainman->ActiveChain().Tip(), tx);
}
Optional<int> findLocatorFork(const CBlockLocator& locator) override
{
LOCK(cs_main);
const CChain& active = Assert(m_node.chainman)->ActiveChain();
- if (CBlockIndex* fork = g_chainman.m_blockman.FindForkInGlobalIndex(active, locator)) {
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ if (CBlockIndex* fork = m_node.chainman->m_blockman.FindForkInGlobalIndex(active, locator)) {
return fork->nHeight;
}
return nullopt;
@@ -456,7 +466,8 @@ public:
{
WAIT_LOCK(cs_main, lock);
const CChain& active = Assert(m_node.chainman)->ActiveChain();
- return FillBlock(g_chainman.m_blockman.LookupBlockIndex(hash), block, lock, active);
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ return FillBlock(m_node.chainman->m_blockman.LookupBlockIndex(hash), block, lock, active);
}
bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
{
@@ -468,7 +479,8 @@ public:
{
WAIT_LOCK(cs_main, lock);
const CChain& active = Assert(m_node.chainman)->ActiveChain();
- if (const CBlockIndex* block = g_chainman.m_blockman.LookupBlockIndex(block_hash)) {
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ if (const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) {
if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
return FillBlock(ancestor, ancestor_out, lock, active);
}
@@ -479,8 +491,10 @@ public:
{
WAIT_LOCK(cs_main, lock);
const CChain& active = Assert(m_node.chainman)->ActiveChain();
- const CBlockIndex* block = g_chainman.m_blockman.LookupBlockIndex(block_hash);
- const CBlockIndex* ancestor = g_chainman.m_blockman.LookupBlockIndex(ancestor_hash);
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash);
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ const CBlockIndex* ancestor = m_node.chainman->m_blockman.LookupBlockIndex(ancestor_hash);
if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
return FillBlock(ancestor, ancestor_out, lock, active);
}
@@ -488,8 +502,10 @@ public:
{
WAIT_LOCK(cs_main, lock);
const CChain& active = Assert(m_node.chainman)->ActiveChain();
- const CBlockIndex* block1 = g_chainman.m_blockman.LookupBlockIndex(block_hash1);
- const CBlockIndex* block2 = g_chainman.m_blockman.LookupBlockIndex(block_hash2);
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ const CBlockIndex* block1 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash1);
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ const CBlockIndex* block2 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash2);
const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
// Using & instead of && below to avoid short circuiting and leaving
// output uninitialized.
@@ -499,7 +515,8 @@ public:
double guessVerificationProgress(const uint256& block_hash) override
{
LOCK(cs_main);
- return GuessVerificationProgress(Params().TxData(), g_chainman.m_blockman.LookupBlockIndex(block_hash));
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ return GuessVerificationProgress(Params().TxData(), m_node.chainman->m_blockman.LookupBlockIndex(block_hash));
}
bool hasBlocks(const uint256& block_hash, int min_height, Optional<int> max_height) override
{
@@ -511,7 +528,8 @@ public:
// used to limit the range, and passing min_height that's too low or
// max_height that's too high will not crash or change the result.
LOCK(::cs_main);
- if (CBlockIndex* block = g_chainman.m_blockman.LookupBlockIndex(block_hash)) {
+ assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
+ if (CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) {
if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);
for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {
// Check pprev to not segfault if min_height is too low
@@ -601,7 +619,10 @@ public:
return ::fHavePruned;
}
bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
- bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
+ bool isInitialBlockDownload() override {
+ assert(std::addressof(::ChainstateActive()) == std::addressof(m_node.chainman->ActiveChainstate()));
+ return m_node.chainman->ActiveChainstate().IsInitialBlockDownload();
+ }
bool shutdownRequested() override { return ShutdownRequested(); }
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
@@ -613,7 +634,7 @@ public:
}
std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override
{
- return MakeUnique<NotificationsHandlerImpl>(std::move(notifications));
+ return std::make_unique<NotificationsHandlerImpl>(std::move(notifications));
}
void waitForNotificationsIfTipChanged(const uint256& old_tip) override
{
@@ -626,7 +647,7 @@ public:
}
std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
{
- return MakeUnique<RpcHandlerImpl>(command);
+ return std::make_unique<RpcHandlerImpl>(command);
}
bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); }
void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) override
@@ -669,6 +690,6 @@ public:
} // namespace node
namespace interfaces {
-std::unique_ptr<Node> MakeNode(NodeContext* context) { return MakeUnique<node::NodeImpl>(context); }
-std::unique_ptr<Chain> MakeChain(NodeContext& context) { return MakeUnique<node::ChainImpl>(context); }
+std::unique_ptr<Node> MakeNode(NodeContext* context) { return std::make_unique<node::NodeImpl>(context); }
+std::unique_ptr<Chain> MakeChain(NodeContext& context) { return std::make_unique<node::ChainImpl>(context); }
} // namespace interfaces
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 3b3fab7b6b..97763f4fa2 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -39,9 +39,10 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
{ // cs_main scope
LOCK(cs_main);
+ assert(std::addressof(::ChainstateActive()) == std::addressof(node.chainman->ActiveChainstate()));
// If the transaction is already confirmed in the chain, don't do anything
// and return early.
- CCoinsViewCache &view = ::ChainstateActive().CoinsTip();
+ CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
for (size_t o = 0; o < tx->vout.size(); o++) {
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
// IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
@@ -53,7 +54,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
if (max_tx_fee > 0) {
// First, call ATMP with test_accept and check the fee. If ATMP
// fails here, return error immediately.
- const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), *node.mempool, tx, false /* bypass_limits */,
+ const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
true /* test_accept */);
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
return HandleATMPError(result.m_state, err_string);
@@ -62,7 +63,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
}
}
// Try to submit the transaction to the mempool.
- const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), *node.mempool, tx, false /* bypass_limits */,
+ const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
false /* test_accept */);
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
return HandleATMPError(result.m_state, err_string);
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index ab6168a541..9927e925ac 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -295,7 +295,7 @@ void AddressBookPage::on_exportButton_clicked()
// CSV is currently the only supported format
QString filename = GUIUtil::getSaveFileName(this,
tr("Export Address List"), QString(),
- tr("Comma separated file (*.csv)"), nullptr);
+ tr("Comma separated file", "Name of CSV file format") + QLatin1String(" (*.csv)"), nullptr);
if (filename.isNull())
return;
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index ef2f56c2c0..791a29f7a0 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -52,7 +52,6 @@
#include <QThread>
#include <QTimer>
#include <QTranslator>
-#include <QtGlobal>
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
@@ -62,6 +61,7 @@ Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#elif defined(QT_QPA_PLATFORM_COCOA)
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
+Q_IMPORT_PLUGIN(QMacStylePlugin);
#endif
#endif
@@ -466,13 +466,6 @@ int GuiMain(int argc, char* argv[])
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
-#if (QT_VERSION <= QT_VERSION_CHECK(5, 9, 8)) && defined(Q_OS_MACOS)
- const auto os_name = QSysInfo::prettyProductName();
- if (os_name.startsWith("macOS 11") || os_name.startsWith("macOS 10.16")) {
- QApplication::setStyle("fusion");
- }
-#endif
-
BitcoinApplication app;
QFontDatabase::addApplicationFont(":/fonts/monospace");
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 89d6deb70d..32890ed0fe 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -683,13 +683,13 @@ QString formatDurationStr(int secs)
int seconds = secs % 60;
if (days)
- strList.append(QString(QObject::tr("%1 d")).arg(days));
+ strList.append(QObject::tr("%1 d").arg(days));
if (hours)
- strList.append(QString(QObject::tr("%1 h")).arg(hours));
+ strList.append(QObject::tr("%1 h").arg(hours));
if (mins)
- strList.append(QString(QObject::tr("%1 m")).arg(mins));
+ strList.append(QObject::tr("%1 m").arg(mins));
if (seconds || (!days && !hours && !mins))
- strList.append(QString(QObject::tr("%1 s")).arg(seconds));
+ strList.append(QObject::tr("%1 s").arg(seconds));
return strList.join(" ");
}
@@ -712,12 +712,12 @@ QString formatPingTime(std::chrono::microseconds ping_time)
{
return (ping_time == std::chrono::microseconds::max() || ping_time == 0us) ?
QObject::tr("N/A") :
- QString(QObject::tr("%1 ms")).arg(QString::number((int)(count_microseconds(ping_time) / 1000), 10));
+ QObject::tr("%1 ms").arg(QString::number((int)(count_microseconds(ping_time) / 1000), 10));
}
QString formatTimeOffset(int64_t nTimeOffset)
{
- return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10));
+ return QObject::tr("%1 s").arg(QString::number((int)nTimeOffset, 10));
}
QString formatNiceTimeOffset(qint64 secs)
@@ -760,13 +760,13 @@ QString formatNiceTimeOffset(qint64 secs)
QString formatBytes(uint64_t bytes)
{
if(bytes < 1024)
- return QString(QObject::tr("%1 B")).arg(bytes);
+ return QObject::tr("%1 B").arg(bytes);
if(bytes < 1024 * 1024)
- return QString(QObject::tr("%1 KB")).arg(bytes / 1024);
+ return QObject::tr("%1 KB").arg(bytes / 1024);
if(bytes < 1024 * 1024 * 1024)
- return QString(QObject::tr("%1 MB")).arg(bytes / 1024 / 1024);
+ return QObject::tr("%1 MB").arg(bytes / 1024 / 1024);
- return QString(QObject::tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
+ return QObject::tr("%1 GB").arg(bytes / 1024 / 1024 / 1024);
}
qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal minPointSize, qreal font_size) {
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index 55ab6046cf..17746b395b 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -141,11 +141,11 @@ void PSBTOperationsDialog::saveTransaction() {
filename_suggestion.append(".psbt");
QString filename = GUIUtil::getSaveFileName(this,
tr("Save Transaction Data"), filename_suggestion,
- tr("Partially Signed Transaction (Binary) (*.psbt)"), &selected_filter);
+ tr("Partially Signed Transaction (Binary)", "Name of binary PSBT file format") + QLatin1String(" (*.psbt)"), &selected_filter);
if (filename.isEmpty()) {
return;
}
- std::ofstream out(filename.toLocal8Bit().data());
+ std::ofstream out(filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary);
out << ssTx.str();
out.close();
showStatus(tr("PSBT saved to disk."), StatusLevel::INFO);
diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp
index 490826cbbb..a71c8831e9 100644
--- a/src/qt/qrimagewidget.cpp
+++ b/src/qt/qrimagewidget.cpp
@@ -120,7 +120,9 @@ void QRImageWidget::saveImage()
{
if (!GUIUtil::HasPixmap(this))
return;
- QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), nullptr);
+ QString fn = GUIUtil::getSaveFileName(
+ this, tr("Save QR Code"), QString(),
+ tr("PNG Image", "Name of PNG file format") + QLatin1String(" (*.png)"), nullptr);
if (!fn.isEmpty())
{
exportImage().save(fn);
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 0da12c84fd..61cb89d75a 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -81,7 +81,6 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWid
tableView->horizontalHeader()->setMinimumSectionSize(MINIMUM_COLUMN_WIDTH);
tableView->horizontalHeader()->setStretchLastSection(true);
}
- tableView->horizontalHeader()->setSortIndicator(RecentRequestsTableModel::Date, Qt::DescendingOrder);
}
void ReceiveCoinsDialog::setModel(WalletModel *_model)
@@ -96,6 +95,8 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
QTableView* tableView = ui->recentRequestsView;
tableView->setModel(_model->getRecentRequestsTableModel());
+ tableView->sortByColumn(RecentRequestsTableModel::Date, Qt::DescendingOrder);
+
connect(tableView->selectionModel(),
&QItemSelectionModel::selectionChanged, this,
&ReceiveCoinsDialog::recentRequestsView_selectionChanged);
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 611f3584c3..95e1ce2210 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -266,7 +266,7 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
}
// prepare transaction for getting txFee earlier
- m_current_transaction = MakeUnique<WalletModelTransaction>(recipients);
+ m_current_transaction = std::make_unique<WalletModelTransaction>(recipients);
WalletModel::SendCoinsReturn prepareStatus;
updateCoinControlState(*m_coin_control);
@@ -430,11 +430,11 @@ void SendCoinsDialog::on_sendButton_clicked()
fileNameSuggestion.append(".psbt");
QString filename = GUIUtil::getSaveFileName(this,
tr("Save Transaction Data"), fileNameSuggestion,
- tr("Partially Signed Transaction (Binary) (*.psbt)"), &selectedFilter);
+ tr("Partially Signed Transaction (Binary)", "Name of binary PSBT file format") + QLatin1String(" (*.psbt)"), &selectedFilter);
if (filename.isEmpty()) {
return;
}
- std::ofstream out(filename.toLocal8Bit().data());
+ std::ofstream out(filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary);
out << ssTx.str();
out.close();
Q_EMIT message(tr("PSBT saved"), "PSBT saved to disk", CClientUIInterface::MSG_INFORMATION);
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index e1ec7b6ed0..42e08c6af7 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -160,7 +160,6 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
transactionView->horizontalHeader()->setMinimumSectionSize(MINIMUM_COLUMN_WIDTH);
transactionView->horizontalHeader()->setStretchLastSection(true);
}
- transactionView->horizontalHeader()->setSortIndicator(TransactionTableModel::Date, Qt::DescendingOrder);
// Actions
abandonAction = new QAction(tr("Abandon transaction"), this);
@@ -236,6 +235,7 @@ void TransactionView::setModel(WalletModel *_model)
transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
transactionProxyModel->setSortRole(Qt::EditRole);
transactionView->setModel(transactionProxyModel);
+ transactionView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder);
if (_model->getOptionsModel())
{
@@ -357,7 +357,7 @@ void TransactionView::exportClicked()
// CSV is currently the only supported format
QString filename = GUIUtil::getSaveFileName(this,
tr("Export Transaction History"), QString(),
- tr("Comma separated file (*.csv)"), nullptr);
+ tr("Comma separated file", "Name of CSV file format") + QLatin1String(" (*.csv)"), nullptr);
if (filename.isNull())
return;
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index b1e6b43e60..8612893683 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -273,7 +273,7 @@ void WalletView::backupWallet()
{
QString filename = GUIUtil::getSaveFileName(this,
tr("Backup Wallet"), QString(),
- tr("Wallet Data (*.dat)"), nullptr);
+ tr("Wallet Data", "Name of wallet data file format") + QLatin1String(" (*.dat)"), nullptr);
if (filename.isEmpty())
return;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index ab0c0b8385..b90dc9bf42 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1073,9 +1073,9 @@ static RPCHelpMan gettxoutsetinfo()
const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
- CCoinsView* coins_view = WITH_LOCK(cs_main, return &ChainstateActive().CoinsDB());
+ CCoinsView* coins_view = WITH_LOCK(::cs_main, return &::ChainstateActive().CoinsDB());
NodeContext& node = EnsureNodeContext(request.context);
- if (GetUTXOStats(coins_view, stats, hash_type, node.rpc_interruption_point)) {
+ if (GetUTXOStats(coins_view, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats, hash_type, node.rpc_interruption_point)) {
ret.pushKV("height", (int64_t)stats.nHeight);
ret.pushKV("bestblock", stats.hashBlock.GetHex());
ret.pushKV("transactions", (int64_t)stats.nTransactions);
@@ -1100,30 +1100,29 @@ static RPCHelpMan gettxoutsetinfo()
static RPCHelpMan gettxout()
{
return RPCHelpMan{"gettxout",
- "\nReturns details about an unspent transaction output.\n",
- {
- {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
- {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
- {"include_mempool", RPCArg::Type::BOOL, /* default */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
- },
- RPCResult{
- RPCResult::Type::OBJ, "", "",
- {
- {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
- {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
- {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
- {RPCResult::Type::OBJ, "scriptPubKey", "",
- {
- {RPCResult::Type::STR_HEX, "asm", ""},
- {RPCResult::Type::STR_HEX, "hex", ""},
- {RPCResult::Type::NUM, "reqSigs", "Number of required signatures"},
- {RPCResult::Type::STR_HEX, "type", "The type, eg pubkeyhash"},
- {RPCResult::Type::ARR, "addresses", "array of bitcoin addresses",
- {{RPCResult::Type::STR, "address", "bitcoin address"}}},
- }},
- {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
- }},
- RPCExamples{
+ "\nReturns details about an unspent transaction output.\n",
+ {
+ {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
+ {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
+ {"include_mempool", RPCArg::Type::BOOL, /* default */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
+ },
+ {
+ RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
+ RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
+ {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
+ {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
+ {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
+ {RPCResult::Type::OBJ, "scriptPubKey", "", {
+ {RPCResult::Type::STR_HEX, "asm", ""},
+ {RPCResult::Type::STR_HEX, "hex", ""},
+ {RPCResult::Type::NUM, "reqSigs", "Number of required signatures"},
+ {RPCResult::Type::STR_HEX, "type", "The type, eg pubkeyhash"},
+ {RPCResult::Type::ARR, "addresses", "array of bitcoin addresses", {{RPCResult::Type::STR, "address", "bitcoin address"}}},
+ }},
+ {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
+ }},
+ },
+ RPCExamples{
"\nGet unspent transactions\n"
+ HelpExampleCli("listunspent", "") +
"\nView the details\n"
@@ -2137,59 +2136,63 @@ public:
static RPCHelpMan scantxoutset()
{
return RPCHelpMan{"scantxoutset",
- "\nEXPERIMENTAL warning: this call may be removed or changed in future releases.\n"
- "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
- "Examples of output descriptors are:\n"
- " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
- " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
- " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
- " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
- " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
- "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
- "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
- "unhardened or hardened child keys.\n"
- "In the latter case, a range needs to be specified by below if different from 1000.\n"
- "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
+ "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
+ "Examples of output descriptors are:\n"
+ " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
+ " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
+ " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
+ " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
+ " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
+ "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
+ "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
+ "unhardened or hardened child keys.\n"
+ "In the latter case, a range needs to be specified by below if different from 1000.\n"
+ "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
+ {
+ {"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
+ "\"start\" for starting a scan\n"
+ "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
+ "\"status\" for progress report (in %) of the current scan"},
+ {"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
+ "Every scan object is either a string descriptor or an object:",
+ {
+ {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
{
- {"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
- " \"start\" for starting a scan\n"
- " \"abort\" for aborting the current scan (returns true when abort was successful)\n"
- " \"status\" for progress report (in %) of the current scan"},
- {"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
- " Every scan object is either a string descriptor or an object:",
- {
- {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
- {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
- {
- {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
- {"range", RPCArg::Type::RANGE, /* default */ "1000", "The range of HD chain indexes to explore (either end or [begin,end])"},
- },
- },
- },
+ {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
+ {"range", RPCArg::Type::RANGE, /* default */ "1000", "The range of HD chain indexes to explore (either end or [begin,end])"},
+ }},
+ },
"[scanobjects,...]"},
- },
- RPCResult{
- RPCResult::Type::OBJ, "", "",
+ },
+ {
+ RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
+ RPCResult{"When action=='status' and no scan is in progress", RPCResult::Type::NONE, "", ""},
+ RPCResult{"When action=='status' and scan is in progress", RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::NUM, "progress", "The scan progress"},
+ }},
+ RPCResult{"When action=='start'", RPCResult::Type::OBJ, "", "", {
+ {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
+ {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
+ {RPCResult::Type::NUM, "height", "The current block height (index)"},
+ {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
+ {RPCResult::Type::ARR, "unspents", "",
+ {
+ {RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
- {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
- {RPCResult::Type::NUM, "height", "The current block height (index)"},
- {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
- {RPCResult::Type::ARR, "unspents", "",
- {
- {RPCResult::Type::OBJ, "", "",
- {
- {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
- {RPCResult::Type::NUM, "vout", "The vout value"},
- {RPCResult::Type::STR_HEX, "scriptPubKey", "The script key"},
- {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched scriptPubKey"},
- {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
- {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
- }},
- }},
- {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
+ {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
+ {RPCResult::Type::NUM, "vout", "The vout value"},
+ {RPCResult::Type::STR_HEX, "scriptPubKey", "The script key"},
+ {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched scriptPubKey"},
+ {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
+ {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
}},
- RPCExamples{""},
+ }},
+ {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
+ }},
+ },
+ RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
@@ -2444,7 +2447,7 @@ UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFil
chainstate.ForceFlushStateToDisk();
- if (!GetUTXOStats(&chainstate.CoinsDB(), stats, CoinStatsHashType::NONE, node.rpc_interruption_point)) {
+ if (!GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, stats, CoinStatsHashType::NONE, node.rpc_interruption_point)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
}
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index f29f556517..fd780ba782 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -150,7 +150,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me
UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd && !ShutdownRequested())
{
- std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(mempool, Params()).CreateNewBlock(coinbase_script));
+ std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbase_script));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;
@@ -358,7 +358,7 @@ static RPCHelpMan generateblock()
LOCK(cs_main);
CTxMemPool empty_mempool;
- std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(empty_mempool, chainparams).CreateNewBlock(coinbase_script));
+ std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(empty_mempool, chainparams).CreateNewBlock(::ChainstateActive(), coinbase_script));
if (!blocktemplate) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
}
@@ -369,7 +369,7 @@ static RPCHelpMan generateblock()
// Add transactions
block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
- RegenerateCommitments(block);
+ RegenerateCommitments(block, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)));
{
LOCK(cs_main);
@@ -505,83 +505,84 @@ static std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
static RPCHelpMan getblocktemplate()
{
return RPCHelpMan{"getblocktemplate",
- "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
- "It returns data needed to construct a block to work on.\n"
- "For full specification, see BIPs 22, 23, 9, and 145:\n"
- " https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
- " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n"
- " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
- " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
+ "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
+ "It returns data needed to construct a block to work on.\n"
+ "For full specification, see BIPs 22, 23, 9, and 145:\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
+ {
+ {"template_request", RPCArg::Type::OBJ, "{}", "Format of the template",
+ {
+ {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
+ {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
{
- {"template_request", RPCArg::Type::OBJ, "{}", "Format of the template",
- {
- {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
- {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
- {
- {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
- },
- },
- {"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings",
- {
- {"segwit", RPCArg::Type::STR, RPCArg::Optional::NO, "(literal) indicates client side segwit support"},
- {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "other client side supported softfork deployment"},
- },
- },
- },
+ {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
+ }},
+ {"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings",
+ {
+ {"segwit", RPCArg::Type::STR, RPCArg::Optional::NO, "(literal) indicates client side segwit support"},
+ {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "other client side supported softfork deployment"},
+ }},
+ },
"\"template_request\""},
- },
- RPCResult{
- RPCResult::Type::OBJ, "", "",
+ },
+ {
+ RPCResult{"If the proposal was accepted with mode=='proposal'", RPCResult::Type::NONE, "", ""},
+ RPCResult{"If the proposal was not accepted with mode=='proposal'", RPCResult::Type::STR, "", "According to BIP22"},
+ RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::NUM, "version", "The preferred block version"},
+ {RPCResult::Type::ARR, "rules", "specific block rules that are to be enforced",
+ {
+ {RPCResult::Type::STR, "", "name of a rule the client must understand to some extent; see BIP 9 for format"},
+ }},
+ {RPCResult::Type::OBJ_DYN, "vbavailable", "set of pending, supported versionbit (BIP 9) softfork deployments",
+ {
+ {RPCResult::Type::NUM, "rulename", "identifies the bit number as indicating acceptance and readiness for the named softfork rule"},
+ }},
+ {RPCResult::Type::NUM, "vbrequired", "bit mask of versionbits the server requires set in submissions"},
+ {RPCResult::Type::STR, "previousblockhash", "The hash of current highest block"},
+ {RPCResult::Type::ARR, "transactions", "contents of non-coinbase transactions that should be included in the next block",
+ {
+ {RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::NUM, "version", "The preferred block version"},
- {RPCResult::Type::ARR, "rules", "specific block rules that are to be enforced",
- {
- {RPCResult::Type::STR, "", "name of a rule the client must understand to some extent; see BIP 9 for format"},
- }},
- {RPCResult::Type::OBJ_DYN, "vbavailable", "set of pending, supported versionbit (BIP 9) softfork deployments",
- {
- {RPCResult::Type::NUM, "rulename", "identifies the bit number as indicating acceptance and readiness for the named softfork rule"},
- }},
- {RPCResult::Type::NUM, "vbrequired", "bit mask of versionbits the server requires set in submissions"},
- {RPCResult::Type::STR, "previousblockhash", "The hash of current highest block"},
- {RPCResult::Type::ARR, "transactions", "contents of non-coinbase transactions that should be included in the next block",
- {
- {RPCResult::Type::OBJ, "", "",
- {
- {RPCResult::Type::STR_HEX, "data", "transaction data encoded in hexadecimal (byte-for-byte)"},
- {RPCResult::Type::STR_HEX, "txid", "transaction id encoded in little-endian hexadecimal"},
- {RPCResult::Type::STR_HEX, "hash", "hash encoded in little-endian hexadecimal (including witness data)"},
- {RPCResult::Type::ARR, "depends", "array of numbers",
- {
- {RPCResult::Type::NUM, "", "transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is"},
- }},
- {RPCResult::Type::NUM, "fee", "difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one"},
- {RPCResult::Type::NUM, "sigops", "total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero"},
- {RPCResult::Type::NUM, "weight", "total transaction weight, as counted for purposes of block limits"},
- }},
- }},
- {RPCResult::Type::OBJ_DYN, "coinbaseaux", "data that should be included in the coinbase's scriptSig content",
+ {RPCResult::Type::STR_HEX, "data", "transaction data encoded in hexadecimal (byte-for-byte)"},
+ {RPCResult::Type::STR_HEX, "txid", "transaction id encoded in little-endian hexadecimal"},
+ {RPCResult::Type::STR_HEX, "hash", "hash encoded in little-endian hexadecimal (including witness data)"},
+ {RPCResult::Type::ARR, "depends", "array of numbers",
{
- {RPCResult::Type::STR_HEX, "key", "values must be in the coinbase (keys may be ignored)"},
+ {RPCResult::Type::NUM, "", "transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is"},
}},
- {RPCResult::Type::NUM, "coinbasevalue", "maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)"},
- {RPCResult::Type::STR, "longpollid", "an id to include with a request to longpoll on an update to this template"},
- {RPCResult::Type::STR, "target", "The hash target"},
- {RPCResult::Type::NUM_TIME, "mintime", "The minimum timestamp appropriate for the next block time, expressed in " + UNIX_EPOCH_TIME},
- {RPCResult::Type::ARR, "mutable", "list of ways the block template may be changed",
- {
- {RPCResult::Type::STR, "value", "A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'"},
- }},
- {RPCResult::Type::STR_HEX, "noncerange", "A range of valid nonces"},
- {RPCResult::Type::NUM, "sigoplimit", "limit of sigops in blocks"},
- {RPCResult::Type::NUM, "sizelimit", "limit of block size"},
- {RPCResult::Type::NUM, "weightlimit", "limit of block weight"},
- {RPCResult::Type::NUM_TIME, "curtime", "current timestamp in " + UNIX_EPOCH_TIME},
- {RPCResult::Type::STR, "bits", "compressed target of next block"},
- {RPCResult::Type::NUM, "height", "The height of the next block"},
- {RPCResult::Type::STR, "default_witness_commitment", /* optional */ true, "a valid witness commitment for the unmodified block template"}
+ {RPCResult::Type::NUM, "fee", "difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one"},
+ {RPCResult::Type::NUM, "sigops", "total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero"},
+ {RPCResult::Type::NUM, "weight", "total transaction weight, as counted for purposes of block limits"},
}},
- RPCExamples{
+ }},
+ {RPCResult::Type::OBJ_DYN, "coinbaseaux", "data that should be included in the coinbase's scriptSig content",
+ {
+ {RPCResult::Type::STR_HEX, "key", "values must be in the coinbase (keys may be ignored)"},
+ }},
+ {RPCResult::Type::NUM, "coinbasevalue", "maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)"},
+ {RPCResult::Type::STR, "longpollid", "an id to include with a request to longpoll on an update to this template"},
+ {RPCResult::Type::STR, "target", "The hash target"},
+ {RPCResult::Type::NUM_TIME, "mintime", "The minimum timestamp appropriate for the next block time, expressed in " + UNIX_EPOCH_TIME},
+ {RPCResult::Type::ARR, "mutable", "list of ways the block template may be changed",
+ {
+ {RPCResult::Type::STR, "value", "A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'"},
+ }},
+ {RPCResult::Type::STR_HEX, "noncerange", "A range of valid nonces"},
+ {RPCResult::Type::NUM, "sigoplimit", "limit of sigops in blocks"},
+ {RPCResult::Type::NUM, "sizelimit", "limit of block size"},
+ {RPCResult::Type::NUM, "weightlimit", "limit of block weight"},
+ {RPCResult::Type::NUM_TIME, "curtime", "current timestamp in " + UNIX_EPOCH_TIME},
+ {RPCResult::Type::STR, "bits", "compressed target of next block"},
+ {RPCResult::Type::NUM, "height", "The height of the next block"},
+ {RPCResult::Type::STR, "default_witness_commitment", /* optional */ true, "a valid witness commitment for the unmodified block template"},
+ }},
+ },
+ RPCExamples{
HelpExampleCli("getblocktemplate", "'{\"rules\": [\"segwit\"]}'")
+ HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}")
},
@@ -747,7 +748,7 @@ static RPCHelpMan getblocktemplate()
// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
- pblocktemplate = BlockAssembler(mempool, Params()).CreateNewBlock(scriptDummy);
+ pblocktemplate = BlockAssembler(mempool, Params()).CreateNewBlock(::ChainstateActive(), scriptDummy);
if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
@@ -940,14 +941,17 @@ static RPCHelpMan submitblock()
{
// We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
return RPCHelpMan{"submitblock",
- "\nAttempts to submit new block to network.\n"
- "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
- {
- {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block data to submit"},
- {"dummy", RPCArg::Type::STR, /* default */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."},
- },
- RPCResult{RPCResult::Type::NONE, "", "Returns JSON Null when valid, a string according to BIP22 otherwise"},
- RPCExamples{
+ "\nAttempts to submit new block to network.\n"
+ "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
+ {
+ {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block data to submit"},
+ {"dummy", RPCArg::Type::STR, /* default */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."},
+ },
+ {
+ RPCResult{"If the block was accepted", RPCResult::Type::NONE, "", ""},
+ RPCResult{"Otherwise", RPCResult::Type::STR, "", "According to BIP22"},
+ },
+ RPCExamples{
HelpExampleCli("submitblock", "\"mydata\"")
+ HelpExampleRpc("submitblock", "\"mydata\"")
},
diff --git a/src/rpc/request.h b/src/rpc/request.h
index de3a4ae840..27d06f3c92 100644
--- a/src/rpc/request.h
+++ b/src/rpc/request.h
@@ -34,19 +34,19 @@ public:
UniValue id;
std::string strMethod;
UniValue params;
- bool fHelp;
+ enum Mode { EXECUTE, GET_HELP, GET_ARGS } mode = EXECUTE;
std::string URI;
std::string authUser;
std::string peerAddr;
const util::Ref& context;
- explicit JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), fHelp(false), context(context) {}
+ explicit JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), context(context) {}
//! Initializes request information from another request object and the
//! given context. The implementation should be updated if any members are
//! added or removed above.
JSONRPCRequest(const JSONRPCRequest& other, const util::Ref& context)
- : id(other.id), strMethod(other.strMethod), params(other.params), fHelp(other.fHelp), URI(other.URI),
+ : id(other.id), strMethod(other.strMethod), params(other.params), mode(other.mode), URI(other.URI),
authUser(other.authUser), peerAddr(other.peerAddr), context(context)
{
}
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 9a9b3713f3..39938f4eb9 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -88,7 +88,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
sort(vCommands.begin(), vCommands.end());
JSONRPCRequest jreq(helpreq);
- jreq.fHelp = true;
+ jreq.mode = JSONRPCRequest::GET_HELP;
jreq.params = UniValue();
for (const std::pair<std::string, const CRPCCommand*>& command : vCommands)
@@ -149,7 +149,7 @@ static RPCHelpMan help()
}
if (strCommand == "dump_all_command_conversions") {
// Used for testing only, undocumented
- return tableRPC.dumpArgMap();
+ return tableRPC.dumpArgMap(jsonRequest);
}
return tableRPC.help(strCommand, jsonRequest);
@@ -437,6 +437,16 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
return out;
}
+static bool ExecuteCommands(const std::vector<const CRPCCommand*>& commands, const JSONRPCRequest& request, UniValue& result)
+{
+ for (const auto& command : commands) {
+ if (ExecuteCommand(*command, request, result, &command == &commands.back())) {
+ return true;
+ }
+ }
+ return false;
+}
+
UniValue CRPCTable::execute(const JSONRPCRequest &request) const
{
// Return immediately if in warmup
@@ -450,10 +460,8 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
auto it = mapCommands.find(request.strMethod);
if (it != mapCommands.end()) {
UniValue result;
- for (const auto& command : it->second) {
- if (ExecuteCommand(*command, request, result, &command == &it->second.back())) {
- return result;
- }
+ if (ExecuteCommands(it->second, request, result)) {
+ return result;
}
}
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
@@ -484,13 +492,18 @@ std::vector<std::string> CRPCTable::listCommands() const
return commandList;
}
-UniValue CRPCTable::dumpArgMap() const
+UniValue CRPCTable::dumpArgMap(const JSONRPCRequest& args_request) const
{
+ JSONRPCRequest request(args_request);
+ request.mode = JSONRPCRequest::GET_ARGS;
+
UniValue ret{UniValue::VARR};
for (const auto& cmd : mapCommands) {
- for (const auto& c : cmd.second) {
- const auto help = RpcMethodFnType(c->unique_id)();
- help.AppendArgMap(ret);
+ UniValue result;
+ if (ExecuteCommands(cmd.second, request, result)) {
+ for (const auto& values : result.getValues()) {
+ ret.push_back(values);
+ }
}
}
return ret;
diff --git a/src/rpc/server.h b/src/rpc/server.h
index fe5a791e1e..03967020c2 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -148,7 +148,7 @@ public:
/**
* Return all named arguments that need to be converted by the client from string to another JSON type
*/
- UniValue dumpArgMap() const;
+ UniValue dumpArgMap(const JSONRPCRequest& request) const;
/**
* Appends a CRPCCommand to the dispatch table.
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index e890c0108a..44e58cb75f 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -459,6 +459,21 @@ std::string RPCExamples::ToDescriptionString() const
return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples;
}
+UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request)
+{
+ if (request.mode == JSONRPCRequest::GET_ARGS) {
+ return GetArgMap();
+ }
+ /*
+ * Check if the given request is valid according to this command or if
+ * the user is asking for help information, and throw help when appropriate.
+ */
+ if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(ToString());
+ }
+ return m_fun(*this, request);
+}
+
bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
{
size_t num_required_args = 0;
@@ -532,8 +547,9 @@ std::string RPCHelpMan::ToString() const
return ret;
}
-void RPCHelpMan::AppendArgMap(UniValue& arr) const
+UniValue RPCHelpMan::GetArgMap() const
{
+ UniValue arr{UniValue::VARR};
for (int i{0}; i < int(m_args.size()); ++i) {
const auto& arg = m_args.at(i);
std::vector<std::string> arg_names;
@@ -548,6 +564,7 @@ void RPCHelpMan::AppendArgMap(UniValue& arr) const
arr.push_back(map);
}
}
+ return arr;
}
std::string RPCArg::GetFirstName() const
diff --git a/src/rpc/util.h b/src/rpc/util.h
index c54ce85f60..94c2d2d626 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -333,26 +333,12 @@ public:
using RPCMethodImpl = std::function<UniValue(const RPCHelpMan&, const JSONRPCRequest&)>;
RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun);
+ UniValue HandleRequest(const JSONRPCRequest& request);
std::string ToString() const;
- /** Append the named args that need to be converted from string to another JSON type */
- void AppendArgMap(UniValue& arr) const;
- UniValue HandleRequest(const JSONRPCRequest& request)
- {
- Check(request);
- return m_fun(*this, request);
- }
+ /** Return the named args that need to be converted from string to another JSON type */
+ UniValue GetArgMap() const;
/** If the supplied number of args is neither too small nor too high */
bool IsValidNumArgs(size_t num_args) const;
- /**
- * Check if the given request is valid according to this command or if
- * the user is asking for help information, and throw help when appropriate.
- */
- inline void Check(const JSONRPCRequest& request) const {
- if (request.fHelp || !IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(ToString());
- }
- }
-
std::vector<std::string> GetArgNames() const;
const std::string m_name;
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 6ab01882ac..889cb4f06e 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -853,7 +853,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
CPubKey pubkey(data);
if (pubkey.IsFullyValid()) {
if (permit_uncompressed || pubkey.IsCompressed()) {
- return MakeUnique<ConstPubkeyProvider>(key_exp_index, pubkey);
+ return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey);
} else {
error = "Uncompressed keys are not allowed";
return nullptr;
@@ -867,7 +867,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
if (permit_uncompressed || key.IsCompressed()) {
CPubKey pubkey = key.GetPubKey();
out.keys.emplace(pubkey.GetID(), key);
- return MakeUnique<ConstPubkeyProvider>(key_exp_index, pubkey);
+ return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey);
} else {
error = "Uncompressed keys are not allowed";
return nullptr;
@@ -894,7 +894,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
extpubkey = extkey.Neuter();
out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key);
}
- return MakeUnique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type);
+ return std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type);
}
/** Parse a public key including origin information (if enabled). */
@@ -931,7 +931,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
if (!ParseKeyPath(slash_split, info.path, error)) return nullptr;
auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], permit_uncompressed, out, error);
if (!provider) return nullptr;
- return MakeUnique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider));
+ return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider));
}
/** Parse a script in a particular context. */
@@ -944,17 +944,17 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
if (Func("pk", expr)) {
auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error);
if (!pubkey) return nullptr;
- return MakeUnique<PKDescriptor>(std::move(pubkey));
+ return std::make_unique<PKDescriptor>(std::move(pubkey));
}
if (Func("pkh", expr)) {
auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error);
if (!pubkey) return nullptr;
- return MakeUnique<PKHDescriptor>(std::move(pubkey));
+ return std::make_unique<PKHDescriptor>(std::move(pubkey));
}
if (ctx == ParseScriptContext::TOP && Func("combo", expr)) {
auto pubkey = ParsePubkey(key_exp_index, expr, true, out, error);
if (!pubkey) return nullptr;
- return MakeUnique<ComboDescriptor>(std::move(pubkey));
+ return std::make_unique<ComboDescriptor>(std::move(pubkey));
} else if (ctx != ParseScriptContext::TOP && Func("combo", expr)) {
error = "Cannot have combo in non-top level";
return nullptr;
@@ -1002,12 +1002,12 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
return nullptr;
}
}
- return MakeUnique<MultisigDescriptor>(thres, std::move(providers), sorted_multi);
+ return std::make_unique<MultisigDescriptor>(thres, std::move(providers), sorted_multi);
}
if (ctx != ParseScriptContext::P2WSH && Func("wpkh", expr)) {
auto pubkey = ParsePubkey(key_exp_index, expr, false, out, error);
if (!pubkey) return nullptr;
- return MakeUnique<WPKHDescriptor>(std::move(pubkey));
+ return std::make_unique<WPKHDescriptor>(std::move(pubkey));
} else if (ctx == ParseScriptContext::P2WSH && Func("wpkh", expr)) {
error = "Cannot have wpkh within wsh";
return nullptr;
@@ -1015,7 +1015,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
if (ctx == ParseScriptContext::TOP && Func("sh", expr)) {
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error);
if (!desc || expr.size()) return nullptr;
- return MakeUnique<SHDescriptor>(std::move(desc));
+ return std::make_unique<SHDescriptor>(std::move(desc));
} else if (ctx != ParseScriptContext::TOP && Func("sh", expr)) {
error = "Cannot have sh in non-top level";
return nullptr;
@@ -1023,7 +1023,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
if (ctx != ParseScriptContext::P2WSH && Func("wsh", expr)) {
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error);
if (!desc || expr.size()) return nullptr;
- return MakeUnique<WSHDescriptor>(std::move(desc));
+ return std::make_unique<WSHDescriptor>(std::move(desc));
} else if (ctx == ParseScriptContext::P2WSH && Func("wsh", expr)) {
error = "Cannot have wsh within wsh";
return nullptr;
@@ -1034,7 +1034,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
error = "Address is not valid";
return nullptr;
}
- return MakeUnique<AddressDescriptor>(std::move(dest));
+ return std::make_unique<AddressDescriptor>(std::move(dest));
}
if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {
std::string str(expr.begin(), expr.end());
@@ -1043,7 +1043,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
return nullptr;
}
auto bytes = ParseHex(str);
- return MakeUnique<RawDescriptor>(CScript(bytes.begin(), bytes.end()));
+ return std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end()));
}
if (ctx == ParseScriptContext::P2SH) {
error = "A function is needed within P2SH";
@@ -1058,10 +1058,10 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
{
- std::unique_ptr<PubkeyProvider> key_provider = MakeUnique<ConstPubkeyProvider>(0, pubkey);
+ std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey);
KeyOriginInfo info;
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
- return MakeUnique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
+ return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
}
return key_provider;
}
@@ -1074,7 +1074,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
if (txntype == TxoutType::PUBKEY) {
CPubKey pubkey(data[0].begin(), data[0].end());
if (pubkey.IsValid()) {
- return MakeUnique<PKDescriptor>(InferPubkey(pubkey, ctx, provider));
+ return std::make_unique<PKDescriptor>(InferPubkey(pubkey, ctx, provider));
}
}
if (txntype == TxoutType::PUBKEYHASH) {
@@ -1082,7 +1082,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
CKeyID keyid(hash);
CPubKey pubkey;
if (provider.GetPubKey(keyid, pubkey)) {
- return MakeUnique<PKHDescriptor>(InferPubkey(pubkey, ctx, provider));
+ return std::make_unique<PKHDescriptor>(InferPubkey(pubkey, ctx, provider));
}
}
if (txntype == TxoutType::WITNESS_V0_KEYHASH && ctx != ParseScriptContext::P2WSH) {
@@ -1090,7 +1090,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
CKeyID keyid(hash);
CPubKey pubkey;
if (provider.GetPubKey(keyid, pubkey)) {
- return MakeUnique<WPKHDescriptor>(InferPubkey(pubkey, ctx, provider));
+ return std::make_unique<WPKHDescriptor>(InferPubkey(pubkey, ctx, provider));
}
}
if (txntype == TxoutType::MULTISIG) {
@@ -1099,7 +1099,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
CPubKey pubkey(data[i].begin(), data[i].end());
providers.push_back(InferPubkey(pubkey, ctx, provider));
}
- return MakeUnique<MultisigDescriptor>((int)data[0][0], std::move(providers));
+ return std::make_unique<MultisigDescriptor>((int)data[0][0], std::move(providers));
}
if (txntype == TxoutType::SCRIPTHASH && ctx == ParseScriptContext::TOP) {
uint160 hash(data[0]);
@@ -1107,7 +1107,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
CScript subscript;
if (provider.GetCScript(scriptid, subscript)) {
auto sub = InferScript(subscript, ParseScriptContext::P2SH, provider);
- if (sub) return MakeUnique<SHDescriptor>(std::move(sub));
+ if (sub) return std::make_unique<SHDescriptor>(std::move(sub));
}
}
if (txntype == TxoutType::WITNESS_V0_SCRIPTHASH && ctx != ParseScriptContext::P2WSH) {
@@ -1116,18 +1116,18 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
CScript subscript;
if (provider.GetCScript(scriptid, subscript)) {
auto sub = InferScript(subscript, ParseScriptContext::P2WSH, provider);
- if (sub) return MakeUnique<WSHDescriptor>(std::move(sub));
+ if (sub) return std::make_unique<WSHDescriptor>(std::move(sub));
}
}
CTxDestination dest;
if (ExtractDestination(script, dest)) {
if (GetScriptForDestination(dest) == script) {
- return MakeUnique<AddressDescriptor>(std::move(dest));
+ return std::make_unique<AddressDescriptor>(std::move(dest));
}
}
- return MakeUnique<RawDescriptor>(script);
+ return std::make_unique<RawDescriptor>(script);
}
diff --git a/src/shutdown.cpp b/src/shutdown.cpp
index 6a73e0b2d8..2fc195e2d1 100644
--- a/src/shutdown.cpp
+++ b/src/shutdown.cpp
@@ -5,16 +5,15 @@
#include <shutdown.h>
+#include <logging.h>
+#include <util/tokenpipe.h>
+
#include <config/bitcoin-config.h>
#include <assert.h>
#include <atomic>
#ifdef WIN32
#include <condition_variable>
-#else
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
#endif
static std::atomic<bool> fRequestShutdown(false);
@@ -24,25 +23,18 @@ std::mutex g_shutdown_mutex;
std::condition_variable g_shutdown_cv;
#else
/** On UNIX-like operating systems use the self-pipe trick.
- * Index 0 will be the read end of the pipe, index 1 the write end.
*/
-static int g_shutdown_pipe[2] = {-1, -1};
+static TokenPipeEnd g_shutdown_r;
+static TokenPipeEnd g_shutdown_w;
#endif
bool InitShutdownState()
{
#ifndef WIN32
-#if HAVE_O_CLOEXEC && HAVE_DECL_PIPE2
- // If we can, make sure that the file descriptors are closed on exec()
- // to prevent interference.
- if (pipe2(g_shutdown_pipe, O_CLOEXEC) != 0) {
- return false;
- }
-#else
- if (pipe(g_shutdown_pipe) != 0) {
- return false;
- }
-#endif
+ std::optional<TokenPipe> pipe = TokenPipe::Make();
+ if (!pipe) return false;
+ g_shutdown_r = pipe->TakeReadEnd();
+ g_shutdown_w = pipe->TakeWriteEnd();
#endif
return true;
}
@@ -59,17 +51,10 @@ void StartShutdown()
// case of a reentrant signal.
if (!fRequestShutdown.exchange(true)) {
// Write an arbitrary byte to the write end of the shutdown pipe.
- const char token = 'x';
- while (true) {
- int result = write(g_shutdown_pipe[1], &token, 1);
- if (result < 0) {
- // Failure. It's possible that the write was interrupted by another signal.
- // Other errors are unexpected here.
- assert(errno == EINTR);
- } else {
- assert(result == 1);
- break;
- }
+ int res = g_shutdown_w.TokenWrite('x');
+ if (res != 0) {
+ LogPrintf("Sending shutdown token failed\n");
+ assert(0);
}
}
#endif
@@ -96,17 +81,10 @@ void WaitForShutdown()
std::unique_lock<std::mutex> lk(g_shutdown_mutex);
g_shutdown_cv.wait(lk, [] { return fRequestShutdown.load(); });
#else
- char token;
- while (true) {
- int result = read(g_shutdown_pipe[0], &token, 1);
- if (result < 0) {
- // Failure. Check if the read was interrupted by a signal.
- // Other errors are unexpected here.
- assert(errno == EINTR);
- } else {
- assert(result == 1);
- break;
- }
+ int res = g_shutdown_r.TokenRead();
+ if (res != 'x') {
+ LogPrintf("Reading shutdown token failed\n");
+ assert(0);
}
#endif
}
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index d33d668a04..b523173a45 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/memory.h>
#include <util/system.h>
#include <test/util/setup_common.h>
@@ -163,7 +162,7 @@ private:
BOOST_AUTO_TEST_CASE(lockedpool_tests_mock)
{
// Test over three virtual arenas, of which one will succeed being locked
- std::unique_ptr<LockedPageAllocator> x = MakeUnique<TestLockedPageAllocator>(3, 1);
+ std::unique_ptr<LockedPageAllocator> x = std::make_unique<TestLockedPageAllocator>(3, 1);
LockedPool pool(std::move(x));
BOOST_CHECK(pool.stats().total == 0);
BOOST_CHECK(pool.stats().locked == 0);
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index 633a95ce96..04da10715f 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -62,7 +62,7 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev,
const CScript& scriptPubKey)
{
const CChainParams& chainparams = Params();
- std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(*m_node.mempool, chainparams).CreateNewBlock(scriptPubKey);
+ std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(*m_node.mempool, chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
CBlock& block = pblocktemplate->block;
block.hashPrevBlock = prev->GetBlockHash();
block.nTime = prev->nTime + 1;
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 21921375b3..64c6d7f634 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -5,7 +5,6 @@
#include <checkqueue.h>
#include <sync.h>
#include <test/util/setup_common.h>
-#include <util/memory.h>
#include <util/system.h>
#include <util/time.h>
@@ -146,7 +145,7 @@ typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue;
*/
static void Correct_Queue_range(std::vector<size_t> range)
{
- auto small_queue = MakeUnique<Correct_Queue>(QUEUE_BATCH_SIZE);
+ auto small_queue = std::make_unique<Correct_Queue>(QUEUE_BATCH_SIZE);
small_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
// Make vChecks here to save on malloc (this test can be slow...)
std::vector<FakeCheckCheckCompletion> vChecks;
@@ -206,7 +205,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random)
/** Test that failing checks are caught */
BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
{
- auto fail_queue = MakeUnique<Failing_Queue>(QUEUE_BATCH_SIZE);
+ auto fail_queue = std::make_unique<Failing_Queue>(QUEUE_BATCH_SIZE);
fail_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (size_t i = 0; i < 1001; ++i) {
@@ -234,7 +233,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
// future blocks, ie, the bad state is cleared.
BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
{
- auto fail_queue = MakeUnique<Failing_Queue>(QUEUE_BATCH_SIZE);
+ auto fail_queue = std::make_unique<Failing_Queue>(QUEUE_BATCH_SIZE);
fail_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (auto times = 0; times < 10; ++times) {
@@ -258,7 +257,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
// more than once as well
BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
{
- auto queue = MakeUnique<Unique_Queue>(QUEUE_BATCH_SIZE);
+ auto queue = std::make_unique<Unique_Queue>(QUEUE_BATCH_SIZE);
queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
size_t COUNT = 100000;
@@ -293,7 +292,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
// time could leave the data hanging across a sequence of blocks.
BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
{
- auto queue = MakeUnique<Memory_Queue>(QUEUE_BATCH_SIZE);
+ auto queue = std::make_unique<Memory_Queue>(QUEUE_BATCH_SIZE);
queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (size_t i = 0; i < 1000; ++i) {
size_t total = i;
@@ -320,7 +319,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
// have been destructed
BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
{
- auto queue = MakeUnique<FrozenCleanup_Queue>(QUEUE_BATCH_SIZE);
+ auto queue = std::make_unique<FrozenCleanup_Queue>(QUEUE_BATCH_SIZE);
bool fails = false;
queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
std::thread t0([&]() {
@@ -360,7 +359,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
/** Test that CCheckQueueControl is threadsafe */
BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
{
- auto queue = MakeUnique<Standard_Queue>(QUEUE_BATCH_SIZE);
+ auto queue = std::make_unique<Standard_Queue>(QUEUE_BATCH_SIZE);
{
std::vector<std::thread> tg;
std::atomic<int> nThreads {0};
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index 3d802cbeb3..a6080ad3dd 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -5,7 +5,6 @@
#include <dbwrapper.h>
#include <test/util/setup_common.h>
#include <uint256.h>
-#include <util/memory.h>
#include <memory>
@@ -207,7 +206,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
+ std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = InsecureRand256();
uint256 res;
@@ -248,7 +247,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
+ std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = InsecureRand256();
uint256 res;
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 5906913b58..e75982bc6f 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -15,7 +15,6 @@
#include <script/standard.h>
#include <serialize.h>
#include <txorphanage.h>
-#include <util/memory.h>
#include <util/string.h>
#include <util/system.h>
#include <util/time.h>
@@ -68,7 +67,7 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
const CChainParams& chainparams = Params();
- auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337);
auto peerLogic = PeerManager::make(chainparams, *connman, nullptr, *m_node.scheduler,
*m_node.chainman, *m_node.mempool, false);
@@ -138,7 +137,7 @@ static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerManager &pee
BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{
const CChainParams& chainparams = Params();
- auto connman = MakeUnique<CConnmanTest>(0x1337, 0x1337);
+ auto connman = std::make_unique<CConnmanTest>(0x1337, 0x1337);
auto peerLogic = PeerManager::make(chainparams, *connman, nullptr, *m_node.scheduler,
*m_node.chainman, *m_node.mempool, false);
@@ -211,8 +210,8 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
BOOST_AUTO_TEST_CASE(peer_discouragement)
{
const CChainParams& chainparams = Params();
- auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
+ auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337);
auto peerLogic = PeerManager::make(chainparams, *connman, banman.get(), *m_node.scheduler,
*m_node.chainman, *m_node.mempool, false);
@@ -258,8 +257,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
const CChainParams& chainparams = Params();
- auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
+ auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337);
auto peerLogic = PeerManager::make(chainparams, *connman, banman.get(), *m_node.scheduler,
*m_node.chainman, *m_node.mempool, false);
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index 328a31f1dc..d951bda20f 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -264,7 +264,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
CCoinsStats stats;
bool expected_code_path = false;
try {
- (void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED);
+ (void)GetUTXOStats(&coins_view_cache, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats, CoinStatsHashType::HASH_SERIALIZED);
} catch (const std::logic_error&) {
expected_code_path = true;
}
diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp
index 0d1921f285..ffe4855662 100644
--- a/src/test/fuzz/descriptor_parse.cpp
+++ b/src/test/fuzz/descriptor_parse.cpp
@@ -6,7 +6,6 @@
#include <pubkey.h>
#include <script/descriptor.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
void initialize_descriptor_parse()
{
diff --git a/src/test/fuzz/eval_script.cpp b/src/test/fuzz/eval_script.cpp
index 635288fc36..77ed798923 100644
--- a/src/test/fuzz/eval_script.cpp
+++ b/src/test/fuzz/eval_script.cpp
@@ -6,7 +6,6 @@
#include <script/interpreter.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
#include <limits>
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index aa8f826e4a..32077b1fe2 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -17,7 +17,6 @@
#include <script/standard.h>
#include <streams.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
#include <util/strencodings.h>
#include <cassert>
diff --git a/src/test/fuzz/netbase_dns_lookup.cpp b/src/test/fuzz/netbase_dns_lookup.cpp
new file mode 100644
index 0000000000..7be8b13743
--- /dev/null
+++ b/src/test/fuzz/netbase_dns_lookup.cpp
@@ -0,0 +1,71 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <netaddress.h>
+#include <netbase.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+FUZZ_TARGET(netbase_dns_lookup)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const std::string name = fuzzed_data_provider.ConsumeRandomLengthString(512);
+ const unsigned int max_results = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ const bool allow_lookup = fuzzed_data_provider.ConsumeBool();
+ const int default_port = fuzzed_data_provider.ConsumeIntegral<int>();
+
+ auto fuzzed_dns_lookup_function = [&](const std::string&, bool) {
+ std::vector<CNetAddr> resolved_addresses;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ resolved_addresses.push_back(ConsumeNetAddr(fuzzed_data_provider));
+ }
+ return resolved_addresses;
+ };
+
+ {
+ std::vector<CNetAddr> resolved_addresses;
+ if (LookupHost(name, resolved_addresses, max_results, allow_lookup, fuzzed_dns_lookup_function)) {
+ for (const CNetAddr& resolved_address : resolved_addresses) {
+ assert(!resolved_address.IsInternal());
+ }
+ }
+ assert(resolved_addresses.size() <= max_results || max_results == 0);
+ }
+ {
+ CNetAddr resolved_address;
+ if (LookupHost(name, resolved_address, allow_lookup, fuzzed_dns_lookup_function)) {
+ assert(!resolved_address.IsInternal());
+ }
+ }
+ {
+ std::vector<CService> resolved_services;
+ if (Lookup(name, resolved_services, default_port, allow_lookup, max_results, fuzzed_dns_lookup_function)) {
+ for (const CNetAddr& resolved_service : resolved_services) {
+ assert(!resolved_service.IsInternal());
+ }
+ }
+ assert(resolved_services.size() <= max_results || max_results == 0);
+ }
+ {
+ CService resolved_service;
+ if (Lookup(name, resolved_service, default_port, allow_lookup, fuzzed_dns_lookup_function)) {
+ assert(!resolved_service.IsInternal());
+ }
+ }
+ {
+ CService resolved_service = LookupNumeric(name, default_port, fuzzed_dns_lookup_function);
+ assert(!resolved_service.IsInternal());
+ }
+ {
+ CSubNet resolved_subnet;
+ if (LookupSubNet(name, resolved_subnet, fuzzed_dns_lookup_function)) {
+ assert(resolved_subnet.IsValid());
+ }
+ }
+}
diff --git a/src/test/fuzz/parse_numbers.cpp b/src/test/fuzz/parse_numbers.cpp
index ddd2bcfba3..1ad5fb6a05 100644
--- a/src/test/fuzz/parse_numbers.cpp
+++ b/src/test/fuzz/parse_numbers.cpp
@@ -18,6 +18,9 @@ FUZZ_TARGET(parse_numbers)
double d;
(void)ParseDouble(random_string, &d);
+ uint8_t u8;
+ (void)ParseUInt8(random_string, &u8);
+
int32_t i32;
(void)ParseInt32(random_string, &i32);
(void)atoi(random_string);
diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp
index afe382ba21..3fffaac8d0 100644
--- a/src/test/fuzz/parse_univalue.cpp
+++ b/src/test/fuzz/parse_univalue.cpp
@@ -7,7 +7,6 @@
#include <rpc/client.h>
#include <rpc/util.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
#include <limits>
#include <string>
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 0289d49ccc..04fc6da9b1 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -19,7 +19,6 @@
#include <test/util/setup_common.h>
#include <test/util/validation.h>
#include <txorphanage.h>
-#include <util/memory.h>
#include <validationinterface.h>
#include <version.h>
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index 617a71ea60..ee402dba38 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -14,7 +14,6 @@
#include <test/util/setup_common.h>
#include <test/util/validation.h>
#include <txorphanage.h>
-#include <util/memory.h>
#include <validation.h>
#include <validationinterface.h>
diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp
index 0b4588c4ce..eb2754054a 100644
--- a/src/test/fuzz/psbt.cpp
+++ b/src/test/fuzz/psbt.cpp
@@ -10,7 +10,6 @@
#include <pubkey.h>
#include <script/script.h>
#include <streams.h>
-#include <util/memory.h>
#include <version.h>
#include <cstdint>
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index 193862e847..8219a04e49 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -20,7 +20,6 @@
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <univalue.h>
-#include <util/memory.h>
#include <algorithm>
#include <cassert>
diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp
index ce8915ca2c..561230707c 100644
--- a/src/test/fuzz/script_flags.cpp
+++ b/src/test/fuzz/script_flags.cpp
@@ -5,7 +5,6 @@
#include <pubkey.h>
#include <script/interpreter.h>
#include <streams.h>
-#include <util/memory.h>
#include <version.h>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp
index 3e7b72805e..7b57c5dfd8 100644
--- a/src/test/fuzz/signature_checker.cpp
+++ b/src/test/fuzz/signature_checker.cpp
@@ -6,7 +6,6 @@
#include <script/interpreter.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
#include <cstdint>
#include <limits>
@@ -15,7 +14,7 @@
void initialize_signature_checker()
{
- static const auto verify_handle = MakeUnique<ECCVerifyHandle>();
+ static const auto verify_handle = std::make_unique<ECCVerifyHandle>();
}
namespace {
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index d8c536e8b1..cdddad82b3 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -259,6 +259,16 @@ void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider, const std::array<T
errno = fuzzed_data_provider.PickValueInArray(errnos);
}
+/*
+ * Sets a fuzzed errno in the range [0, 133 (EHWPOISON)]. Can be used from functions emulating
+ * standard library functions that set errno, or in other contexts where the value of errno
+ * might be relevant for the execution path that will be taken.
+ */
+inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ errno = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 133);
+}
+
/**
* Returns a byte vector of specified size regardless of the number of remaining bytes available
* from the fuzzer. Pads with zero value bytes if needed to achieve the specified size.
@@ -345,6 +355,7 @@ public:
FILE* open()
{
+ SetFuzzedErrNo(m_fuzzed_data_provider);
if (m_fuzzed_data_provider.ConsumeBool()) {
return nullptr;
}
@@ -386,6 +397,7 @@ public:
static ssize_t read(void* cookie, char* buf, size_t size)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
}
@@ -404,6 +416,7 @@ public:
static ssize_t write(void* cookie, const char* buf, size_t size)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
@@ -414,8 +427,9 @@ public:
static int seek(void* cookie, int64_t* offset, int whence)
{
- assert(whence == SEEK_SET || whence == SEEK_CUR); // SEEK_END not implemented yet.
+ assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
int64_t new_offset = 0;
if (whence == SEEK_SET) {
new_offset = *offset;
@@ -424,6 +438,12 @@ public:
return -1;
}
new_offset = fuzzed_file->m_offset + *offset;
+ } else if (whence == SEEK_END) {
+ const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096);
+ if (AdditionOverflow(n, *offset)) {
+ return -1;
+ }
+ new_offset = n + *offset;
}
if (new_offset < 0) {
return -1;
@@ -436,6 +456,7 @@ public:
static int close(void* cookie)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
}
};
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
new file mode 100644
index 0000000000..e1a21b6c53
--- /dev/null
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -0,0 +1,34 @@
+// 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.
+
+#include <chainparamsbase.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <txmempool.h>
+#include <util/time.h>
+#include <validation.h>
+
+#include <cstdint>
+#include <vector>
+
+void initialize_validation_load_mempool()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+}
+
+FUZZ_TARGET_INIT(validation_load_mempool, initialize_validation_load_mempool)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
+
+ CTxMemPool pool{};
+ auto fuzzed_fopen = [&](const fs::path&, const char*) {
+ return fuzzed_file_provider.open();
+ };
+ (void)LoadMempool(pool, ::ChainstateActive(), fuzzed_fopen);
+ (void)DumpMempool(pool, fuzzed_fopen, true);
+}
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index aa628371e6..9acd17c463 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -122,7 +122,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
uint256 hashHighFeeTx = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx);
@@ -143,7 +143,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
uint256 hashLowFeeTx = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
// Verify that the free tx and the low fee tx didn't get selected
for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx);
@@ -157,7 +157,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
hashLowFeeTx = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(feeToUse+2).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);
@@ -179,7 +179,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
uint256 hashLowFeeTx2 = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
// Verify that this tx isn't selected.
for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
@@ -192,7 +192,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vin[0].prevout.n = 1;
tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee
m_node.mempool->addUnchecked(entry.Fee(10000).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U);
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
}
@@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
fCheckpointsEnabled = false;
// Simple block creation, nothing special yet:
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
// We can't make transactions until we have inputs
// Therefore, load 110 blocks :)
@@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
LOCK(m_node.mempool->cs);
// Just to make sure we can still make simple blocks
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
const CAmount BLOCKSUBSIDY = 50*COIN;
const CAmount LOWFEE = CENT;
@@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
m_node.mempool->clear();
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
@@ -291,7 +291,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
m_node.mempool->clear();
// block size > limit
@@ -311,13 +311,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
m_node.mempool->clear();
// orphan in *m_node.mempool, template creation fails
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
m_node.mempool->clear();
// child with higher feerate than parent
@@ -334,7 +334,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
m_node.mempool->clear();
// coinbase in *m_node.mempool, template creation fails
@@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// give it a fee so it'll get mined
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
// Should throw bad-cb-multiple
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
m_node.mempool->clear();
// double spend txn pair in *m_node.mempool, template creation fails
@@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
m_node.mempool->clear();
// subsidy changing
@@ -375,7 +375,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
next->BuildSkip();
::ChainActive().SetTip(next);
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
// Extend to a 210000-long block chain.
while (::ChainActive().Tip()->nHeight < 210000) {
CBlockIndex* prev = ::ChainActive().Tip();
@@ -387,7 +387,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
next->BuildSkip();
::ChainActive().SetTip(next);
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
// invalid p2sh txn in *m_node.mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
@@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
// Should throw block-validation-failed
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
m_node.mempool->clear();
// Delete the dummy blocks again.
@@ -492,7 +492,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
// None of the of the absolute height/time locked tx should have made
// it into the template because we still check IsFinalTx in CreateNewBlock,
@@ -505,7 +505,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
::ChainActive().Tip()->nHeight++;
SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1);
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
::ChainActive().Tip()->nHeight--;
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index a29c6a2665..167242a971 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -14,7 +14,6 @@
#include <span.h>
#include <streams.h>
#include <test/util/setup_common.h>
-#include <util/memory.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/system.h>
@@ -188,7 +187,7 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
std::string pszDest;
- std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(
+ std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>(
id++, NODE_NETWORK, hSocket, addr,
/* nKeyedNetGroupIn = */ 0,
/* nLocalHostNonceIn = */ 0,
@@ -203,7 +202,7 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK(pnode1->m_inbound_onion == false);
BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
- std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(
+ std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>(
id++, NODE_NETWORK, hSocket, addr,
/* nKeyedNetGroupIn = */ 1,
/* nLocalHostNonceIn = */ 1,
@@ -218,7 +217,7 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK(pnode2->m_inbound_onion == false);
BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
- std::unique_ptr<CNode> pnode3 = MakeUnique<CNode>(
+ std::unique_ptr<CNode> pnode3 = std::make_unique<CNode>(
id++, NODE_NETWORK, hSocket, addr,
/* nKeyedNetGroupIn = */ 0,
/* nLocalHostNonceIn = */ 0,
@@ -233,7 +232,7 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK(pnode3->m_inbound_onion == false);
BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
- std::unique_ptr<CNode> pnode4 = MakeUnique<CNode>(
+ std::unique_ptr<CNode> pnode4 = std::make_unique<CNode>(
id++, NODE_NETWORK, hSocket, addr,
/* nKeyedNetGroupIn = */ 1,
/* nLocalHostNonceIn = */ 1,
@@ -711,7 +710,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
in_addr ipv4AddrPeer;
ipv4AddrPeer.s_addr = 0xa0b0c001;
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
- std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, INVALID_SOCKET, addr, /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0, CAddress{}, /* pszDest */ std::string{}, ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false);
+ std::unique_ptr<CNode> pnode = std::make_unique<CNode>(0, NODE_NETWORK, INVALID_SOCKET, addr, /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0, CAddress{}, /* pszDest */ std::string{}, ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false);
pnode->fSuccessfullyConnected.store(true);
// the peer claims to be reaching us via IPv6
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 810665877d..2e0fc7e48f 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -36,7 +36,6 @@ UniValue RPCTestingSetup::CallRPC(std::string args)
JSONRPCRequest request(context);
request.strMethod = strMethod;
request.params = RPCConvertValues(strMethod, vArgs);
- request.fHelp = false;
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
try {
UniValue result = tableRPC.execute(request);
diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp
index 3e4b963fe3..496292875d 100644
--- a/src/test/sanity_tests.cpp
+++ b/src/test/sanity_tests.cpp
@@ -13,7 +13,6 @@ BOOST_FIXTURE_TEST_SUITE(sanity_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(basic_sanity)
{
- BOOST_CHECK_MESSAGE(glibc_sanity_test() == true, "libc sanity test");
BOOST_CHECK_MESSAGE(glibcxx_sanity_test() == true, "stdlib sanity test");
BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "secp256k1 sanity test");
BOOST_CHECK_MESSAGE(ChronoSanityCheck() == true, "chrono epoch test");
diff --git a/src/test/util/logging.cpp b/src/test/util/logging.cpp
index c1dd47f06c..66f4efc139 100644
--- a/src/test/util/logging.cpp
+++ b/src/test/util/logging.cpp
@@ -7,7 +7,6 @@
#include <logging.h>
#include <noui.h>
#include <tinyformat.h>
-#include <util/memory.h>
#include <stdexcept>
diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp
index 0c6487fbfa..ba1edba0ae 100644
--- a/src/test/util/mining.cpp
+++ b/src/test/util/mining.cpp
@@ -42,7 +42,7 @@ std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coi
{
auto block = std::make_shared<CBlock>(
BlockAssembler{*Assert(node.mempool), Params()}
- .CreateNewBlock(coinbase_scriptPubKey)
+ .CreateNewBlock(::ChainstateActive(), coinbase_scriptPubKey)
->block);
LOCK(cs_main);
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 46b28190d3..f866c2a1f9 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -25,7 +25,6 @@
#include <script/sigcache.h>
#include <streams.h>
#include <txdb.h>
-#include <util/memory.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
@@ -131,7 +130,7 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
{
// We have to run a scheduler thread to prevent ActivateBestChain
// from blocking due to queue overrun.
- m_node.scheduler = MakeUnique<CScheduler>();
+ m_node.scheduler = std::make_unique<CScheduler>();
m_node.scheduler->m_service_thread = std::thread([&] { TraceThread("scheduler", [&] { m_node.scheduler->serviceQueue(); }); });
GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
@@ -188,8 +187,8 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
}
- m_node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
+ m_node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, m_node.banman.get(),
*m_node.scheduler, *m_node.chainman, *m_node.mempool,
false);
@@ -245,13 +244,13 @@ CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransa
{
const CChainParams& chainparams = Params();
CTxMemPool empty_pool;
- CBlock block = BlockAssembler(empty_pool, chainparams).CreateNewBlock(scriptPubKey)->block;
+ CBlock block = BlockAssembler(empty_pool, chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)->block;
Assert(block.vtx.size() == 1);
for (const CMutableTransaction& tx : txns) {
block.vtx.push_back(MakeTransactionRef(tx));
}
- RegenerateCommitments(block);
+ RegenerateCommitments(block, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)));
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 5a46002a79..b1b71ef7c9 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -38,6 +38,7 @@
#include <boost/test/unit_test.hpp>
using namespace std::literals;
+static const std::string STRING_WITH_EMBEDDED_NULL_CHAR{"1"s "\0" "1"s};
/* defined in logging.cpp */
namespace BCLog {
@@ -71,7 +72,7 @@ BOOST_AUTO_TEST_CASE(util_datadir)
BOOST_AUTO_TEST_CASE(util_check)
{
// Check that Assert can forward
- const std::unique_ptr<int> p_two = Assert(MakeUnique<int>(2));
+ const std::unique_ptr<int> p_two = Assert(std::make_unique<int>(2));
// Check that Assert works on lvalues and rvalues
const int two = *Assert(p_two);
Assert(two == 2);
@@ -1272,7 +1273,7 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
// Parsing strings with embedded NUL characters should fail
BOOST_CHECK(!ParseMoney("\0-1"s, ret));
- BOOST_CHECK(!ParseMoney("\0" "1"s, ret));
+ BOOST_CHECK(!ParseMoney(STRING_WITH_EMBEDDED_NULL_CHAR, ret));
BOOST_CHECK(!ParseMoney("1\0"s, ret));
}
@@ -1450,9 +1451,7 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(!ParseInt32("aap", &n));
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseInt32(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseInt32("-2147483649", nullptr));
BOOST_CHECK(!ParseInt32("2147483648", nullptr));
@@ -1480,9 +1479,7 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64)
BOOST_CHECK(!ParseInt64("1a", &n));
BOOST_CHECK(!ParseInt64("aap", &n));
BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseInt64(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseInt64("-9223372036854775809", nullptr));
BOOST_CHECK(!ParseInt64("9223372036854775808", nullptr));
@@ -1490,6 +1487,42 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64)
BOOST_CHECK(!ParseInt64("32482348723847471234", nullptr));
}
+BOOST_AUTO_TEST_CASE(test_ParseUInt8)
+{
+ uint8_t n;
+ // Valid values
+ BOOST_CHECK(ParseUInt8("255", nullptr));
+ BOOST_CHECK(ParseUInt8("0", &n) && n == 0);
+ BOOST_CHECK(ParseUInt8("255", &n) && n == 255);
+ BOOST_CHECK(ParseUInt8("0255", &n) && n == 255); // no octal
+ BOOST_CHECK(ParseUInt8("255", &n) && n == static_cast<uint8_t>(255));
+ BOOST_CHECK(ParseUInt8("+255", &n) && n == 255);
+ BOOST_CHECK(ParseUInt8("00000000000000000012", &n) && n == 12);
+ BOOST_CHECK(ParseUInt8("00000000000000000000", &n) && n == 0);
+ // Invalid values
+ BOOST_CHECK(!ParseUInt8("-00000000000000000000", &n));
+ BOOST_CHECK(!ParseUInt8("", &n));
+ BOOST_CHECK(!ParseUInt8(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseUInt8(" -1", &n));
+ BOOST_CHECK(!ParseUInt8("++1", &n));
+ BOOST_CHECK(!ParseUInt8("+-1", &n));
+ BOOST_CHECK(!ParseUInt8("-+1", &n));
+ BOOST_CHECK(!ParseUInt8("--1", &n));
+ BOOST_CHECK(!ParseUInt8("-1", &n));
+ BOOST_CHECK(!ParseUInt8("1 ", &n));
+ BOOST_CHECK(!ParseUInt8("1a", &n));
+ BOOST_CHECK(!ParseUInt8("aap", &n));
+ BOOST_CHECK(!ParseUInt8("0x1", &n)); // no hex
+ BOOST_CHECK(!ParseUInt8("0x1", &n)); // no hex
+ BOOST_CHECK(!ParseUInt8(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
+ // Overflow and underflow
+ BOOST_CHECK(!ParseUInt8("-255", &n));
+ BOOST_CHECK(!ParseUInt8("256", &n));
+ BOOST_CHECK(!ParseUInt8("-123", &n));
+ BOOST_CHECK(!ParseUInt8("-123", nullptr));
+ BOOST_CHECK(!ParseUInt8("256", nullptr));
+}
+
BOOST_AUTO_TEST_CASE(test_ParseUInt32)
{
uint32_t n;
@@ -1519,9 +1552,7 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt32)
BOOST_CHECK(!ParseUInt32("aap", &n));
BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseUInt32(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseUInt32(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseUInt32("-2147483648", &n));
BOOST_CHECK(!ParseUInt32("4294967296", &n));
@@ -1550,9 +1581,7 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt64)
BOOST_CHECK(!ParseUInt64("1a", &n));
BOOST_CHECK(!ParseUInt64("aap", &n));
BOOST_CHECK(!ParseUInt64("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseUInt64(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseUInt64(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseUInt64("-9223372036854775809", nullptr));
BOOST_CHECK(!ParseUInt64("18446744073709551616", nullptr));
@@ -1582,9 +1611,7 @@ BOOST_AUTO_TEST_CASE(test_ParseDouble)
BOOST_CHECK(!ParseDouble("1a", &n));
BOOST_CHECK(!ParseDouble("aap", &n));
BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseDouble(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseDouble("-1e10000", nullptr));
BOOST_CHECK(!ParseDouble("1e10000", nullptr));
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 0c87c4d360..f3fc83078f 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -63,7 +63,7 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash)
static int i = 0;
static uint64_t time = Params().GenesisBlock().nTime;
- auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(CScript{} << i++ << OP_TRUE);
+ auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), CScript{} << i++ << OP_TRUE);
auto pblock = std::make_shared<CBlock>(ptemplate->block);
pblock->hashPrevBlock = prev_hash;
pblock->nTime = ++time;
@@ -325,7 +325,7 @@ BOOST_AUTO_TEST_CASE(witness_commitment_index)
{
CScript pubKey;
pubKey << 1 << OP_TRUE;
- auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(pubKey);
+ auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), pubKey);
CBlock pblock = ptemplate->block;
CTxOut witness;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 4b4766e1ba..3a08e28c01 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -10,7 +10,6 @@
#include <random.h>
#include <shutdown.h>
#include <uint256.h>
-#include <util/memory.h>
#include <util/system.h>
#include <util/translation.h>
#include <util/vector.h>
@@ -41,7 +40,7 @@ struct CoinEntry {
}
CCoinsViewDB::CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe) :
- m_db(MakeUnique<CDBWrapper>(ldb_path, nCacheSize, fMemory, fWipe, true)),
+ m_db(std::make_unique<CDBWrapper>(ldb_path, nCacheSize, fMemory, fWipe, true)),
m_ldb_path(ldb_path),
m_is_memory(fMemory) { }
@@ -53,7 +52,7 @@ void CCoinsViewDB::ResizeCache(size_t new_cache_size)
// Have to do a reset first to get the original `m_db` state to release its
// filesystem lock.
m_db.reset();
- m_db = MakeUnique<CDBWrapper>(
+ m_db = std::make_unique<CDBWrapper>(
m_ldb_path, new_cache_size, m_is_memory, /*fWipe*/ false, /*obfuscate*/ true);
}
}
diff --git a/src/txrequest.cpp b/src/txrequest.cpp
index e54c073328..58424134b0 100644
--- a/src/txrequest.cpp
+++ b/src/txrequest.cpp
@@ -9,7 +9,6 @@
#include <primitives/transaction.h>
#include <random.h>
#include <uint256.h>
-#include <util/memory.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
@@ -711,7 +710,7 @@ public:
};
TxRequestTracker::TxRequestTracker(bool deterministic) :
- m_impl{MakeUnique<TxRequestTracker::Impl>(deterministic)} {}
+ m_impl{std::make_unique<TxRequestTracker::Impl>(deterministic)} {}
TxRequestTracker::~TxRequestTracker() = default;
diff --git a/src/util/memory.h b/src/util/memory.h
deleted file mode 100644
index f21b81bade..0000000000
--- a/src/util/memory.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-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.
-
-#ifndef BITCOIN_UTIL_MEMORY_H
-#define BITCOIN_UTIL_MEMORY_H
-
-#include <memory>
-#include <utility>
-
-//! Substitute for C++14 std::make_unique.
-//! DEPRECATED use std::make_unique in new code.
-template <typename T, typename... Args>
-std::unique_ptr<T> MakeUnique(Args&&... args)
-{
- return std::make_unique<T>(std::forward<Args>(args)...);
-}
-
-#endif
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 71453eed81..63b3c52ee5 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -100,7 +100,7 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
// Create empty lock file if it doesn't exist.
FILE* file = fsbridge::fopen(pathLockFile, "a");
if (file) fclose(file);
- auto lock = MakeUnique<fsbridge::FileLock>(pathLockFile);
+ auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
if (!lock->TryLock()) {
return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason());
}
diff --git a/src/util/system.h b/src/util/system.h
index de47b93b6e..30b8cb1c68 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -22,7 +22,6 @@
#include <optional.h>
#include <sync.h>
#include <tinyformat.h>
-#include <util/memory.h>
#include <util/settings.h>
#include <util/threadnames.h>
#include <util/time.h>
diff --git a/src/util/tokenpipe.cpp b/src/util/tokenpipe.cpp
new file mode 100644
index 0000000000..79465dd430
--- /dev/null
+++ b/src/util/tokenpipe.cpp
@@ -0,0 +1,108 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <util/tokenpipe.h>
+
+#include <config/bitcoin-config.h>
+
+#ifndef WIN32
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+TokenPipeEnd TokenPipe::TakeReadEnd()
+{
+ TokenPipeEnd res(m_fds[0]);
+ m_fds[0] = -1;
+ return res;
+}
+
+TokenPipeEnd TokenPipe::TakeWriteEnd()
+{
+ TokenPipeEnd res(m_fds[1]);
+ m_fds[1] = -1;
+ return res;
+}
+
+TokenPipeEnd::TokenPipeEnd(int fd) : m_fd(fd)
+{
+}
+
+TokenPipeEnd::~TokenPipeEnd()
+{
+ Close();
+}
+
+int TokenPipeEnd::TokenWrite(uint8_t token)
+{
+ while (true) {
+ ssize_t result = write(m_fd, &token, 1);
+ if (result < 0) {
+ // Failure. It's possible that the write was interrupted by a signal,
+ // in that case retry.
+ if (errno != EINTR) {
+ return TS_ERR;
+ }
+ } else if (result == 0) {
+ return TS_EOS;
+ } else { // ==1
+ return 0;
+ }
+ }
+}
+
+int TokenPipeEnd::TokenRead()
+{
+ uint8_t token;
+ while (true) {
+ ssize_t result = read(m_fd, &token, 1);
+ if (result < 0) {
+ // Failure. Check if the read was interrupted by a signal,
+ // in that case retry.
+ if (errno != EINTR) {
+ return TS_ERR;
+ }
+ } else if (result == 0) {
+ return TS_EOS;
+ } else { // ==1
+ return token;
+ }
+ }
+ return token;
+}
+
+void TokenPipeEnd::Close()
+{
+ if (m_fd != -1) close(m_fd);
+ m_fd = -1;
+}
+
+std::optional<TokenPipe> TokenPipe::Make()
+{
+ int fds[2] = {-1, -1};
+#if HAVE_O_CLOEXEC && HAVE_DECL_PIPE2
+ if (pipe2(fds, O_CLOEXEC) != 0) {
+ return std::nullopt;
+ }
+#else
+ if (pipe(fds) != 0) {
+ return std::nullopt;
+ }
+#endif
+ return TokenPipe(fds);
+}
+
+TokenPipe::~TokenPipe()
+{
+ Close();
+}
+
+void TokenPipe::Close()
+{
+ if (m_fds[0] != -1) close(m_fds[0]);
+ if (m_fds[1] != -1) close(m_fds[1]);
+ m_fds[0] = m_fds[1] = -1;
+}
+
+#endif // WIN32
diff --git a/src/util/tokenpipe.h b/src/util/tokenpipe.h
new file mode 100644
index 0000000000..f56be93a38
--- /dev/null
+++ b/src/util/tokenpipe.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_TOKENPIPE_H
+#define BITCOIN_UTIL_TOKENPIPE_H
+
+#ifndef WIN32
+
+#include <cstdint>
+#include <optional>
+
+/** One end of a token pipe. */
+class TokenPipeEnd
+{
+private:
+ int m_fd = -1;
+
+public:
+ TokenPipeEnd(int fd = -1);
+ ~TokenPipeEnd();
+
+ /** Return value constants for TokenWrite and TokenRead. */
+ enum Status {
+ TS_ERR = -1, //!< I/O error
+ TS_EOS = -2, //!< Unexpected end of stream
+ };
+
+ /** Write token to endpoint.
+ *
+ * @returns 0 If successful.
+ * <0 if error:
+ * TS_ERR If an error happened.
+ * TS_EOS If end of stream happened.
+ */
+ int TokenWrite(uint8_t token);
+
+ /** Read token from endpoint.
+ *
+ * @returns >=0 Token value, if successful.
+ * <0 if error:
+ * TS_ERR If an error happened.
+ * TS_EOS If end of stream happened.
+ */
+ int TokenRead();
+
+ /** Explicit close function.
+ */
+ void Close();
+
+ /** Return whether endpoint is open.
+ */
+ bool IsOpen() { return m_fd != -1; }
+
+ // Move-only class.
+ TokenPipeEnd(TokenPipeEnd&& other)
+ {
+ m_fd = other.m_fd;
+ other.m_fd = -1;
+ }
+ TokenPipeEnd& operator=(TokenPipeEnd&& other)
+ {
+ Close();
+ m_fd = other.m_fd;
+ other.m_fd = -1;
+ return *this;
+ }
+ TokenPipeEnd(const TokenPipeEnd&) = delete;
+ TokenPipeEnd& operator=(const TokenPipeEnd&) = delete;
+};
+
+/** An interprocess or interthread pipe for sending tokens (one-byte values)
+ * over.
+ */
+class TokenPipe
+{
+private:
+ int m_fds[2] = {-1, -1};
+
+ TokenPipe(int fds[2]) : m_fds{fds[0], fds[1]} {}
+
+public:
+ ~TokenPipe();
+
+ /** Create a new pipe.
+ * @returns The created TokenPipe, or an empty std::nullopt in case of error.
+ */
+ static std::optional<TokenPipe> Make();
+
+ /** Take the read end of this pipe. This can only be called once,
+ * as the object will be moved out.
+ */
+ TokenPipeEnd TakeReadEnd();
+
+ /** Take the write end of this pipe. This should only be called once,
+ * as the object will be moved out.
+ */
+ TokenPipeEnd TakeWriteEnd();
+
+ /** Close and end of the pipe that hasn't been moved out.
+ */
+ void Close();
+
+ // Move-only class.
+ TokenPipe(TokenPipe&& other)
+ {
+ for (int i = 0; i < 2; ++i) {
+ m_fds[i] = other.m_fds[i];
+ other.m_fds[i] = -1;
+ }
+ }
+ TokenPipe& operator=(TokenPipe&& other)
+ {
+ Close();
+ for (int i = 0; i < 2; ++i) {
+ m_fds[i] = other.m_fds[i];
+ other.m_fds[i] = -1;
+ }
+ return *this;
+ }
+ TokenPipe(const TokenPipe&) = delete;
+ TokenPipe& operator=(const TokenPipe&) = delete;
+};
+
+#endif // WIN32
+
+#endif // BITCOIN_UTIL_TOKENPIPE_H
diff --git a/src/validation.cpp b/src/validation.cpp
index e7439a2a1a..a1bd79bdfc 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1287,7 +1287,7 @@ CoinsViews::CoinsViews(
void CoinsViews::InitCache()
{
- m_cacheview = MakeUnique<CCoinsViewCache>(&m_catcherview);
+ m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview);
}
CChainState::CChainState(CTxMemPool& mempool, BlockManager& blockman, uint256 from_snapshot_blockhash)
@@ -1305,7 +1305,7 @@ void CChainState::InitCoinsDB(
leveldb_name += "_" + m_from_snapshot_blockhash.ToString();
}
- m_coins_views = MakeUnique<CoinsViews>(
+ m_coins_views = std::make_unique<CoinsViews>(
leveldb_name, cache_size_bytes, in_memory, should_wipe);
}
@@ -5010,11 +5010,11 @@ CBlockFileInfo* GetBlockFileInfo(size_t n)
static const uint64_t MEMPOOL_DUMP_VERSION = 1;
-bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate)
+bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function)
{
const CChainParams& chainparams = Params();
int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
- FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat", "rb");
+ FILE* filestr{mockable_fopen_function(GetDataDir() / "mempool.dat", "rb")};
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
@@ -5095,7 +5095,7 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate)
return true;
}
-bool DumpMempool(const CTxMemPool& pool)
+bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function, bool skip_file_commit)
{
int64_t start = GetTimeMicros();
@@ -5118,7 +5118,7 @@ bool DumpMempool(const CTxMemPool& pool)
int64_t mid = GetTimeMicros();
try {
- FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat.new", "wb");
+ FILE* filestr{mockable_fopen_function(GetDataDir() / "mempool.dat.new", "wb")};
if (!filestr) {
return false;
}
@@ -5141,7 +5141,7 @@ bool DumpMempool(const CTxMemPool& pool)
LogPrintf("Writing %d unbroadcast transactions to disk.\n", unbroadcast_txids.size());
file << unbroadcast_txids;
- if (!FileCommit(file.Get()))
+ if (!skip_file_commit && !FileCommit(file.Get()))
throw std::runtime_error("FileCommit failed");
file.fclose();
if (!RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat")) {
@@ -5279,7 +5279,7 @@ bool ChainstateManager::ActivateSnapshot(
static_cast<size_t>(current_coinsdb_cache_size * IBD_CACHE_PERC));
}
- auto snapshot_chainstate = WITH_LOCK(::cs_main, return MakeUnique<CChainState>(
+ auto snapshot_chainstate = WITH_LOCK(::cs_main, return std::make_unique<CChainState>(
this->ActiveChainstate().m_mempool, m_blockman, base_blockhash));
{
@@ -5425,7 +5425,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
// about the snapshot_chainstate.
CCoinsViewDB* snapshot_coinsdb = WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsDB());
- if (!GetUTXOStats(snapshot_coinsdb, stats, CoinStatsHashType::HASH_SERIALIZED, breakpoint_fnc)) {
+ if (!GetUTXOStats(snapshot_coinsdb, WITH_LOCK(::cs_main, return std::ref(m_blockman)), stats, CoinStatsHashType::HASH_SERIALIZED, breakpoint_fnc)) {
LogPrintf("[snapshot] failed to generate coins stats\n");
return false;
}
diff --git a/src/validation.h b/src/validation.h
index 74f8541934..ea783ddcd1 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -148,8 +148,6 @@ extern const std::vector<std::string> CHECKLEVEL_DOC;
FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false);
/** Translation to a filesystem path */
fs::path GetBlockPosFilename(const FlatFilePos &pos);
-/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
-bool LoadGenesisBlock(const CChainParams& chainparams);
/** Unload database information */
void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman);
/** Run instances of script checking worker threads */
@@ -725,6 +723,7 @@ public:
/** Replay blocks that aren't fully applied to the database. */
bool ReplayBlocks(const CChainParams& params);
bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
+ /** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
bool LoadGenesisBlock(const CChainParams& chainparams);
void PruneBlockIndexCandidates();
@@ -1014,11 +1013,13 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
/** Get block file info entry for one block file */
CBlockFileInfo* GetBlockFileInfo(size_t n);
+using FopenFn = std::function<FILE*(const fs::path&, const char*)>;
+
/** Dump the mempool to disk. */
-bool DumpMempool(const CTxMemPool& pool);
+bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function = fsbridge::fopen, bool skip_file_commit = false);
/** Load the mempool from disk. */
-bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate);
+bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function = fsbridge::fopen);
//! Check whether the block associated with this index entry is pruned or not.
inline bool IsBlockPruned(const CBlockIndex* pblockindex)
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index ad40e6da9a..1dc23374e3 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -331,7 +331,7 @@ void BerkeleyDatabase::Open()
if (m_db == nullptr) {
int ret;
- std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv.get(), 0);
+ std::unique_ptr<Db> pdb_temp = std::make_unique<Db>(env->dbenv.get(), 0);
bool fMockDb = env->IsMock();
if (fMockDb) {
@@ -462,7 +462,7 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip)
std::string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {}
BerkeleyBatch db(*this, true);
- std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0);
+ std::unique_ptr<Db> pdbCopy = std::make_unique<Db>(env->dbenv.get(), 0);
int ret = pdbCopy->open(nullptr, // Txn pointer
strFileRes.c_str(), // Filename
@@ -819,7 +819,7 @@ void BerkeleyDatabase::RemoveRef()
std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(bool flush_on_close)
{
- return MakeUnique<BerkeleyBatch>(*this, false, flush_on_close);
+ return std::make_unique<BerkeleyBatch>(*this, false, flush_on_close);
}
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
@@ -835,7 +835,7 @@ std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, con
status = DatabaseStatus::FAILED_ALREADY_LOADED;
return nullptr;
}
- db = MakeUnique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
+ db = std::make_unique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
}
if (options.verify && !db->Verify(error)) {
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 2c75486a44..b64e9fa533 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -11,7 +11,6 @@
#include <optional.h>
#include <streams.h>
#include <support/allocators/secure.h>
-#include <util/memory.h>
#include <atomic>
#include <memory>
@@ -193,7 +192,7 @@ public:
void ReloadDbEnv() override {}
std::string Filename() override { return "dummy"; }
std::string Format() override { return "dummy"; }
- std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); }
+ std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<DummyBatch>(); }
};
enum class DatabaseFormat {
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index f3e24384df..fdeead1fa5 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -70,7 +70,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
#if HAVE_SYSTEM
- argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID and %w is replaced by wallet name. %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+ argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID, %w is replaced by wallet name, %b is replaced by the hash of the block including the transaction (set to 'unconfirmed' if the transaction is not included) and %h is replaced by the block height (-1 if not included). %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
#endif
argsman.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 1fb789b128..ada586119a 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -588,10 +588,10 @@ public:
} // namespace wallet
namespace interfaces {
-std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<wallet::WalletImpl>(wallet) : nullptr; }
+std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? std::make_unique<wallet::WalletImpl>(wallet) : nullptr; }
std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args)
{
- return MakeUnique<wallet::WalletClientImpl>(chain, args);
+ return std::make_unique<wallet::WalletClientImpl>(chain, args);
}
} // namespace interfaces
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 60f76465a6..50423c3e32 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -982,14 +982,14 @@ static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CP
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string");
}
auto parsed_redeemscript = ParseHex(strRedeemScript);
- import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
+ import_data.redeemscript = std::make_unique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
}
if (witness_script_hex.size()) {
if (!IsHex(witness_script_hex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string");
}
auto parsed_witnessscript = ParseHex(witness_script_hex);
- import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
+ import_data.witnessscript = std::make_unique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
}
for (size_t i = 0; i < pubKeys.size(); ++i) {
const auto& str = pubKeys[i].get_str();
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 8b0962f9ee..1b9071a712 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -96,7 +96,7 @@ bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string&
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
- CHECK_NONFATAL(!request.fHelp);
+ CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp
index 09a9ec68cd..6d912be019 100644
--- a/src/wallet/salvage.cpp
+++ b/src/wallet/salvage.cpp
@@ -119,7 +119,7 @@ bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::v
return false;
}
- std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0);
+ std::unique_ptr<Db> pdbCopy = std::make_unique<Db>(env->dbenv.get(), 0);
int ret = pdbCopy->open(nullptr, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index efb408c163..a8200981d8 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -378,7 +378,7 @@ void LegacyScriptPubKeyMan::UpgradeKeyMetadata()
return;
}
- std::unique_ptr<WalletBatch> batch = MakeUnique<WalletBatch>(m_storage.GetDatabase());
+ std::unique_ptr<WalletBatch> batch = std::make_unique<WalletBatch>(m_storage.GetDatabase());
for (auto& meta_pair : mapKeyMetadata) {
CKeyMetadata& meta = meta_pair.second;
if (!meta.hd_seed_id.IsNull() && !meta.has_key_origin && meta.hdKeypath != "s") { // If the hdKeypath is "s", that's the seed and it doesn't have a key origin
@@ -551,7 +551,7 @@ int64_t LegacyScriptPubKeyMan::GetTimeFirstKey() const
std::unique_ptr<SigningProvider> LegacyScriptPubKeyMan::GetSolvingProvider(const CScript& script) const
{
- return MakeUnique<LegacySigningProvider>(*this);
+ return std::make_unique<LegacySigningProvider>(*this);
}
bool LegacyScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sigdata)
@@ -651,14 +651,14 @@ std::unique_ptr<CKeyMetadata> LegacyScriptPubKeyMan::GetMetadata(const CTxDestin
if (!key_id.IsNull()) {
auto it = mapKeyMetadata.find(key_id);
if (it != mapKeyMetadata.end()) {
- return MakeUnique<CKeyMetadata>(it->second);
+ return std::make_unique<CKeyMetadata>(it->second);
}
}
CScript scriptPubKey = GetScriptForDestination(dest);
auto it = m_script_metadata.find(CScriptID(scriptPubKey));
if (it != m_script_metadata.end()) {
- return MakeUnique<CKeyMetadata>(it->second);
+ return std::make_unique<CKeyMetadata>(it->second);
}
return nullptr;
@@ -2026,7 +2026,7 @@ std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvid
{
AssertLockHeld(cs_desc_man);
// Get the scripts, keys, and key origins for this script
- std::unique_ptr<FlatSigningProvider> out_keys = MakeUnique<FlatSigningProvider>();
+ std::unique_ptr<FlatSigningProvider> out_keys = std::make_unique<FlatSigningProvider>();
std::vector<CScript> scripts_temp;
if (!m_wallet_descriptor.descriptor->ExpandFromCache(index, m_wallet_descriptor.cache, scripts_temp, *out_keys)) return nullptr;
@@ -2051,7 +2051,7 @@ bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData&
bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const
{
- std::unique_ptr<FlatSigningProvider> keys = MakeUnique<FlatSigningProvider>();
+ std::unique_ptr<FlatSigningProvider> keys = std::make_unique<FlatSigningProvider>();
for (const auto& coin_pair : coins) {
std::unique_ptr<FlatSigningProvider> coin_keys = GetSigningProvider(coin_pair.second.out.scriptPubKey, true);
if (!coin_keys) {
@@ -2115,13 +2115,13 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
SignatureData sigdata;
input.FillSignatureData(sigdata);
- std::unique_ptr<FlatSigningProvider> keys = MakeUnique<FlatSigningProvider>();
+ std::unique_ptr<FlatSigningProvider> keys = std::make_unique<FlatSigningProvider>();
std::unique_ptr<FlatSigningProvider> script_keys = GetSigningProvider(script, sign);
if (script_keys) {
*keys = Merge(*keys, *script_keys);
} else {
// Maybe there are pubkeys listed that we can sign for
- script_keys = MakeUnique<FlatSigningProvider>();
+ script_keys = std::make_unique<FlatSigningProvider>();
for (const auto& pk_pair : input.hd_keypaths) {
const CPubKey& pubkey = pk_pair.first;
std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
@@ -2162,7 +2162,7 @@ std::unique_ptr<CKeyMetadata> DescriptorScriptPubKeyMan::GetMetadata(const CTxDe
CKeyID key_id = GetKeyForDestination(*provider, dest);
if (provider->GetKeyOrigin(key_id, orig)) {
LOCK(cs_desc_man);
- std::unique_ptr<CKeyMetadata> meta = MakeUnique<CKeyMetadata>();
+ std::unique_ptr<CKeyMetadata> meta = std::make_unique<CKeyMetadata>();
meta->key_origin = orig;
meta->has_key_origin = true;
meta->nCreateTime = m_wallet_descriptor.creation_time;
diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp
index 0fb3b1d3c4..975974cb6a 100644
--- a/src/wallet/sqlite.cpp
+++ b/src/wallet/sqlite.cpp
@@ -8,7 +8,6 @@
#include <crypto/common.h>
#include <logging.h>
#include <sync.h>
-#include <util/memory.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/translation.h>
@@ -330,7 +329,7 @@ void SQLiteDatabase::Close()
std::unique_ptr<DatabaseBatch> SQLiteDatabase::MakeBatch(bool flush_on_close)
{
// We ignore flush_on_close because we don't do manual flushing for SQLite
- return MakeUnique<SQLiteBatch>(*this);
+ return std::make_unique<SQLiteBatch>(*this);
}
SQLiteBatch::SQLiteBatch(SQLiteDatabase& database)
@@ -571,7 +570,7 @@ std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const D
{
try {
fs::path data_file = SQLiteDataFile(path);
- auto db = MakeUnique<SQLiteDatabase>(data_file.parent_path(), data_file);
+ auto db = std::make_unique<SQLiteDatabase>(data_file.parent_path(), data_file);
if (options.verify && !db->Verify(error)) {
status = DatabaseStatus::FAILED_VERIFY;
return nullptr;
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index ffac78d752..0e9f3819eb 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
// Make sure that can use BnB when there are preset inputs
empty_wallet();
{
- std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
bool firstRun;
wallet->LoadWallet(firstRun);
wallet->SetupLegacyScriptPubKeyMan();
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 5480f3ab22..4598999b3c 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -485,7 +485,7 @@ public:
ListCoinsTestingSetup()
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- wallet = MakeUnique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
{
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 58ab124061..ac1b2a4c0a 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -944,6 +944,14 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
if (!strCmd.empty())
{
boost::replace_all(strCmd, "%s", hash.GetHex());
+ if (confirm.status == CWalletTx::Status::CONFIRMED)
+ {
+ boost::replace_all(strCmd, "%b", confirm.hashBlock.GetHex());
+ boost::replace_all(strCmd, "%h", ToString(confirm.block_height));
+ } else {
+ boost::replace_all(strCmd, "%b", "unconfirmed");
+ boost::replace_all(strCmd, "%h", "-1");
+ }
#ifndef WIN32
// Substituting the wallet name isn't currently supported on windows
// because windows shell escaping has not been implemented yet:
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 69854cae05..a5a454f9a8 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1086,15 +1086,15 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
/** Return object for accessing dummy database with no read/write capabilities. */
std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase()
{
- return MakeUnique<DummyDatabase>();
+ return std::make_unique<DummyDatabase>();
}
/** Return object for accessing temporary in-memory database. */
std::unique_ptr<WalletDatabase> CreateMockWalletDatabase()
{
#ifdef USE_BDB
- return MakeUnique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
+ return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
#elif USE_SQLITE
- return MakeUnique<SQLiteDatabase>("", "", true);
+ return std::make_unique<SQLiteDatabase>("", "", true);
#endif
}
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index 6f0b202a18..49c1c2a07d 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -5,7 +5,6 @@
#ifndef BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
-#include <util/memory.h>
#include <memory>
#include <string>
@@ -27,7 +26,7 @@ public:
template <typename T>
static std::unique_ptr<CZMQAbstractNotifier> Create()
{
- return MakeUnique<T>();
+ return std::make_unique<T>();
}
std::string GetType() const { return type; }
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index b068ce612c..4e2de1daf4 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -17,7 +17,7 @@ from test_framework.util import (
FILE_CHAR_START = 32 if os.name == 'nt' else 1
FILE_CHAR_END = 128
FILE_CHARS_DISALLOWED = '/\\?%*:|"<>' if os.name == 'nt' else '/'
-
+UNCONFIRMED_HASH_STRING = 'unconfirmed'
def notify_outputname(walletname, txid):
return txid if os.name == 'nt' else '{}_{}'.format(walletname, txid)
@@ -43,7 +43,7 @@ class NotificationsTest(BitcoinTestFramework):
"-blocknotify=echo > {}".format(os.path.join(self.blocknotify_dir, '%s')),
], [
"-rescan",
- "-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))),
+ "-walletnotify=echo %h_%b > {}".format(os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))),
]]
self.wallet_names = [self.default_wallet_name, self.wallet]
super().setup_network()
@@ -90,11 +90,9 @@ class NotificationsTest(BitcoinTestFramework):
self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)
# directory content should equal the generated transaction hashes
- txids_rpc = list(map(lambda t: notify_outputname(self.wallet, t['txid']), self.nodes[1].listtransactions("*", block_count)))
- assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))
+ tx_details = list(map(lambda t: (t['txid'], t['blockheight'], t['blockhash']), self.nodes[1].listtransactions("*", block_count)))
self.stop_node(1)
- for tx_file in os.listdir(self.walletnotify_dir):
- os.remove(os.path.join(self.walletnotify_dir, tx_file))
+ self.expect_wallet_notify(tx_details)
self.log.info("test -walletnotify after rescan")
# restart node to rescan to force wallet notifications
@@ -104,10 +102,8 @@ class NotificationsTest(BitcoinTestFramework):
self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)
# directory content should equal the generated transaction hashes
- txids_rpc = list(map(lambda t: notify_outputname(self.wallet, t['txid']), self.nodes[1].listtransactions("*", block_count)))
- assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))
- for tx_file in os.listdir(self.walletnotify_dir):
- os.remove(os.path.join(self.walletnotify_dir, tx_file))
+ tx_details = list(map(lambda t: (t['txid'], t['blockheight'], t['blockhash']), self.nodes[1].listtransactions("*", block_count)))
+ self.expect_wallet_notify(tx_details)
# Conflicting transactions tests.
# Generate spends from node 0, and check notifications
@@ -122,7 +118,7 @@ class NotificationsTest(BitcoinTestFramework):
tx1 = self.nodes[0].sendtoaddress(address=ADDRESS_BCRT1_UNSPENDABLE, amount=1, replaceable=True)
assert_equal(tx1 in self.nodes[0].getrawmempool(), True)
self.sync_mempools()
- self.expect_wallet_notify([tx1])
+ self.expect_wallet_notify([(tx1, -1, UNCONFIRMED_HASH_STRING)])
# Generate bump transaction, sync mempools, and check for bump1
# notification. In the future, per
@@ -131,39 +127,57 @@ class NotificationsTest(BitcoinTestFramework):
bump1 = self.nodes[0].bumpfee(tx1)["txid"]
assert_equal(bump1 in self.nodes[0].getrawmempool(), True)
self.sync_mempools()
- self.expect_wallet_notify([bump1])
+ self.expect_wallet_notify([(bump1, -1, UNCONFIRMED_HASH_STRING)])
# Add bump1 transaction to new block, checking for a notification
# and the correct number of confirmations.
- self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)
+ blockhash1 = self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)[0]
+ blockheight1 = self.nodes[0].getblockcount()
self.sync_blocks()
- self.expect_wallet_notify([bump1])
+ self.expect_wallet_notify([(bump1, blockheight1, blockhash1)])
assert_equal(self.nodes[1].gettransaction(bump1)["confirmations"], 1)
# Generate a second transaction to be bumped.
tx2 = self.nodes[0].sendtoaddress(address=ADDRESS_BCRT1_UNSPENDABLE, amount=1, replaceable=True)
assert_equal(tx2 in self.nodes[0].getrawmempool(), True)
self.sync_mempools()
- self.expect_wallet_notify([tx2])
+ self.expect_wallet_notify([(tx2, -1, UNCONFIRMED_HASH_STRING)])
# Bump tx2 as bump2 and generate a block on node 0 while
# disconnected, then reconnect and check for notifications on node 1
# about newly confirmed bump2 and newly conflicted tx2.
self.disconnect_nodes(0, 1)
bump2 = self.nodes[0].bumpfee(tx2)["txid"]
- self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)
+ blockhash2 = self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)[0]
+ blockheight2 = self.nodes[0].getblockcount()
assert_equal(self.nodes[0].gettransaction(bump2)["confirmations"], 1)
assert_equal(tx2 in self.nodes[1].getrawmempool(), True)
self.connect_nodes(0, 1)
self.sync_blocks()
- self.expect_wallet_notify([bump2, tx2])
+ self.expect_wallet_notify([(bump2, blockheight2, blockhash2), (tx2, -1, UNCONFIRMED_HASH_STRING)])
assert_equal(self.nodes[1].gettransaction(bump2)["confirmations"], 1)
# TODO: add test for `-alertnotify` large fork notifications
- def expect_wallet_notify(self, tx_ids):
- self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) >= len(tx_ids), timeout=10)
- assert_equal(sorted(notify_outputname(self.wallet, tx_id) for tx_id in tx_ids), sorted(os.listdir(self.walletnotify_dir)))
+ def expect_wallet_notify(self, tx_details):
+ self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) >= len(tx_details), timeout=10)
+ # Should have no more and no less files than expected
+ assert_equal(sorted(notify_outputname(self.wallet, tx_id) for tx_id, _, _ in tx_details), sorted(os.listdir(self.walletnotify_dir)))
+ # Should now verify contents of each file
+ for tx_id, blockheight, blockhash in tx_details:
+ fname = os.path.join(self.walletnotify_dir, notify_outputname(self.wallet, tx_id))
+ with open(fname, 'rt', encoding='utf-8') as f:
+ text = f.read()
+ # Universal newline ensures '\n' on 'nt'
+ assert_equal(text[-1], '\n')
+ text = text[:-1]
+ if os.name == 'nt':
+ # On Windows, echo as above will append a whitespace
+ assert_equal(text[-1], ' ')
+ text = text[:-1]
+ expected = str(blockheight) + '_' + blockhash
+ assert_equal(text, expected)
+
for tx_file in os.listdir(self.walletnotify_dir):
os.remove(os.path.join(self.walletnotify_dir, tx_file))
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index e5c4f12f20..c0b76d960f 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -29,8 +29,9 @@ class WalletGroupTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def run_test(self):
+ self.log.info("Setting up")
# Mine some coins
- self.nodes[0].generate(110)
+ self.nodes[0].generate(101)
# Get some addresses from the two nodes
addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
@@ -48,6 +49,7 @@ class WalletGroupTest(BitcoinTestFramework):
# - node[1] should pick one 0.5 UTXO and leave the rest
# - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
# given address, and leave the rest
+ self.log.info("Test sending transactions picks one UTXO group and leaves the rest")
txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
tx1 = self.nodes[1].getrawtransaction(txid1, True)
# txid1 should have 1 input and 2 outputs
@@ -70,7 +72,7 @@ class WalletGroupTest(BitcoinTestFramework):
assert_approx(v[0], vexp=0.2, vspan=0.0001)
assert_approx(v[1], vexp=1.3, vspan=0.0001)
- # Test 'avoid partial if warranted, even if disabled'
+ self.log.info("Test avoiding partial spends if warranted, even if avoidpartialspends is disabled")
self.sync_all()
self.nodes[0].generate(1)
# Nodes 1-2 now have confirmed UTXOs (letters denote destinations):
@@ -104,7 +106,7 @@ class WalletGroupTest(BitcoinTestFramework):
assert_equal(input_addrs[0], input_addrs[1])
# Node 2 enforces avoidpartialspends so needs no checking here
- # Test wallet option maxapsfee with Node 3
+ self.log.info("Test wallet option maxapsfee")
addr_aps = self.nodes[3].getnewaddress()
self.nodes[0].sendtoaddress(addr_aps, 1.0)
self.nodes[0].sendtoaddress(addr_aps, 1.0)
@@ -131,6 +133,7 @@ class WalletGroupTest(BitcoinTestFramework):
# Test wallet option maxapsfee with node 4, which sets maxapsfee
# 1 sat higher, crossing the threshold from non-grouped to grouped.
+ self.log.info("Test wallet option maxapsfee threshold from non-grouped to grouped")
addr_aps3 = self.nodes[4].getnewaddress()
[self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
self.nodes[0].generate(1)
@@ -147,8 +150,7 @@ class WalletGroupTest(BitcoinTestFramework):
self.sync_all()
self.nodes[0].generate(1)
- # Fill node2's wallet with 10000 outputs corresponding to the same
- # scriptPubKey
+ self.log.info("Fill a wallet with 10,000 outputs corresponding to the same scriptPubKey")
for _ in range(5):
raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: 0.05}])
tx = FromHex(CTransaction(), raw_tx)
@@ -158,12 +160,12 @@ class WalletGroupTest(BitcoinTestFramework):
signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
self.nodes[0].sendrawtransaction(signed_tx['hex'])
self.nodes[0].generate(1)
-
- self.sync_all()
+ self.sync_all()
# Check that we can create a transaction that only requires ~100 of our
# utxos, without pulling in all outputs and creating a transaction that
# is way too big.
+ self.log.info("Test creating txn that only requires ~100 of our UTXOs without pulling in all outputs")
assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)