aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.fuzzbuzz.yml16
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml11
-rwxr-xr-xci/test/00_setup_env.sh3
-rw-r--r--ci/test/00_setup_env_native_multiprocess.sh14
-rw-r--r--ci/test/00_setup_env_native_tsan.sh6
-rwxr-xr-xci/test/04_install.sh2
-rwxr-xr-xci/test/06_script_b.sh2
-rw-r--r--configure.ac65
-rwxr-xr-xcontrib/devtools/security-check.py124
-rw-r--r--contrib/guix/README.md5
-rw-r--r--contrib/guix/libexec/build.sh8
-rw-r--r--depends/Makefile8
-rw-r--r--depends/README.md1
-rw-r--r--depends/config.site.in7
-rw-r--r--depends/funcs.mk11
-rw-r--r--depends/hosts/android.mk1
-rw-r--r--depends/hosts/darwin.mk1
-rw-r--r--depends/hosts/linux.mk1
-rw-r--r--depends/hosts/mingw32.mk2
-rw-r--r--depends/packages/boost.mk2
-rw-r--r--depends/packages/capnp.mk18
-rw-r--r--depends/packages/libmultiprocess.mk18
-rw-r--r--depends/packages/native_capnp.mk18
-rw-r--r--depends/packages/native_libmultiprocess.mk18
-rw-r--r--depends/packages/packages.mk3
-rw-r--r--doc/multiprocess.md35
-rw-r--r--src/Makefile.am58
-rw-r--r--src/Makefile.qt.include43
-rw-r--r--src/bench/prevector.cpp4
-rw-r--r--src/blockencodings.h3
-rw-r--r--src/bloom.h10
-rw-r--r--src/flatfile.h8
-rw-r--r--src/httprpc.cpp6
-rw-r--r--src/httpserver.cpp6
-rw-r--r--src/index/blockfilterindex.cpp16
-rw-r--r--src/index/txindex.cpp10
-rw-r--r--src/init.cpp17
-rw-r--r--src/interfaces/node.cpp8
-rw-r--r--src/interfaces/node.h5
-rw-r--r--src/interfaces/wallet.cpp3
-rw-r--r--src/interfaces/wallet.h7
-rw-r--r--src/merkleblock.cpp18
-rw-r--r--src/merkleblock.h41
-rw-r--r--src/net_processing.cpp122
-rw-r--r--src/netaddress.h24
-rw-r--r--src/node/utxo_snapshot.h11
-rw-r--r--src/policy/feerate.h7
-rw-r--r--src/primitives/block.h30
-rw-r--r--src/primitives/transaction.h25
-rw-r--r--src/protocol.h118
-rw-r--r--src/qt/bitcoin.cpp3
-rw-r--r--src/qt/bitcoingui.cpp11
-rw-r--r--src/qt/bitcoingui.h3
-rw-r--r--src/qt/clientmodel.cpp37
-rw-r--r--src/qt/clientmodel.h6
-rw-r--r--src/qt/transactiontablemodel.cpp2
-rw-r--r--src/qt/walletmodel.cpp33
-rw-r--r--src/qt/walletmodel.h6
-rw-r--r--src/qt/walletview.cpp1
-rw-r--r--src/random.cpp16
-rw-r--r--src/random.h16
-rw-r--r--src/rest.cpp9
-rw-r--r--src/rpc/blockchain.cpp2
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/mining.cpp14
-rw-r--r--src/script/keyorigin.h8
-rw-r--r--src/script/script.h7
-rw-r--r--src/serialize.h93
-rw-r--r--src/test/blockencodings_tests.cpp19
-rw-r--r--src/test/dbwrapper_tests.cpp36
-rw-r--r--src/test/fuzz/addrdb.cpp4
-rw-r--r--src/test/fuzz/asmap.cpp4
-rw-r--r--src/test/fuzz/asmap_direct.cpp6
-rw-r--r--src/test/fuzz/block.cpp5
-rw-r--r--src/test/fuzz/block_header.cpp12
-rw-r--r--src/test/fuzz/blockfilter.cpp4
-rw-r--r--src/test/fuzz/bloom_filter.cpp8
-rw-r--r--src/test/fuzz/chain.cpp4
-rw-r--r--src/test/fuzz/checkqueue.cpp1
-rw-r--r--src/test/fuzz/cuckoocache.cpp1
-rw-r--r--src/test/fuzz/fees.cpp1
-rw-r--r--src/test/fuzz/flatfile.cpp6
-rw-r--r--src/test/fuzz/golomb_rice.cpp2
-rw-r--r--src/test/fuzz/hex.cpp3
-rw-r--r--src/test/fuzz/merkleblock.cpp4
-rw-r--r--src/test/fuzz/message.cpp1
-rw-r--r--src/test/fuzz/net_permissions.cpp1
-rw-r--r--src/test/fuzz/policy_estimator.cpp6
-rw-r--r--src/test/fuzz/pow.cpp6
-rw-r--r--src/test/fuzz/prevector.cpp93
-rw-r--r--src/test/fuzz/primitives_transaction.cpp8
-rw-r--r--src/test/fuzz/protocol.cpp6
-rw-r--r--src/test/fuzz/rbf.cpp6
-rw-r--r--src/test/fuzz/rolling_bloom_filter.cpp4
-rw-r--r--src/test/fuzz/script.cpp9
-rw-r--r--src/test/fuzz/string.cpp6
-rw-r--r--src/test/fuzz/strprintf.cpp28
-rw-r--r--src/test/fuzz/util.h6
-rw-r--r--src/test/random_tests.cpp7
-rw-r--r--src/test/serialize_tests.cpp23
-rw-r--r--src/test/validation_block_tests.cpp14
-rw-r--r--src/test/validationinterface_tests.cpp34
-rw-r--r--src/txdb.cpp14
-rw-r--r--src/ui_interface.cpp4
-rw-r--r--src/ui_interface.h5
-rw-r--r--src/validation.cpp13
-rw-r--r--src/validation.h7
-rw-r--r--src/validationinterface.cpp35
-rw-r--r--src/validationinterface.h14
-rw-r--r--src/wallet/rpcwallet.cpp34
-rw-r--r--test/README.md4
-rwxr-xr-xtest/functional/example_test.py4
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py12
-rwxr-xr-xtest/functional/feature_segwit.py8
-rwxr-xr-xtest/functional/p2p_compactblocks.py15
-rwxr-xr-xtest/functional/p2p_feefilter.py4
-rwxr-xr-xtest/functional/p2p_fingerprint.py4
-rwxr-xr-xtest/functional/p2p_invalid_messages.py23
-rwxr-xr-xtest/functional/p2p_leak_tx.py4
-rwxr-xr-xtest/functional/p2p_node_network_limited.py4
-rwxr-xr-xtest/functional/p2p_segwit.py12
-rwxr-xr-xtest/functional/p2p_sendheaders.py5
-rwxr-xr-xtest/functional/p2p_tx_download.py10
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py4
-rwxr-xr-xtest/functional/rpc_users.py32
-rwxr-xr-xtest/functional/test_framework/messages.py1
-rwxr-xr-xtest/functional/test_framework/mininode.py6
-rwxr-xr-xtest/functional/test_framework/test_framework.py24
-rwxr-xr-xtest/functional/test_framework/test_node.py14
-rw-r--r--test/functional/test_framework/util.py4
131 files changed, 1126 insertions, 843 deletions
diff --git a/.fuzzbuzz.yml b/.fuzzbuzz.yml
new file mode 100644
index 0000000000..d44ac27eb9
--- /dev/null
+++ b/.fuzzbuzz.yml
@@ -0,0 +1,16 @@
+base: ubuntu:16.04
+language: c++
+engine: libFuzzer
+environment:
+ - CXXFLAGS=-fcoverage-mapping -fno-omit-frame-pointer -fprofile-instr-generate -gline-tables-only -O1
+setup:
+ - sudo apt-get update
+ - sudo apt-get install -y autoconf bsdmainutils clang git libboost-all-dev libboost-program-options-dev libc++1 libc++abi1 libc++abi-dev libc++-dev libclang1 libclang-dev libdb5.3++ libevent-dev libllvm-ocaml-dev libomp5 libomp-dev libprotobuf-dev libqt5core5a libqt5dbus5 libqt5gui5 libssl-dev libtool llvm llvm-dev llvm-runtime pkg-config protobuf-compiler qttools5-dev qttools5-dev-tools software-properties-common
+ - ./autogen.sh
+ - CC=clang CXX=clang++ ./configure --enable-fuzz --with-sanitizers=address,fuzzer,undefined
+ - make
+ - git clone https://github.com/bitcoin-core/qa-assets
+auto_targets:
+ find_targets_command: find src/test/fuzz/ -executable -type f ! -name "*.cpp" ! -name "*.h"
+ base_corpus_dir: qa-assets/fuzz_seed_corpus/
+ memory_limit: none
diff --git a/.gitignore b/.gitignore
index 1c487f43a7..5b9ec1f355 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,8 @@
src/bitcoin
src/bitcoind
src/bitcoin-cli
+src/bitcoin-gui
+src/bitcoin-node
src/bitcoin-tx
src/bitcoin-wallet
src/test/fuzz
diff --git a/.travis.yml b/.travis.yml
index fd280a91ab..1598813ed2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -112,10 +112,11 @@ jobs:
FILE_ENV="./ci/test/00_setup_env_native_qt5.sh"
- stage: test
- name: 'x86_64 Linux [GOAL: install] [xenial] [no depends, only system libs, sanitizers: thread (TSan), no wallet]'
+ name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: thread (TSan), no wallet]'
+ # Not enough memory on travis machines, so feature_block is excluded for now
env: >-
+ TEST_RUNNER_EXTRA="--exclude feature_block"
FILE_ENV="./ci/test/00_setup_env_native_tsan.sh"
- TEST_RUNNER_EXTRA="--exclude feature_block" # Not enough memory on travis machines
- stage: test
name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer]'
@@ -128,6 +129,12 @@ jobs:
FILE_ENV="./ci/test/00_setup_env_native_fuzz.sh"
- stage: test
+ name: 'x86_64 Linux [GOAL: install] [bionic] [multiprocess]'
+ if: type != pull_request OR commit_message =~ /depends:|multiprocess:/ # Skip on non-depends, non-multiprocess PRs
+ env: >-
+ FILE_ENV="./ci/test/00_setup_env_native_multiprocess.sh"
+
+ - stage: test
name: 'x86_64 Linux [GOAL: install] [bionic] [no wallet]'
env: >-
FILE_ENV="./ci/test/00_setup_env_native_nowallet.sh"
diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh
index dae61c5e34..deb4643731 100755
--- a/ci/test/00_setup_env.sh
+++ b/ci/test/00_setup_env.sh
@@ -34,12 +34,15 @@ export USE_BUSY_BOX=${USE_BUSY_BOX:-false}
export RUN_UNIT_TESTS=${RUN_UNIT_TESTS:-true}
export RUN_FUNCTIONAL_TESTS=${RUN_FUNCTIONAL_TESTS:-true}
export TEST_PREVIOUS_RELEASES=${TEST_PREVIOUS_RELEASES:-false}
+export TEST_RUNNER_ENV=${TEST_RUNNER_ENV:-}
export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false}
export CONTAINER_NAME=${CONTAINER_NAME:-ci_unnamed}
export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:18.04}
# Randomize test order.
# See https://www.boost.org/doc/libs/1_71_0/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/random.html
export BOOST_TEST_RANDOM=${BOOST_TEST_RANDOM:-1}
+# See man 7 debconf
+export DEBIAN_FRONTEND=noninteractive
export CCACHE_SIZE=${CCACHE_SIZE:-100M}
export CCACHE_TEMPDIR=${CCACHE_TEMPDIR:-/tmp/.ccache-temp}
export CCACHE_COMPRESS=${CCACHE_COMPRESS:-1}
diff --git a/ci/test/00_setup_env_native_multiprocess.sh b/ci/test/00_setup_env_native_multiprocess.sh
new file mode 100644
index 0000000000..0fc989085c
--- /dev/null
+++ b/ci/test/00_setup_env_native_multiprocess.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+#
+# 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.
+
+export LC_ALL=C.UTF-8
+
+export CONTAINER_NAME=ci_native_multiprocess
+export PACKAGES="cmake python3"
+export DEP_OPTS="MULTIPROCESS=1"
+export GOAL="install"
+export BITCOIN_CONFIG=""
+export TEST_RUNNER_ENV="BITCOIND=bitcoin-node"
diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh
index 73ab5eebb6..63d06dea64 100644
--- a/ci/test/00_setup_env_native_tsan.sh
+++ b/ci/test/00_setup_env_native_tsan.sh
@@ -7,8 +7,8 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_tsan
-export DOCKER_NAME_TAG=ubuntu:16.04
-export PACKAGES="clang-8 llvm-8 python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev"
+export DOCKER_NAME_TAG=ubuntu:18.04
+export PACKAGES="clang-9 llvm-9 python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev"
export NO_DEPENDS=1
export GOAL="install"
-export BITCOIN_CONFIG="--enable-zmq --disable-wallet --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=thread --disable-hardening --disable-asm CC=clang-8 CXX=clang++-8"
+export BITCOIN_CONFIG="--enable-zmq --disable-wallet --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=thread --disable-hardening --disable-asm CC=clang-9 CXX=clang++-9"
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
index 5dbf1b82f1..8eb49e9ac1 100755
--- a/ci/test/04_install.sh
+++ b/ci/test/04_install.sh
@@ -26,7 +26,7 @@ export ASAN_OPTIONS="detect_stack_use_after_return=1:check_initialization_order=
export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan"
export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:log_path=${BASE_SCRATCH_DIR}/sanitizer-output/tsan"
export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
-env | grep -E '^(BITCOIN_CONFIG|BASE_|QEMU_|CCACHE_|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS|TEST_PREVIOUS_RELEASES|PREVIOUS_RELEASES_DIR)' | tee /tmp/env
+env | grep -E '^(BITCOIN_CONFIG|BASE_|QEMU_|CCACHE_|LC_ALL|BOOST_TEST_RANDOM|DEBIAN_FRONTEND|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS|TEST_PREVIOUS_RELEASES|PREVIOUS_RELEASES_DIR)' | tee /tmp/env
if [[ $HOST = *-mingw32 ]]; then
DOCKER_ADMIN="--cap-add SYS_ADMIN"
elif [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764)
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index ed720bcd00..51d84ee39d 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -37,7 +37,7 @@ fi
if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
BEGIN_FOLD functional-tests
- DOCKER_EXEC LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib test/functional/test_runner.py --ci $MAKEJOBS --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=4000 ${TEST_RUNNER_EXTRA} --quiet --failfast
+ DOCKER_EXEC LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib ${TEST_RUNNER_ENV} test/functional/test_runner.py --ci $MAKEJOBS --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=4000 ${TEST_RUNNER_EXTRA} --quiet --failfast
END_FOLD
fi
diff --git a/configure.ac b/configure.ac
index dc7d34e55e..7f0c5dbd7a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -242,6 +242,24 @@ if test x$enable_bip70 != xno; then
AC_MSG_ERROR([BIP70 is no longer supported!])
fi
+AC_ARG_WITH([libmultiprocess],
+ [AS_HELP_STRING([--with-libmultiprocess=yes|no|auto],
+ [Build with libmultiprocess library. (default: auto, i.e. detect with pkg-config)])],
+ [with_libmultiprocess=$withval],
+ [with_libmultiprocess=auto])
+
+AC_ARG_WITH([mpgen],
+ [AS_HELP_STRING([--with-mpgen=yes|no|auto|PREFIX],
+ [Build with libmultiprocess codegen tool. Useful to specify different libmultiprocess host system library and build system codegen tool prefixes when cross-compiling (default is host system libmultiprocess prefix)])],
+ [with_mpgen=$withval],
+ [with_mpgen=auto])
+
+AC_ARG_ENABLE([multiprocess],
+ [AS_HELP_STRING([--enable-multiprocess],
+ [build multiprocess bitcoin-node, bitcoin-wallet, and bitcoin-gui executables in addition to monolithic bitcoind and bitcoin-qt executables. Requires libmultiprocess library. Experimental (default is no)])],
+ [enable_multiprocess=$enableval],
+ [enable_multiprocess=no])
+
AC_ARG_ENABLE(man,
[AS_HELP_STRING([--disable-man],
[do not install man pages (default is to install)])],,
@@ -595,6 +613,8 @@ case $host in
archive_cmds_CXX="\$CC -shared \$libobjs \$deplibs \$compiler_flags -static -o \$output_objdir/\$soname \${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker \$lib"
postdeps_CXX=
+ dnl We require Windows 7 (NT 6.1) or later
+ AX_CHECK_LINK_FLAG([[-Wl,--major-subsystem-version -Wl,6 -Wl,--minor-subsystem-version -Wl,1]],[LDFLAGS="$LDFLAGS -Wl,--major-subsystem-version -Wl,6 -Wl,--minor-subsystem-version -Wl,1"],,[[$LDFLAG_WERROR]])
;;
*darwin*)
TARGET_OS=darwin
@@ -1387,6 +1407,50 @@ AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes])
AC_SUBST(UNIVALUE_CFLAGS)
AC_SUBST(UNIVALUE_LIBS)
+dnl libmultiprocess library check
+
+libmultiprocess_found=no
+if test "x$with_libmultiprocess" = xyes || test "x$with_libmultiprocess" = xauto; then
+ if test "x$use_pkgconfig" = xyes; then
+ m4_ifdef([PKG_CHECK_MODULES], [PKG_CHECK_MODULES([LIBMULTIPROCESS], [libmultiprocess], [
+ libmultiprocess_found=yes;
+ libmultiprocess_prefix=`$PKG_CONFIG --variable=prefix libmultiprocess`;
+ ], [true])])
+ fi
+elif test "x$with_libmultiprocess" != xno; then
+ AC_MSG_ERROR([--with-libmultiprocess=$with_libmultiprocess value is not yes, auto, or no])
+fi
+AC_SUBST(LIBMULTIPROCESS_CFLAGS)
+AC_SUBST(LIBMULTIPROCESS_LIBS)
+
+dnl Enable multiprocess check
+
+if test "x$enable_multiprocess" = xyes; then
+ if test "x$libmultiprocess_found" != xyes; then
+ AC_MSG_ERROR([--enable-multiprocess=yes option specified but libmultiprocess library was not found. May need to install libmultiprocess library, or specify install path with PKG_CONFIG_PATH environment variable. Running 'pkg-config --debug libmultiprocess' may be helpful for debugging.])
+ fi
+ build_multiprocess=yes
+elif test "x$enable_multiprocess" = xauto; then
+ build_multiprocess=$libmultiprocess_found
+else
+ build_multiprocess=no
+fi
+
+AM_CONDITIONAL([BUILD_MULTIPROCESS],[test "x$build_multiprocess" = xyes])
+AM_CONDITIONAL([BUILD_BITCOIN_NODE], [test "x$build_multiprocess" = xyes])
+AM_CONDITIONAL([BUILD_BITCOIN_GUI], [test "x$build_multiprocess" = xyes])
+
+dnl codegen tools check
+
+if test x$build_multiprocess != xno; then
+ if test "x$with_mpgen" = xyes || test "x$with_mpgen" = xauto; then
+ MPGEN_PREFIX="$libmultiprocess_prefix"
+ elif test "x$with_mpgen" != xno; then
+ MPGEN_PREFIX="$with_mpgen";
+ fi
+ AC_SUBST(MPGEN_PREFIX)
+fi
+
AC_MSG_CHECKING([whether to build bitcoind])
AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes])
AC_MSG_RESULT($build_bitcoind)
@@ -1665,6 +1729,7 @@ esac
echo
echo "Options used to compile and link:"
+echo " multiprocess = $build_multiprocess"
echo " with wallet = $enable_wallet"
echo " with gui / qt = $bitcoin_enable_qt"
if test x$bitcoin_enable_qt != xno; then
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 9444271bdc..ca587ca9e5 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -12,33 +12,33 @@ import subprocess
import sys
import os
+from typing import List, Optional
+
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
OTOOL_CMD = os.getenv('OTOOL', '/usr/bin/otool')
-NONFATAL = {} # checks which are non-fatal for now but only generate a warning
-def check_ELF_PIE(executable):
+def run_command(command) -> str:
+ p = subprocess.run(command, stdout=subprocess.PIPE, check=True, universal_newlines=True)
+ return p.stdout
+
+def check_ELF_PIE(executable) -> bool:
'''
Check for position independent executable (PIE), allowing for address space randomization.
'''
- p = subprocess.Popen([READELF_CMD, '-h', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
+ stdout = run_command([READELF_CMD, '-h', '-W', executable])
ok = False
for line in stdout.splitlines():
- line = line.split()
- if len(line)>=2 and line[0] == 'Type:' and line[1] == 'DYN':
+ tokens = line.split()
+ if len(line)>=2 and tokens[0] == 'Type:' and tokens[1] == 'DYN':
ok = True
return ok
def get_ELF_program_headers(executable):
'''Return type and flags for ELF program headers'''
- p = subprocess.Popen([READELF_CMD, '-l', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
+ stdout = run_command([READELF_CMD, '-l', '-W', executable])
+
in_headers = False
count = 0
headers = []
@@ -62,7 +62,7 @@ def get_ELF_program_headers(executable):
count += 1
return headers
-def check_ELF_NX(executable):
+def check_ELF_NX(executable) -> bool:
'''
Check that no sections are writable and executable (including the stack)
'''
@@ -75,7 +75,7 @@ def check_ELF_NX(executable):
have_wx = True
return have_gnu_stack and not have_wx
-def check_ELF_RELRO(executable):
+def check_ELF_RELRO(executable) -> bool:
'''
Check for read-only relocations.
GNU_RELRO program header must exist
@@ -84,7 +84,8 @@ def check_ELF_RELRO(executable):
have_gnu_relro = False
for (typ, flags) in get_ELF_program_headers(executable):
# Note: not checking flags == 'R': here as linkers set the permission differently
- # This does not affect security: the permission flags of the GNU_RELRO program header are ignored, the PT_LOAD header determines the effective permissions.
+ # This does not affect security: the permission flags of the GNU_RELRO program
+ # header are ignored, the PT_LOAD header determines the effective permissions.
# However, the dynamic linker need to write to this area so these are RW.
# Glibc itself takes care of mprotecting this area R after relocations are finished.
# See also https://marc.info/?l=binutils&m=1498883354122353
@@ -92,93 +93,69 @@ def check_ELF_RELRO(executable):
have_gnu_relro = True
have_bindnow = False
- p = subprocess.Popen([READELF_CMD, '-d', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
+ stdout = run_command([READELF_CMD, '-d', '-W', executable])
+
for line in stdout.splitlines():
tokens = line.split()
if len(tokens)>1 and tokens[1] == '(BIND_NOW)' or (len(tokens)>2 and tokens[1] == '(FLAGS)' and 'BIND_NOW' in tokens[2:]):
have_bindnow = True
return have_gnu_relro and have_bindnow
-def check_ELF_Canary(executable):
+def check_ELF_Canary(executable) -> bool:
'''
Check for use of stack canary
'''
- p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
+ stdout = run_command([READELF_CMD, '--dyn-syms', '-W', executable])
+
ok = False
for line in stdout.splitlines():
if '__stack_chk_fail' in line:
ok = True
return ok
-def get_PE_dll_characteristics(executable):
- '''
- Get PE DllCharacteristics bits.
- Returns a tuple (arch,bits) where arch is 'i386:x86-64' or 'i386'
- and bits is the DllCharacteristics value.
- '''
- p = subprocess.Popen([OBJDUMP_CMD, '-x', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
- arch = ''
+def get_PE_dll_characteristics(executable) -> int:
+ '''Get PE DllCharacteristics bits'''
+ stdout = run_command([OBJDUMP_CMD, '-x', executable])
+
bits = 0
for line in stdout.splitlines():
tokens = line.split()
- if len(tokens)>=2 and tokens[0] == 'architecture:':
- arch = tokens[1].rstrip(',')
if len(tokens)>=2 and tokens[0] == 'DllCharacteristics':
bits = int(tokens[1],16)
- return (arch,bits)
+ return bits
IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020
IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040
IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100
-def check_PE_DYNAMIC_BASE(executable):
+def check_PE_DYNAMIC_BASE(executable) -> bool:
'''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)'''
- (arch,bits) = get_PE_dll_characteristics(executable)
- reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
- return (bits & reqbits) == reqbits
+ bits = get_PE_dll_characteristics(executable)
+ return (bits & IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE) == IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
-# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE
-# to have secure ASLR.
-def check_PE_HIGH_ENTROPY_VA(executable):
+# Must support high-entropy 64-bit address space layout randomization
+# in addition to DYNAMIC_BASE to have secure ASLR.
+def check_PE_HIGH_ENTROPY_VA(executable) -> bool:
'''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR'''
- (arch,bits) = get_PE_dll_characteristics(executable)
- if arch == 'i386:x86-64':
- reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
- else: # Unnecessary on 32-bit
- assert(arch == 'i386')
- reqbits = 0
- return (bits & reqbits) == reqbits
+ bits = get_PE_dll_characteristics(executable)
+ return (bits & IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA) == IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
def check_PE_RELOC_SECTION(executable) -> bool:
'''Check for a reloc section. This is required for functional ASLR.'''
- p = subprocess.Popen([OBJDUMP_CMD, '-h', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
+ stdout = run_command([OBJDUMP_CMD, '-h', executable])
+
for line in stdout.splitlines():
if '.reloc' in line:
return True
return False
-def check_PE_NX(executable):
+def check_PE_NX(executable) -> bool:
'''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)'''
- (arch,bits) = get_PE_dll_characteristics(executable)
+ bits = get_PE_dll_characteristics(executable)
return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
-def get_MACHO_executable_flags(executable):
- p = subprocess.Popen([OTOOL_CMD, '-vh', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
+def get_MACHO_executable_flags(executable) -> List[str]:
+ stdout = run_command([OTOOL_CMD, '-vh', executable])
flags = []
for line in stdout.splitlines():
@@ -222,10 +199,7 @@ def check_MACHO_LAZY_BINDINGS(executable) -> bool:
Check for no lazy bindings.
We don't use or check for MH_BINDATLOAD. See #18295.
'''
- p = subprocess.Popen([OTOOL_CMD, '-l', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
+ stdout = run_command([OTOOL_CMD, '-l', executable])
for line in stdout.splitlines():
tokens = line.split()
@@ -238,10 +212,8 @@ def check_MACHO_Canary(executable) -> bool:
'''
Check for use of stack canary
'''
- p = subprocess.Popen([OTOOL_CMD, '-Iv', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
+ stdout = run_command([OTOOL_CMD, '-Iv', executable])
+
ok = False
for line in stdout.splitlines():
if '___stack_chk_fail' in line:
@@ -270,7 +242,7 @@ CHECKS = {
]
}
-def identify_executable(executable):
+def identify_executable(executable) -> Optional[str]:
with open(filename, 'rb') as f:
magic = f.read(4)
if magic.startswith(b'MZ'):
@@ -292,18 +264,12 @@ if __name__ == '__main__':
continue
failed = []
- warning = []
for (name, func) in CHECKS[etype]:
if not func(filename):
- if name in NONFATAL:
- warning.append(name)
- else:
- failed.append(name)
+ failed.append(name)
if failed:
print('%s: failed %s' % (filename, ' '.join(failed)))
retval = 1
- if warning:
- print('%s: warning %s' % (filename, ' '.join(warning)))
except IOError:
print('%s: cannot open' % filename)
retval = 1
diff --git a/contrib/guix/README.md b/contrib/guix/README.md
index 8ce8cb97a0..dffcf99607 100644
--- a/contrib/guix/README.md
+++ b/contrib/guix/README.md
@@ -142,6 +142,11 @@ find output/ -type f -print0 | sort -z | xargs -r0 sha256sum
If non-empty, will pass `V=1` to all `make` invocations, making `make` output
verbose.
+ Note that any given value is ignored. The variable is only checked for
+ emptiness. More concretely, this means that `V=` (setting `V` to the empty
+ string) is interpreted the same way as not setting `V` at all, and that `V=0`
+ has the same effect as `V=1`.
+
* _**ADDITIONAL_GUIX_ENVIRONMENT_FLAGS**_
Additional flags to be passed to `guix environment`. For a fully-bootstrapped
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index 01f4518c73..5be3baeefa 100644
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -3,6 +3,14 @@ export LC_ALL=C
set -e -o pipefail
export TZ=UTC
+if [ -n "$V" ]; then
+ # Print both unexpanded (-v) and expanded (-x) forms of commands as they are
+ # read from this file.
+ set -vx
+ # Set VERBOSE for CMake-based builds
+ export VERBOSE="$V"
+fi
+
# Check that environment variables assumed to be set by the environment are set
echo "Building for platform triple ${HOST:?not set} with reference timestamp ${SOURCE_DATE_EPOCH:?not set}..."
echo "At most ${MAX_JOBS:?not set} jobs will run at once..."
diff --git a/depends/Makefile b/depends/Makefile
index 5f5247f881..5ad82bb56a 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -13,6 +13,7 @@ NO_QR ?=
NO_WALLET ?=
NO_ZMQ ?=
NO_UPNP ?=
+MULTIPROCESS ?=
FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources
BUILD = $(shell ./config.guess)
@@ -107,6 +108,7 @@ qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch
wallet_packages_$(NO_WALLET) = $(wallet_packages)
upnp_packages_$(NO_UPNP) = $(upnp_packages)
zmq_packages_$(NO_ZMQ) = $(zmq_packages)
+multiprocess_packages_$(MULTIPROCESS) = $(multiprocess_packages)
packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_)
native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages)
@@ -115,6 +117,11 @@ ifneq ($(zmq_packages_),)
packages += $(zmq_packages)
endif
+ifeq ($(multiprocess_packages_),)
+packages += $(multiprocess_packages)
+native_packages += $(multiprocess_native_packages)
+endif
+
all_packages = $(packages) $(native_packages)
meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk
@@ -155,6 +162,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_
-e 's|@no_zmq@|$(NO_ZMQ)|' \
-e 's|@no_wallet@|$(NO_WALLET)|' \
-e 's|@no_upnp@|$(NO_UPNP)|' \
+ -e 's|@multiprocess@|$(MULTIPROCESS)|' \
-e 's|@debug@|$(DEBUG)|' \
$< > $@
$(AT)touch $@
diff --git a/depends/README.md b/depends/README.md
index 79865ff011..c12ea8bcb3 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -91,6 +91,7 @@ The following can be set when running make: make FOO=bar
NO_ZMQ: Don't download/build/cache packages needed for enabling zeromq
NO_WALLET: Don't download/build/cache libs needed to enable the wallet
NO_UPNP: Don't download/build/cache packages needed for enabling upnp
+ MULTIPROCESS: build libmultiprocess (experimental, requires cmake)
DEBUG: disable some optimizations and enable more runtime checking
HOST_ID_SALT: Optional salt to use when generating host package ids
BUILD_ID_SALT: Optional salt to use when generating build package ids
diff --git a/depends/config.site.in b/depends/config.site.in
index fb9bf713cc..103aa0d2ff 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -16,6 +16,9 @@ fi
if test -z $with_qt_bindir && test -z "@no_qt@"; then
with_qt_bindir=$depends_prefix/native/bin
fi
+if test -z $with_mpgen && test -n "@multiprocess@"; then
+ with_mpgen=$depends_prefix/native
+fi
if test -z $with_qrencode && test -n "@no_qr@"; then
with_qrencode=no
@@ -25,6 +28,10 @@ if test -z $enable_wallet && test -n "@no_wallet@"; then
enable_wallet=no
fi
+if test -z $enable_multiprocess && test -n "@multiprocess@"; then
+ enable_multiprocess=yes
+fi
+
if test -z $with_miniupnpc && test -n "@no_upnp@"; then
with_miniupnpc=no
fi
diff --git a/depends/funcs.mk b/depends/funcs.mk
index a4434b5167..135ebba9f8 100644
--- a/depends/funcs.mk
+++ b/depends/funcs.mk
@@ -130,11 +130,11 @@ $(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$(
$(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig
$(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig
+$(1)_config_env+=CMAKE_MODULE_PATH=$($($(1)_type)_prefix)/lib/cmake
$(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH)
$(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH)
$(1)_stage_env+=PATH=$(build_prefix)/bin:$(PATH)
$(1)_autoconf=./configure --host=$($($(1)_type)_host) --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)"
-
ifneq ($($(1)_nm),)
$(1)_autoconf += NM="$$($(1)_nm)"
endif
@@ -156,6 +156,15 @@ endif
ifneq ($($(1)_ldflags),)
$(1)_autoconf += LDFLAGS="$$($(1)_ldflags)"
endif
+
+$(1)_cmake=cmake -DCMAKE_INSTALL_PREFIX=$($($(1)_type)_prefix)
+ifneq ($($(1)_type),build)
+ifneq ($(host),$(build))
+$(1)_cmake += -DCMAKE_SYSTEM_NAME=$($(host_os)_cmake_system) -DCMAKE_SYSROOT=$(host_prefix)
+$(1)_cmake += -DCMAKE_C_COMPILER_TARGET=$(host) -DCMAKE_C_COMPILER=$(firstword $($($(1)_type)_CC)) -DCMAKE_C_FLAGS="$(wordlist 2,1000,$($($(1)_type)_CC))"
+$(1)_cmake += -DCMAKE_CXX_COMPILER_TARGET=$(host) -DCMAKE_CXX_COMPILER=$(firstword $($($(1)_type)_CXX)) -DCMAKE_CXX_FLAGS="$(wordlist 2,1000,$($($(1)_type)_CXX))"
+endif
+endif
endef
define int_add_cmds
diff --git a/depends/hosts/android.mk b/depends/hosts/android.mk
index 969ec2a1cb..eabd84bbbe 100644
--- a/depends/hosts/android.mk
+++ b/depends/hosts/android.mk
@@ -9,3 +9,4 @@ android_CXX=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang++
android_CC=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang
android_RANLIB=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ranlib
endif
+android_cmake_system=Android
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index 1bc4fb8189..82e086a326 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -14,3 +14,4 @@ darwin_debug_CFLAGS=-O1
darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS)
darwin_native_toolchain=native_cctools
+darwin_cmake_system=Darwin
diff --git a/depends/hosts/linux.mk b/depends/hosts/linux.mk
index b13a0f1ad7..8ab448ce5f 100644
--- a/depends/hosts/linux.mk
+++ b/depends/hosts/linux.mk
@@ -29,3 +29,4 @@ i686_linux_CXX=$(default_host_CXX) -m32
x86_64_linux_CC=$(default_host_CC) -m64
x86_64_linux_CXX=$(default_host_CXX) -m64
endif
+linux_cmake_system=Linux
diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk
index dbfb62fdcf..be5fec570c 100644
--- a/depends/hosts/mingw32.mk
+++ b/depends/hosts/mingw32.mk
@@ -8,3 +8,5 @@ mingw32_debug_CFLAGS=-O1
mingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS)
mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
+
+mingw_cmake_system=Windows
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index cbe4fe4d97..970c81041e 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -1,7 +1,7 @@
package=boost
$(package)_version=1_70_0
$(package)_download_path=https://dl.bintray.com/boostorg/release/1.70.0/source/
-$(package)_file_name=$(package)_$($(package)_version).tar.bz2
+$(package)_file_name=boost_$($(package)_version).tar.bz2
$(package)_sha256_hash=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778
define $(package)_set_vars
diff --git a/depends/packages/capnp.mk b/depends/packages/capnp.mk
new file mode 100644
index 0000000000..abeb26545f
--- /dev/null
+++ b/depends/packages/capnp.mk
@@ -0,0 +1,18 @@
+package=capnp
+$(package)_version=$(native_$(package)_version)
+$(package)_download_path=$(native_$(package)_download_path)
+$(package)_file_name=$(native_$(package)_file_name)
+$(package)_sha256_hash=$(native_$(package)_sha256_hash)
+$(package)_dependencies=native_$(package)
+
+define $(package)_config_cmds
+ $($(package)_autoconf) --with-external-capnp
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
diff --git a/depends/packages/libmultiprocess.mk b/depends/packages/libmultiprocess.mk
new file mode 100644
index 0000000000..3e5cf5f160
--- /dev/null
+++ b/depends/packages/libmultiprocess.mk
@@ -0,0 +1,18 @@
+package=libmultiprocess
+$(package)_version=$(native_$(package)_version)
+$(package)_download_path=$(native_$(package)_download_path)
+$(package)_file_name=$(native_$(package)_file_name)
+$(package)_sha256_hash=$(native_$(package)_sha256_hash)
+$(package)_dependencies=native_$(package) boost capnp
+
+define $(package)_config_cmds
+ $($(package)_cmake)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
diff --git a/depends/packages/native_capnp.mk b/depends/packages/native_capnp.mk
new file mode 100644
index 0000000000..ed5a6deee2
--- /dev/null
+++ b/depends/packages/native_capnp.mk
@@ -0,0 +1,18 @@
+package=native_capnp
+$(package)_version=0.7.0
+$(package)_download_path=https://capnproto.org/
+$(package)_download_file=capnproto-c++-$($(package)_version).tar.gz
+$(package)_file_name=capnproto-cxx-$($(package)_version).tar.gz
+$(package)_sha256_hash=c9a4c0bd88123064d483ab46ecee777f14d933359e23bff6fb4f4dbd28b4cd41
+
+define $(package)_config_cmds
+ $($(package)_autoconf)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
diff --git a/depends/packages/native_libmultiprocess.mk b/depends/packages/native_libmultiprocess.mk
new file mode 100644
index 0000000000..c50fdc3f6b
--- /dev/null
+++ b/depends/packages/native_libmultiprocess.mk
@@ -0,0 +1,18 @@
+package=native_libmultiprocess
+$(package)_version=5741d750a04e644a03336090d8979c6d033e32c0
+$(package)_download_path=https://github.com/chaincodelabs/libmultiprocess/archive
+$(package)_file_name=$($(package)_version).tar.gz
+$(package)_sha256_hash=ac848db49a6ed53e423c62d54bd87f1f08cbb0326254a8667e10bbfe5bf032a4
+$(package)_dependencies=native_capnp
+
+define $(package)_config_cmds
+ $($(package)_cmake)
+endef
+
+define $(package)_build_cmds
+ $(MAKE)
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 42dbaa77a6..8fe2c771c9 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -16,6 +16,9 @@ zmq_packages=zeromq
upnp_packages=miniupnpc
+multiprocess_packages = libmultiprocess capnp
+multiprocess_native_packages = native_libmultiprocess native_capnp
+
darwin_native_packages = native_biplist native_ds_store native_mac_alias
ifneq ($(build_os),darwin)
diff --git a/doc/multiprocess.md b/doc/multiprocess.md
new file mode 100644
index 0000000000..471d8561f7
--- /dev/null
+++ b/doc/multiprocess.md
@@ -0,0 +1,35 @@
+# Multiprocess Bitcoin
+
+On unix systems, the `--enable-multiprocess` build option can be passed to `./configure` to build new `bitcoin-node`, `bitcoin-wallet`, and `bitcoin-gui` executables alongside existing `bitcoind` and `bitcoin-qt` executables.
+
+`bitcoin-node` is a drop-in replacement for `bitcoind`, and `bitcoin-gui` is a drop-in replacement for `bitcoin-qt`, and there are no differences in use or external behavior between the new and old executables. But internally (after [#10102](https://github.com/bitcoin/bitcoin/pull/10102)), `bitcoin-gui` will spawn a `bitcoin-node` process to run P2P and RPC code, communicating with it across a socket pair, and `bitcoin-node` will spawn `bitcoin-wallet` to run wallet code, also communicating over a socket pair. This will let node, wallet, and GUI code run in separate address spaces for better isolation, and allow future improvements like being able to start and stop components independently on different machines and environments.
+
+## Next steps
+
+Specific next steps after [#10102](https://github.com/bitcoin/bitcoin/pull/10102) will be:
+
+- [ ] Adding `-ipcbind` and `-ipcconnect` options to `bitcoin-node`, `bitcoin-wallet`, and `bitcoin-gui` executables so they can listen and connect to TCP ports and unix socket paths. This will allow separate processes to be started and stopped any time and connect to each other.
+- [ ] Adding `-server` and `-rpcbind` options to the `bitcoin-wallet` executable so wallet processes can handle RPC requests directly without going through the node.
+- [ ] Supporting windows, not just unix systems. The existing socket code is already cross-platform, so the only windows-specific code that needs to be written is code spawning a process and passing a socket descriptor. This can be implemented with `CreateProcess` and `WSADuplicateSocket`. Example: https://memset.wordpress.com/2010/10/13/win32-api-passing-socket-with-ipc-method/.
+- [ ] Adding sandbox features, restricting subprocess access to resources and data. See [https://eklitzke.org/multiprocess-bitcoin](https://eklitzke.org/multiprocess-bitcoin).
+
+## Debugging
+
+After [#10102](https://github.com/bitcoin/bitcoin/pull/10102), the `-debug=ipc` command line option can be used to see requests and responses between processes.
+
+## Installation
+
+The multiprocess feature requires [Cap'n Proto](https://capnproto.org/) and [libmultiprocess](https://github.com/chaincodelabs/libmultiprocess) as dependencies. A simple way to get starting using it without installing these dependencies manually is to use the [depends system](../depends) with the `MULTIPROCESS=1` [dependency option](../depends#dependency-options) passed to make:
+
+```
+cd <BITCOIN_SOURCE_DIRECTORY>
+make -C depends NO_QT=1 MULTIPROCESS=1
+./configure --prefix=$PWD/depends/x86_64-pc-linux-gnu
+make
+src/bitcoin-node -regtest -printtoconsole -debug=ipc
+BITCOIND=bitcoin-node test/functional/test_runner.py
+```
+
+The configure script will pick up settings and library locations from the depends directory, so there is no need to pass `--enable-multiprocess` as a separate flag when using the depends system (it's controlled by the `MULTIPROCESS=1` option).
+
+Alternately, you can install [Cap'n Proto](https://capnproto.org/) and [libmultiprocess](https://github.com/chaincodelabs/libmultiprocess) packages on your system, and just run `./configure --enable-multiprocess` without using the depends system. The configure script will be able to locate the installed packages via [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/). See [Installation](https://github.com/chaincodelabs/libmultiprocess#installation) section of the libmultiprocess readme for install steps. See [build-unix.md](build-unix.md) and [build-osx.md](build-osx.md) for information about installing dependencies in general.
diff --git a/src/Makefile.am b/src/Makefile.am
index d2c7400bbb..882d83e0b8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -85,6 +85,10 @@ if BUILD_BITCOIND
bin_PROGRAMS += bitcoind
endif
+if BUILD_BITCOIN_NODE
+ bin_PROGRAMS += bitcoin-node
+endif
+
if BUILD_BITCOIN_CLI
bin_PROGRAMS += bitcoin-cli
endif
@@ -547,22 +551,21 @@ libbitcoin_cli_a_SOURCES = \
nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
#
-# bitcoind binary #
-bitcoind_SOURCES = bitcoind.cpp
-bitcoind_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
-bitcoind_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+# bitcoind & bitcoin-node binaries #
+bitcoin_daemon_sources = bitcoind.cpp
+bitcoin_bin_cppflags = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+bitcoin_bin_cxxflags = $(AM_CXXFLAGS) $(PIE_FLAGS)
+bitcoin_bin_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
-bitcoind_SOURCES += bitcoind-res.rc
+bitcoin_daemon_sources += bitcoind-res.rc
endif
-bitcoind_LDADD = \
- $(LIBBITCOIN_SERVER) \
+bitcoin_bin_ldadd = \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_COMMON) \
- $(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
+ $(LIBUNIVALUE) \
$(LIBBITCOIN_ZMQ) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
@@ -571,7 +574,19 @@ bitcoind_LDADD = \
$(LIBMEMENV) \
$(LIBSECP256K1)
-bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
+bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
+
+bitcoind_SOURCES = $(bitcoin_daemon_sources)
+bitcoind_CPPFLAGS = $(bitcoin_bin_cppflags)
+bitcoind_CXXFLAGS = $(bitcoin_bin_cxxflags)
+bitcoind_LDFLAGS = $(bitcoin_bin_ldflags)
+bitcoind_LDADD = $(LIBBITCOIN_SERVER) $(bitcoin_bin_ldadd)
+
+bitcoin_node_SOURCES = $(bitcoin_daemon_sources)
+bitcoin_node_CPPFLAGS = $(bitcoin_bin_cppflags)
+bitcoin_node_CXXFLAGS = $(bitcoin_bin_cxxflags)
+bitcoin_node_LDFLAGS = $(bitcoin_bin_ldflags)
+bitcoin_node_LDADD = $(LIBBITCOIN_SERVER) $(bitcoin_bin_ldadd)
# bitcoin-cli binary #
bitcoin_cli_SOURCES = bitcoin-cli.cpp
@@ -615,29 +630,14 @@ bitcoin_tx_LDADD += $(BOOST_LIBS)
# bitcoin-wallet binary #
bitcoin_wallet_SOURCES = bitcoin-wallet.cpp
-bitcoin_wallet_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
-bitcoin_wallet_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-bitcoin_wallet_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+bitcoin_wallet_CPPFLAGS = $(bitcoin_bin_cppflags)
+bitcoin_wallet_CXXFLAGS = $(bitcoin_bin_cxxflags)
+bitcoin_wallet_LDFLAGS = $(bitcoin_bin_ldflags)
+bitcoin_wallet_LDADD = $(LIBBITCOIN_WALLET_TOOL) $(bitcoin_bin_ldadd)
if TARGET_WINDOWS
bitcoin_wallet_SOURCES += bitcoin-wallet-res.rc
endif
-
-bitcoin_wallet_LDADD = \
- $(LIBBITCOIN_WALLET_TOOL) \
- $(LIBBITCOIN_WALLET) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_ZMQ) \
- $(LIBLEVELDB) \
- $(LIBLEVELDB_SSE42) \
- $(LIBMEMENV) \
- $(LIBSECP256K1) \
- $(LIBUNIVALUE)
-
-bitcoin_wallet_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(ZMQ_LIBS)
#
# bitcoinconsensus library #
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index cf09eee2cb..13bfea7646 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -3,6 +3,11 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
bin_PROGRAMS += qt/bitcoin-qt
+
+if BUILD_BITCOIN_GUI
+ bin_PROGRAMS += bitcoin-gui
+endif
+
EXTRA_LIBRARIES += qt/libbitcoinqt.a
# bitcoin qt core #
@@ -294,29 +299,43 @@ QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:
# Most files will depend on the forms and moc files as includes. Generate them
# before anything else.
$(QT_MOC): $(QT_FORMS_H)
-$(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) : | $(QT_MOC)
+$(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) $(bitcoin_gui_OBJECTS) : | $(QT_MOC)
-# bitcoin-qt binary #
-qt_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
+# bitcoin-qt and bitcoin-gui binaries #
+bitcoin_qt_cppflags = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QR_CFLAGS)
-qt_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
+bitcoin_qt_cxxflags = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
-qt_bitcoin_qt_SOURCES = qt/main.cpp
+bitcoin_qt_sources = qt/main.cpp
if TARGET_WINDOWS
- qt_bitcoin_qt_SOURCES += $(BITCOIN_RC)
+ bitcoin_qt_sources += $(BITCOIN_RC)
endif
-qt_bitcoin_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
+bitcoin_qt_ldadd = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
if ENABLE_WALLET
-qt_bitcoin_qt_LDADD += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET)
+bitcoin_qt_ldadd += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET)
endif
if ENABLE_ZMQ
-qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
+bitcoin_qt_ldadd += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
-qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
+bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
-qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-qt_bitcoin_qt_LIBTOOLFLAGS = $(AM_LIBTOOLFLAGS) --tag CXX
+bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX
+
+qt_bitcoin_qt_CPPFLAGS = $(bitcoin_qt_cppflags)
+qt_bitcoin_qt_CXXFLAGS = $(bitcoin_qt_cxxflags)
+qt_bitcoin_qt_SOURCES = $(bitcoin_qt_sources)
+qt_bitcoin_qt_LDADD = $(bitcoin_qt_ldadd)
+qt_bitcoin_qt_LDFLAGS = $(bitcoin_qt_ldflags)
+qt_bitcoin_qt_LIBTOOLFLAGS = $(bitcoin_qt_libtoolflags)
+
+bitcoin_gui_CPPFLAGS = $(bitcoin_qt_cppflags)
+bitcoin_gui_CXXFLAGS = $(bitcoin_qt_cxxflags)
+bitcoin_gui_SOURCES = $(bitcoin_qt_sources)
+bitcoin_gui_LDADD = $(bitcoin_qt_ldadd)
+bitcoin_gui_LDFLAGS = $(bitcoin_qt_ldflags)
+bitcoin_gui_LIBTOOLFLAGS = $(bitcoin_qt_libtoolflags)
#locale/foo.ts -> locale/foo.qm
QT_QM=$(QT_TS:.ts=.qm)
diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp
index 00e5d7e7a0..42b351a72d 100644
--- a/src/bench/prevector.cpp
+++ b/src/bench/prevector.cpp
@@ -20,9 +20,7 @@
struct nontrivial_t {
int x;
nontrivial_t() :x(-1) {}
- ADD_SERIALIZE_METHODS
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {READWRITE(x);}
+ SERIALIZE_METHODS(nontrivial_t, obj) { READWRITE(obj.x); }
};
static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE<nontrivial_t>::value,
"expected nontrivial_t to not be trivially constructible");
diff --git a/src/blockencodings.h b/src/blockencodings.h
index 377ac3a1a6..9ec1beeaf7 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -92,12 +92,13 @@ private:
friend class PartiallyDownloadedBlock;
- static const int SHORTTXIDS_LENGTH = 6;
protected:
std::vector<uint64_t> shorttxids;
std::vector<PrefilledTransaction> prefilledtxn;
public:
+ static constexpr int SHORTTXIDS_LENGTH = 6;
+
CBlockHeader header;
// Dummy for deserialization
diff --git a/src/bloom.h b/src/bloom.h
index 9173b80d66..9307257852 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -64,15 +64,7 @@ public:
CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweak, unsigned char nFlagsIn);
CBloomFilter() : nHashFuncs(0), nTweak(0), nFlags(0) {}
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(vData);
- READWRITE(nHashFuncs);
- READWRITE(nTweak);
- READWRITE(nFlags);
- }
+ SERIALIZE_METHODS(CBloomFilter, obj) { READWRITE(obj.vData, obj.nHashFuncs, obj.nTweak, obj.nFlags); }
void insert(const std::vector<unsigned char>& vKey);
void insert(const COutPoint& outpoint);
diff --git a/src/flatfile.h b/src/flatfile.h
index 60b3503cc3..04f6373a24 100644
--- a/src/flatfile.h
+++ b/src/flatfile.h
@@ -16,13 +16,7 @@ struct FlatFilePos
int nFile;
unsigned int nPos;
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(VARINT_MODE(nFile, VarIntMode::NONNEGATIVE_SIGNED));
- READWRITE(VARINT(nPos));
- }
+ SERIALIZE_METHODS(FlatFilePos, obj) { READWRITE(VARINT_MODE(obj.nFile, VarIntMode::NONNEGATIVE_SIGNED), VARINT(obj.nPos)); }
FlatFilePos() : nFile(-1), nPos(0) {}
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index f03d8c0c2c..f1b9997371 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -9,7 +9,6 @@
#include <httpserver.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
-#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/translation.h>
@@ -249,11 +248,8 @@ static bool InitRPCAuthentication()
{
if (gArgs.GetArg("-rpcpassword", "") == "")
{
- LogPrintf("No rpcpassword set - using random cookie authentication.\n");
+ LogPrintf("Using random cookie authentication.\n");
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
- uiInterface.ThreadSafeMessageBox(
- _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
- "", CClientUIInterface::MSG_ERROR);
return false;
}
} else {
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index ffe246b241..5e78fd1d71 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -421,7 +421,7 @@ bool UpdateHTTPServerLogging(bool enable) {
#endif
}
-static std::thread threadHTTP;
+static std::thread g_thread_http;
static std::vector<std::thread> g_thread_http_workers;
void StartHTTPServer()
@@ -429,7 +429,7 @@ void StartHTTPServer()
LogPrint(BCLog::HTTP, "Starting HTTP server\n");
int rpcThreads = std::max((long)gArgs.GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
- threadHTTP = std::thread(ThreadHTTP, eventBase);
+ g_thread_http = std::thread(ThreadHTTP, eventBase);
for (int i = 0; i < rpcThreads; i++) {
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue, i);
@@ -467,7 +467,7 @@ void StopHTTPServer()
boundSockets.clear();
if (eventBase) {
LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
- threadHTTP.join();
+ if (g_thread_http.joinable()) g_thread_http.join();
}
if (eventHTTP) {
evhttp_free(eventHTTP);
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index c3ce8d7af0..f2c3d66ebd 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -39,14 +39,7 @@ struct DBVal {
uint256 header;
FlatFilePos pos;
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(hash);
- READWRITE(header);
- READWRITE(pos);
- }
+ SERIALIZE_METHODS(DBVal, obj) { READWRITE(obj.hash, obj.header, obj.pos); }
};
struct DBHeightKey {
@@ -78,17 +71,14 @@ struct DBHashKey {
explicit DBHashKey(const uint256& hash_in) : hash(hash_in) {}
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
+ SERIALIZE_METHODS(DBHashKey, obj) {
char prefix = DB_BLOCK_HASH;
READWRITE(prefix);
if (prefix != DB_BLOCK_HASH) {
throw std::ios_base::failure("Invalid format for block filter index DB hash key");
}
- READWRITE(hash);
+ READWRITE(obj.hash);
}
};
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 5bbe6ad1df..4626395ef0 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -21,12 +21,10 @@ struct CDiskTxPos : public FlatFilePos
{
unsigned int nTxOffset; // after header
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITEAS(FlatFilePos, *this);
- READWRITE(VARINT(nTxOffset));
+ SERIALIZE_METHODS(CDiskTxPos, obj)
+ {
+ READWRITEAS(FlatFilePos, obj);
+ READWRITE(VARINT(obj.nTxOffset));
}
CDiskTxPos(const FlatFilePos &blockIn, unsigned int nTxOffsetIn) : FlatFilePos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {
diff --git a/src/init.cpp b/src/init.cpp
index f01416e136..025ae06520 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -59,9 +59,10 @@
#include <validationinterface.h>
#include <walletinitinterface.h>
+#include <functional>
+#include <set>
#include <stdint.h>
#include <stdio.h>
-#include <set>
#ifndef WIN32
#include <attributes.h>
@@ -350,13 +351,13 @@ static void registerSignalHandler(int signal, void(*handler)(int))
static boost::signals2::connection rpc_notify_block_change_connection;
static void OnRPCStarted()
{
- rpc_notify_block_change_connection = uiInterface.NotifyBlockTip_connect(&RPCNotifyBlockChange);
+ rpc_notify_block_change_connection = uiInterface.NotifyBlockTip_connect(std::bind(RPCNotifyBlockChange, std::placeholders::_2));
}
static void OnRPCStopped()
{
rpc_notify_block_change_connection.disconnect();
- RPCNotifyBlockChange(false, nullptr);
+ RPCNotifyBlockChange(nullptr);
g_best_block_cv.notify_all();
LogPrint(BCLog::RPC, "RPC stopped.\n");
}
@@ -604,9 +605,9 @@ std::string LicenseInfo()
}
#if HAVE_SYSTEM
-static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex)
+static void BlockNotifyCallback(SynchronizationState sync_state, const CBlockIndex* pBlockIndex)
{
- if (initialSync || !pBlockIndex)
+ if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex)
return;
std::string strCmd = gArgs.GetArg("-blocknotify", "");
@@ -622,7 +623,7 @@ static bool fHaveGenesis = false;
static Mutex g_genesis_wait_mutex;
static std::condition_variable g_genesis_wait_cv;
-static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex)
+static void BlockNotifyGenesisWait(const CBlockIndex* pBlockIndex)
{
if (pBlockIndex != nullptr) {
{
@@ -1700,7 +1701,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node)
}
const CBlockIndex* tip = chainstate->m_chain.Tip();
- RPCNotifyBlockChange(true, tip);
+ RPCNotifyBlockChange(tip);
if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
strLoadError = _("The block database contains a block which appears to be from the future. "
"This may be due to your computer's date and time being set incorrectly. "
@@ -1825,7 +1826,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node)
// No locking, as this happens before any background thread is started.
boost::signals2::connection block_notify_genesis_wait_connection;
if (::ChainActive().Tip() == nullptr) {
- block_notify_genesis_wait_connection = uiInterface.NotifyBlockTip_connect(BlockNotifyGenesisWait);
+ block_notify_genesis_wait_connection = uiInterface.NotifyBlockTip_connect(std::bind(BlockNotifyGenesisWait, std::placeholders::_2));
} else {
fHaveGenesis = true;
}
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index cc0f7db5c1..3c94e44b53 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -309,16 +309,16 @@ public:
}
std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
{
- return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](bool initial_download, const CBlockIndex* block) {
- fn(initial_download, block->nHeight, block->GetBlockTime(),
+ return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
+ fn(sync_state, block->nHeight, block->GetBlockTime(),
GuessVerificationProgress(Params().TxData(), block));
}));
}
std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
{
return MakeHandler(
- ::uiInterface.NotifyHeaderTip_connect([fn](bool initial_download, const CBlockIndex* block) {
- fn(initial_download, block->nHeight, block->GetBlockTime(),
+ ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
+ fn(sync_state, block->nHeight, block->GetBlockTime(),
/* verification progress is unused when a header was received */ 0);
}));
}
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index aef6b19458..45b0e18fae 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -27,6 +27,7 @@ class Coin;
class RPCTimerInterface;
class UniValue;
class proxyType;
+enum class SynchronizationState;
enum class WalletCreationStatus;
struct CNodeStateStats;
struct NodeContext;
@@ -249,12 +250,12 @@ public:
//! Register handler for block tip messages.
using NotifyBlockTipFn =
- std::function<void(bool initial_download, int height, int64_t block_time, double verification_progress)>;
+ std::function<void(SynchronizationState, int height, int64_t block_time, double verification_progress)>;
virtual std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) = 0;
//! Register handler for header tip messages.
using NotifyHeaderTipFn =
- std::function<void(bool initial_download, int height, int64_t block_time, double verification_progress)>;
+ std::function<void(SynchronizationState, int height, int64_t block_time, double verification_progress)>;
virtual std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0;
//! Return pointer to internal chain interface, useful for testing.
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 13b034936b..349dce0247 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -351,14 +351,13 @@ public:
}
return result;
}
- bool tryGetBalances(WalletBalances& balances, int& num_blocks, bool force, int cached_num_blocks) override
+ bool tryGetBalances(WalletBalances& balances, int& num_blocks) override
{
TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
if (!locked_wallet) {
return false;
}
num_blocks = m_wallet->GetLastBlockHeight();
- if (!force && num_blocks == cached_num_blocks) return false;
balances = getBalances();
return true;
}
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index f35335c69f..421d35af15 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -202,11 +202,8 @@ public:
//! Get balances.
virtual WalletBalances getBalances() = 0;
- //! Get balances if possible without waiting for chain and wallet locks.
- virtual bool tryGetBalances(WalletBalances& balances,
- int& num_blocks,
- bool force,
- int cached_num_blocks) = 0;
+ //! Get balances if possible without blocking.
+ virtual bool tryGetBalances(WalletBalances& balances, int& num_blocks) = 0;
//! Get balance.
virtual CAmount getBalance() = 0;
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index 4ac6219886..8072b12119 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -9,6 +9,24 @@
#include <consensus/consensus.h>
+std::vector<unsigned char> BitsToBytes(const std::vector<bool>& bits)
+{
+ std::vector<unsigned char> ret((bits.size() + 7) / 8);
+ for (unsigned int p = 0; p < bits.size(); p++) {
+ ret[p / 8] |= bits[p] << (p % 8);
+ }
+ return ret;
+}
+
+std::vector<bool> BytesToBits(const std::vector<unsigned char>& bytes)
+{
+ std::vector<bool> ret(bytes.size() * 8);
+ for (unsigned int p = 0; p < ret.size(); p++) {
+ ret[p] = (bytes[p / 8] & (1 << (p % 8))) != 0;
+ }
+ return ret;
+}
+
CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<uint256>* txids)
{
header = block.GetBlockHeader();
diff --git a/src/merkleblock.h b/src/merkleblock.h
index e641c8aa94..b2d2828784 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -13,6 +13,10 @@
#include <vector>
+// Helper functions for serialization.
+std::vector<unsigned char> BitsToBytes(const std::vector<bool>& bits);
+std::vector<bool> BytesToBits(const std::vector<unsigned char>& bytes);
+
/** Data structure that represents a partial merkle tree.
*
* It represents a subset of the txid's of a known block, in a way that
@@ -81,27 +85,14 @@ protected:
public:
- /** serialization implementation */
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(nTransactions);
- READWRITE(vHash);
- std::vector<unsigned char> vBytes;
- if (ser_action.ForRead()) {
- READWRITE(vBytes);
- CPartialMerkleTree &us = *(const_cast<CPartialMerkleTree*>(this));
- us.vBits.resize(vBytes.size() * 8);
- for (unsigned int p = 0; p < us.vBits.size(); p++)
- us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0;
- us.fBad = false;
- } else {
- vBytes.resize((vBits.size()+7)/8);
- for (unsigned int p = 0; p < vBits.size(); p++)
- vBytes[p / 8] |= vBits[p] << (p % 8);
- READWRITE(vBytes);
- }
+ SERIALIZE_METHODS(CPartialMerkleTree, obj)
+ {
+ READWRITE(obj.nTransactions, obj.vHash);
+ std::vector<unsigned char> bytes;
+ SER_WRITE(obj, bytes = BitsToBytes(obj.vBits));
+ READWRITE(bytes);
+ SER_READ(obj, obj.vBits = BytesToBits(bytes));
+ SER_READ(obj, obj.fBad = false);
}
/** Construct a partial merkle tree from a list of transaction ids, and a mask that selects a subset of them */
@@ -157,13 +148,7 @@ public:
CMerkleBlock() {}
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(header);
- READWRITE(txn);
- }
+ SERIALIZE_METHODS(CMerkleBlock, obj) { READWRITE(obj.header, obj.txn); }
private:
// Combined constructor to consolidate code
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 1df1fab59d..6d85b46831 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1608,6 +1608,37 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
}
}
+//! Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed).
+CTransactionRef static FindTxForGetData(CNode* peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main)
+{
+ // Check if the requested transaction is so recent that we're just
+ // about to announce it to the peer; if so, they certainly shouldn't
+ // know we already have it.
+ {
+ LOCK(peer->m_tx_relay->cs_tx_inventory);
+ if (peer->m_tx_relay->setInventoryTxToSend.count(txid)) return {};
+ }
+
+ {
+ LOCK(cs_main);
+ // Look up transaction in relay pool
+ auto mi = mapRelay.find(txid);
+ if (mi != mapRelay.end()) return mi->second;
+ }
+
+ auto txinfo = mempool.info(txid);
+ if (txinfo.tx) {
+ // To protect privacy, do not answer getdata using the mempool when
+ // that TX couldn't have been INVed in reply to a MEMPOOL request,
+ // or when it's too recent to have expired from mapRelay.
+ if ((mempool_req.count() && txinfo.m_time <= mempool_req) || txinfo.m_time <= longlived_mempool_time) {
+ return txinfo.tx;
+ }
+ }
+
+ return {};
+}
+
void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, CTxMemPool& mempool, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main)
{
AssertLockNotHeld(cs_main);
@@ -1622,58 +1653,31 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
const std::chrono::seconds mempool_req = pfrom->m_tx_relay != nullptr ? pfrom->m_tx_relay->m_last_mempool_req.load()
: std::chrono::seconds::min();
- {
- LOCK(cs_main);
-
- // Process as many TX items from the front of the getdata queue as
- // possible, since they're common and it's efficient to batch process
- // them.
- while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) {
- if (interruptMsgProc)
- return;
- // The send buffer provides backpressure. If there's no space in
- // the buffer, pause processing until the next call.
- if (pfrom->fPauseSend)
- break;
+ // Process as many TX items from the front of the getdata queue as
+ // possible, since they're common and it's efficient to batch process
+ // them.
+ while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) {
+ if (interruptMsgProc) return;
+ // The send buffer provides backpressure. If there's no space in
+ // the buffer, pause processing until the next call.
+ if (pfrom->fPauseSend) break;
- const CInv &inv = *it++;
+ const CInv &inv = *it++;
- if (pfrom->m_tx_relay == nullptr) {
- // Ignore GETDATA requests for transactions from blocks-only peers.
- continue;
- }
+ if (pfrom->m_tx_relay == nullptr) {
+ // Ignore GETDATA requests for transactions from blocks-only peers.
+ continue;
+ }
- // Send stream from relay memory
- bool push = false;
- auto mi = mapRelay.find(inv.hash);
+ CTransactionRef tx = FindTxForGetData(pfrom, inv.hash, mempool_req, longlived_mempool_time);
+ if (tx) {
int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
- if (mi != mapRelay.end()) {
- connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
- push = true;
- } else {
- auto txinfo = mempool.info(inv.hash);
- // To protect privacy, do not answer getdata using the mempool when
- // that TX couldn't have been INVed in reply to a MEMPOOL request,
- // or when it's too recent to have expired from mapRelay.
- if (txinfo.tx && (
- (mempool_req.count() && txinfo.m_time <= mempool_req)
- || (txinfo.m_time <= longlived_mempool_time)))
- {
- connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
- push = true;
- }
- }
-
- if (push) {
- // We interpret fulfilling a GETDATA for a transaction as a
- // successful initial broadcast and remove it from our
- // unbroadcast set.
- mempool.RemoveUnbroadcastTx(inv.hash);
- } else {
- vNotFound.push_back(inv);
- }
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx));
+ mempool.RemoveUnbroadcastTx(inv.hash);
+ } else {
+ vNotFound.push_back(inv);
}
- } // release cs_main
+ }
// Only process one BLOCK item per call, since they're uncommon and can be
// expensive to process.
@@ -2420,6 +2424,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec
uint32_t nFetchFlags = GetFetchFlags(pfrom);
const auto current_time = GetTime<std::chrono::microseconds>();
+ uint256* best_block{nullptr};
for (CInv &inv : vInv)
{
@@ -2436,17 +2441,14 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec
if (inv.type == MSG_BLOCK) {
UpdateBlockAvailability(pfrom->GetId(), inv.hash);
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
- // We used to request the full block here, but since headers-announcements are now the
- // primary method of announcement on the network, and since, in the case that a node
- // fell back to inv we probably have a reorg which we should get the headers for first,
- // we now only provide a getheaders response here. When we receive the headers, we will
- // then ask for the blocks we need.
- connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), inv.hash));
- LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId());
+ // Headers-first is the primary method of announcement on
+ // the network. If a node fell back to sending blocks by inv,
+ // it's probably for a re-org. The final block hash
+ // provided should be the highest, so send a getheaders and
+ // then fetch the blocks we need to catch up.
+ best_block = &inv.hash;
}
- }
- else
- {
+ } else {
pfrom->AddInventoryKnown(inv);
if (fBlocksOnly) {
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom->GetId());
@@ -2457,6 +2459,12 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec
}
}
}
+
+ if (best_block != nullptr) {
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), *best_block));
+ LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom->GetId());
+ }
+
return true;
}
diff --git a/src/netaddress.h b/src/netaddress.h
index d8f19deffe..e640c07d32 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -99,12 +99,7 @@ class CNetAddr
friend bool operator!=(const CNetAddr& a, const CNetAddr& b) { return !(a == b); }
friend bool operator<(const CNetAddr& a, const CNetAddr& b);
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(ip);
- }
+ SERIALIZE_METHODS(CNetAddr, obj) { READWRITE(obj.ip); }
friend class CSubNet;
};
@@ -136,14 +131,7 @@ class CSubNet
friend bool operator!=(const CSubNet& a, const CSubNet& b) { return !(a == b); }
friend bool operator<(const CSubNet& a, const CSubNet& b);
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(network);
- READWRITE(netmask);
- READWRITE(valid);
- }
+ SERIALIZE_METHODS(CSubNet, obj) { READWRITE(obj.network, obj.netmask, obj.valid); }
};
/** A combination of a network address (CNetAddr) and a (TCP) port */
@@ -171,13 +159,7 @@ class CService : public CNetAddr
CService(const struct in6_addr& ipv6Addr, unsigned short port);
explicit CService(const struct sockaddr_in6& addr);
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(ip);
- READWRITE(WrapBigEndian(port));
- }
+ SERIALIZE_METHODS(CService, obj) { READWRITE(obj.ip, Using<BigEndianFormatter<2>>(obj.port)); }
};
bool SanityCheckASMap(const std::vector<bool>& asmap);
diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h
index 702a0cbe53..c8b4d60fd0 100644
--- a/src/node/utxo_snapshot.h
+++ b/src/node/utxo_snapshot.h
@@ -35,16 +35,7 @@ public:
m_coins_count(coins_count),
m_nchaintx(nchaintx) { }
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action)
- {
- READWRITE(m_base_blockhash);
- READWRITE(m_coins_count);
- READWRITE(m_nchaintx);
- }
-
+ SERIALIZE_METHODS(SnapshotMetadata, obj) { READWRITE(obj.m_base_blockhash, obj.m_coins_count, obj.m_nchaintx); }
};
#endif // BITCOIN_NODE_UTXO_SNAPSHOT_H
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index c040867965..61fa80c130 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -48,12 +48,7 @@ public:
CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
std::string ToString() const;
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(nSatoshisPerK);
- }
+ SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); }
};
#endif // BITCOIN_POLICY_FEERATE_H
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 750d42efbc..fd8fc8b868 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -33,17 +33,7 @@ public:
SetNull();
}
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(this->nVersion);
- READWRITE(hashPrevBlock);
- READWRITE(hashMerkleRoot);
- READWRITE(nTime);
- READWRITE(nBits);
- READWRITE(nNonce);
- }
+ SERIALIZE_METHODS(CBlockHeader, obj) { READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce); }
void SetNull()
{
@@ -89,12 +79,10 @@ public:
*(static_cast<CBlockHeader*>(this)) = header;
}
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITEAS(CBlockHeader, *this);
- READWRITE(vtx);
+ SERIALIZE_METHODS(CBlock, obj)
+ {
+ READWRITEAS(CBlockHeader, obj);
+ READWRITE(obj.vtx);
}
void SetNull()
@@ -131,14 +119,12 @@ struct CBlockLocator
explicit CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
+ SERIALIZE_METHODS(CBlockLocator, obj)
+ {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
- READWRITE(vHave);
+ READWRITE(obj.vHave);
}
void SetNull()
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 58b3e8aedc..4514db578a 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -26,13 +26,7 @@ public:
COutPoint(): n(NULL_INDEX) { }
COutPoint(const uint256& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { }
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(hash);
- READWRITE(n);
- }
+ SERIALIZE_METHODS(COutPoint, obj) { READWRITE(obj.hash, obj.n); }
void SetNull() { hash.SetNull(); n = NULL_INDEX; }
bool IsNull() const { return (hash.IsNull() && n == NULL_INDEX); }
@@ -103,14 +97,7 @@ public:
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(prevout);
- READWRITE(scriptSig);
- READWRITE(nSequence);
- }
+ SERIALIZE_METHODS(CTxIn, obj) { READWRITE(obj.prevout, obj.scriptSig, obj.nSequence); }
friend bool operator==(const CTxIn& a, const CTxIn& b)
{
@@ -143,13 +130,7 @@ public:
CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(nValue);
- READWRITE(scriptPubKey);
- }
+ SERIALIZE_METHODS(CTxOut, obj) { READWRITE(obj.nValue, obj.scriptPubKey); }
void SetNull()
{
diff --git a/src/protocol.h b/src/protocol.h
index dfcb0e0660..0bf9f1d7b5 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -46,16 +46,7 @@ public:
std::string GetCommand() const;
bool IsValid(const MessageStartChars& messageStart) const;
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action)
- {
- READWRITE(pchMessageStart);
- READWRITE(pchCommand);
- READWRITE(nMessageSize);
- READWRITE(pchChecksum);
- }
+ SERIALIZE_METHODS(CMessageHeader, obj) { READWRITE(obj.pchMessageStart, obj.pchCommand, obj.nMessageSize, obj.pchChecksum); }
char pchMessageStart[MESSAGE_START_SIZE];
char pchCommand[COMMAND_SIZE];
@@ -74,100 +65,100 @@ namespace NetMsgType {
* receiving node at the beginning of a connection.
* @see https://bitcoin.org/en/developer-reference#version
*/
-extern const char *VERSION;
+extern const char* VERSION;
/**
* The verack message acknowledges a previously-received version message,
* informing the connecting node that it can begin to send other messages.
* @see https://bitcoin.org/en/developer-reference#verack
*/
-extern const char *VERACK;
+extern const char* VERACK;
/**
* The addr (IP address) message relays connection information for peers on the
* network.
* @see https://bitcoin.org/en/developer-reference#addr
*/
-extern const char *ADDR;
+extern const char* ADDR;
/**
* The inv message (inventory message) transmits one or more inventories of
* objects known to the transmitting peer.
* @see https://bitcoin.org/en/developer-reference#inv
*/
-extern const char *INV;
+extern const char* INV;
/**
* The getdata message requests one or more data objects from another node.
* @see https://bitcoin.org/en/developer-reference#getdata
*/
-extern const char *GETDATA;
+extern const char* GETDATA;
/**
* The merkleblock message is a reply to a getdata message which requested a
* block using the inventory type MSG_MERKLEBLOCK.
* @since protocol version 70001 as described by BIP37.
* @see https://bitcoin.org/en/developer-reference#merkleblock
*/
-extern const char *MERKLEBLOCK;
+extern const char* MERKLEBLOCK;
/**
* The getblocks message requests an inv message that provides block header
* hashes starting from a particular point in the block chain.
* @see https://bitcoin.org/en/developer-reference#getblocks
*/
-extern const char *GETBLOCKS;
+extern const char* GETBLOCKS;
/**
* The getheaders message requests a headers message that provides block
* headers starting from a particular point in the block chain.
* @since protocol version 31800.
* @see https://bitcoin.org/en/developer-reference#getheaders
*/
-extern const char *GETHEADERS;
+extern const char* GETHEADERS;
/**
* The tx message transmits a single transaction.
* @see https://bitcoin.org/en/developer-reference#tx
*/
-extern const char *TX;
+extern const char* TX;
/**
* The headers message sends one or more block headers to a node which
* previously requested certain headers with a getheaders message.
* @since protocol version 31800.
* @see https://bitcoin.org/en/developer-reference#headers
*/
-extern const char *HEADERS;
+extern const char* HEADERS;
/**
* The block message transmits a single serialized block.
* @see https://bitcoin.org/en/developer-reference#block
*/
-extern const char *BLOCK;
+extern const char* BLOCK;
/**
* The getaddr message requests an addr message from the receiving node,
* preferably one with lots of IP addresses of other receiving nodes.
* @see https://bitcoin.org/en/developer-reference#getaddr
*/
-extern const char *GETADDR;
+extern const char* GETADDR;
/**
* The mempool message requests the TXIDs of transactions that the receiving
* node has verified as valid but which have not yet appeared in a block.
* @since protocol version 60002.
* @see https://bitcoin.org/en/developer-reference#mempool
*/
-extern const char *MEMPOOL;
+extern const char* MEMPOOL;
/**
* The ping message is sent periodically to help confirm that the receiving
* peer is still connected.
* @see https://bitcoin.org/en/developer-reference#ping
*/
-extern const char *PING;
+extern const char* PING;
/**
* The pong message replies to a ping message, proving to the pinging node that
* the ponging node is still alive.
* @since protocol version 60001 as described by BIP31.
* @see https://bitcoin.org/en/developer-reference#pong
*/
-extern const char *PONG;
+extern const char* PONG;
/**
* The notfound message is a reply to a getdata message which requested an
* object the receiving node does not have available for relay.
* @since protocol version 70001.
* @see https://bitcoin.org/en/developer-reference#notfound
*/
-extern const char *NOTFOUND;
+extern const char* NOTFOUND;
/**
* The filterload message tells the receiving peer to filter all relayed
* transactions and requested merkle blocks through the provided filter.
@@ -176,7 +167,7 @@ extern const char *NOTFOUND;
* 70011 as described by BIP111.
* @see https://bitcoin.org/en/developer-reference#filterload
*/
-extern const char *FILTERLOAD;
+extern const char* FILTERLOAD;
/**
* The filteradd message tells the receiving peer to add a single element to a
* previously-set bloom filter, such as a new public key.
@@ -185,7 +176,7 @@ extern const char *FILTERLOAD;
* 70011 as described by BIP111.
* @see https://bitcoin.org/en/developer-reference#filteradd
*/
-extern const char *FILTERADD;
+extern const char* FILTERADD;
/**
* The filterclear message tells the receiving peer to remove a previously-set
* bloom filter.
@@ -194,20 +185,20 @@ extern const char *FILTERADD;
* 70011 as described by BIP111.
* @see https://bitcoin.org/en/developer-reference#filterclear
*/
-extern const char *FILTERCLEAR;
+extern const char* FILTERCLEAR;
/**
* Indicates that a node prefers to receive new block announcements via a
* "headers" message rather than an "inv".
* @since protocol version 70012 as described by BIP130.
* @see https://bitcoin.org/en/developer-reference#sendheaders
*/
-extern const char *SENDHEADERS;
+extern const char* SENDHEADERS;
/**
* The feefilter message tells the receiving peer not to inv us any txs
* which do not meet the specified min fee rate.
* @since protocol version 70013 as described by BIP133
*/
-extern const char *FEEFILTER;
+extern const char* FEEFILTER;
/**
* Contains a 1-byte bool and 8-byte LE version number.
* Indicates that a node is willing to provide blocks via "cmpctblock" messages.
@@ -215,43 +206,43 @@ extern const char *FEEFILTER;
* "cmpctblock" message rather than an "inv", depending on message contents.
* @since protocol version 70014 as described by BIP 152
*/
-extern const char *SENDCMPCT;
+extern const char* SENDCMPCT;
/**
* Contains a CBlockHeaderAndShortTxIDs object - providing a header and
* list of "short txids".
* @since protocol version 70014 as described by BIP 152
*/
-extern const char *CMPCTBLOCK;
+extern const char* CMPCTBLOCK;
/**
* Contains a BlockTransactionsRequest
* Peer should respond with "blocktxn" message.
* @since protocol version 70014 as described by BIP 152
*/
-extern const char *GETBLOCKTXN;
+extern const char* GETBLOCKTXN;
/**
* Contains a BlockTransactions.
* Sent in response to a "getblocktxn" message.
* @since protocol version 70014 as described by BIP 152
*/
-extern const char *BLOCKTXN;
+extern const char* BLOCKTXN;
/**
* getcfcheckpt requests evenly spaced compact filter headers, enabling
* parallelized download and validation of the headers between them.
* Only available with service bit NODE_COMPACT_FILTERS as described by
* BIP 157 & 158.
*/
-extern const char *GETCFCHECKPT;
+extern const char* GETCFCHECKPT;
/**
* cfcheckpt is a response to a getcfcheckpt request containing a vector of
* evenly spaced filter headers for blocks on the requested chain.
* Only available with service bit NODE_COMPACT_FILTERS as described by
* BIP 157 & 158.
*/
-extern const char *CFCHECKPT;
-};
+extern const char* CFCHECKPT;
+}; // namespace NetMsgType
/* Get a vector of all valid message types (see above) */
-const std::vector<std::string> &getAllNetMessageTypes();
+const std::vector<std::string>& getAllNetMessageTypes();
/** nServices flags */
enum ServiceFlags : uint64_t {
@@ -320,7 +311,8 @@ void SetServiceFlagsIBDCache(bool status);
* == GetDesirableServiceFlags(services), ie determines whether the given
* set of service flags are sufficient for a peer to be "relevant".
*/
-static inline bool HasAllDesirableServiceFlags(ServiceFlags services) {
+static inline bool HasAllDesirableServiceFlags(ServiceFlags services)
+{
return !(GetDesirableServiceFlags(services) & (~services));
}
@@ -328,7 +320,8 @@ static inline bool HasAllDesirableServiceFlags(ServiceFlags services) {
* Checks if a peer with the given service flags may be capable of having a
* robust address-storage DB.
*/
-static inline bool MayHaveUsefulAddressDB(ServiceFlags services) {
+static inline bool MayHaveUsefulAddressDB(ServiceFlags services)
+{
return (services & NODE_NETWORK) || (services & NODE_NETWORK_LIMITED);
}
@@ -341,27 +334,21 @@ public:
void Init();
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action)
+ SERIALIZE_METHODS(CAddress, obj)
{
- if (ser_action.ForRead())
- Init();
+ SER_READ(obj, obj.Init());
int nVersion = s.GetVersion();
- if (s.GetType() & SER_DISK)
+ if (s.GetType() & SER_DISK) {
READWRITE(nVersion);
+ }
if ((s.GetType() & SER_DISK) ||
- (nVersion >= CADDR_TIME_VERSION && !(s.GetType() & SER_GETHASH)))
- READWRITE(nTime);
- uint64_t nServicesInt = nServices;
- READWRITE(nServicesInt);
- nServices = static_cast<ServiceFlags>(nServicesInt);
- READWRITEAS(CService, *this);
+ (nVersion >= CADDR_TIME_VERSION && !(s.GetType() & SER_GETHASH))) {
+ READWRITE(obj.nTime);
+ }
+ READWRITE(Using<CustomUintFormatter<8>>(obj.nServices));
+ READWRITEAS(CService, obj);
}
- // TODO: make private (improves encapsulation)
-public:
ServiceFlags nServices;
// disk and network only
@@ -370,20 +357,19 @@ public:
/** getdata message type flags */
const uint32_t MSG_WITNESS_FLAG = 1 << 30;
-const uint32_t MSG_TYPE_MASK = 0xffffffff >> 2;
+const uint32_t MSG_TYPE_MASK = 0xffffffff >> 2;
/** getdata / inv message types.
* These numbers are defined by the protocol. When adding a new value, be sure
* to mention it in the respective BIP.
*/
-enum GetDataMsg
-{
+enum GetDataMsg {
UNDEFINED = 0,
MSG_TX = 1,
MSG_BLOCK = 2,
// The following can only occur in getdata. Invs always use TX or BLOCK.
- MSG_FILTERED_BLOCK = 3, //!< Defined in BIP37
- MSG_CMPCT_BLOCK = 4, //!< Defined in BIP152
+ MSG_FILTERED_BLOCK = 3, //!< Defined in BIP37
+ MSG_CMPCT_BLOCK = 4, //!< Defined in BIP152
MSG_WITNESS_BLOCK = MSG_BLOCK | MSG_WITNESS_FLAG, //!< Defined in BIP144
MSG_WITNESS_TX = MSG_TX | MSG_WITNESS_FLAG, //!< Defined in BIP144
MSG_FILTERED_WITNESS_BLOCK = MSG_FILTERED_BLOCK | MSG_WITNESS_FLAG,
@@ -396,21 +382,13 @@ public:
CInv();
CInv(int typeIn, const uint256& hashIn);
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action)
- {
- READWRITE(type);
- READWRITE(hash);
- }
+ SERIALIZE_METHODS(CInv, obj) { READWRITE(obj.type, obj.hash); }
friend bool operator<(const CInv& a, const CInv& b);
std::string GetCommand() const;
std::string ToString() const;
-public:
int type;
uint256 hash;
};
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 8939b566f7..6fdf6322ff 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -34,6 +34,7 @@
#include <uint256.h>
#include <util/system.h>
#include <util/threadnames.h>
+#include <validation.h>
#include <memory>
@@ -61,6 +62,7 @@ Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
// Declare meta types used for QMetaObject::invokeMethod
Q_DECLARE_METATYPE(bool*)
Q_DECLARE_METATYPE(CAmount)
+Q_DECLARE_METATYPE(SynchronizationState)
Q_DECLARE_METATYPE(uint256)
static QString GetLangTerritory()
@@ -435,6 +437,7 @@ int GuiMain(int argc, char* argv[])
// Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection
qRegisterMetaType<bool*>();
+ qRegisterMetaType<SynchronizationState>();
#ifdef ENABLE_WALLET
qRegisterMetaType<WalletModel*>();
#endif
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 3a1fdc22a6..4de4850903 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -37,6 +37,7 @@
#include <ui_interface.h>
#include <util/system.h>
#include <util/translation.h>
+#include <validation.h>
#include <QAction>
#include <QApplication>
@@ -567,7 +568,7 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive);
modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime()));
- setNumBlocks(m_node.getNumBlocks(), QDateTime::fromTime_t(m_node.getLastBlockTime()), m_node.getVerificationProgress(), false);
+ setNumBlocks(m_node.getNumBlocks(), QDateTime::fromTime_t(m_node.getLastBlockTime()), m_node.getVerificationProgress(), false, SynchronizationState::INIT_DOWNLOAD);
connect(_clientModel, &ClientModel::numBlocksChanged, this, &BitcoinGUI::setNumBlocks);
// Receive and report messages from client model
@@ -926,11 +927,15 @@ void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab)
dlg.exec();
}
-void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
+void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state)
{
// Disabling macOS App Nap on initial sync, disk and reindex operations.
#ifdef Q_OS_MAC
- (m_node.isInitialBlockDownload() || m_node.getReindex() || m_node.getImporting()) ? m_app_nap_inhibitor->disableAppNap() : m_app_nap_inhibitor->enableAppNap();
+ if (sync_state == SynchronizationState::POST_INIT) {
+ m_app_nap_inhibitor->enableAppNap();
+ } else {
+ m_app_nap_inhibitor->disableAppNap();
+ }
#endif
if (modalOverlay)
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 6733585f68..82a2db9ba2 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -38,6 +38,7 @@ class WalletFrame;
class WalletModel;
class HelpMessageDialog;
class ModalOverlay;
+enum class SynchronizationState;
namespace interfaces {
class Handler;
@@ -213,7 +214,7 @@ public Q_SLOTS:
/** Set network state shown in the UI */
void setNetworkActive(bool networkActive);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state);
/** Notify the user of an event from the core network or transaction handling code.
@param[in] title the message box / notification title
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index b94fcc9865..159b0d3df3 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -15,6 +15,7 @@
#include <net.h>
#include <netbase.h>
#include <util/system.h>
+#include <validation.h>
#include <stdint.h>
@@ -234,17 +235,8 @@ static void BannedListChanged(ClientModel *clientmodel)
assert(invoked);
}
-static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int height, int64_t blockTime, double verificationProgress, bool fHeader)
+static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_state, int height, int64_t blockTime, double verificationProgress, bool fHeader)
{
- // lock free async UI updates in case we have a new block tip
- // during initial sync, only update the UI if the last update
- // was > 250ms (MODEL_UPDATE_DELAY) ago
- int64_t now = 0;
- if (initialSync)
- now = GetTimeMillis();
-
- int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
-
if (fHeader) {
// cache best headers time and height to reduce future cs_main locks
clientmodel->cachedBestHeaderHeight = height;
@@ -253,17 +245,22 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig
clientmodel->m_cached_num_blocks = height;
}
- // During initial sync, block notifications, and header notifications from reindexing are both throttled.
- if (!initialSync || (fHeader && !clientmodel->node().getReindex()) || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
- //pass an async signal to the UI thread
- bool invoked = QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
- Q_ARG(int, height),
- Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)),
- Q_ARG(double, verificationProgress),
- Q_ARG(bool, fHeader));
- assert(invoked);
- nLastUpdateNotification = now;
+ // Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
+ const bool throttle = (sync_state != SynchronizationState::POST_INIT && !fHeader) || sync_state == SynchronizationState::INIT_REINDEX;
+ const int64_t now = throttle ? GetTimeMillis() : 0;
+ int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
+ if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
+ return;
}
+
+ bool invoked = QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
+ Q_ARG(int, height),
+ Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)),
+ Q_ARG(double, verificationProgress),
+ Q_ARG(bool, fHeader),
+ Q_ARG(SynchronizationState, sync_state));
+ assert(invoked);
+ nLastUpdateNotification = now;
}
void ClientModel::subscribeToCoreSignals()
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 7ac4120a8f..ace77f5972 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -12,10 +12,10 @@
#include <memory>
class BanTableModel;
+class CBlockIndex;
class OptionsModel;
class PeerTableModel;
-
-class CBlockIndex;
+enum class SynchronizationState;
namespace interfaces {
class Handler;
@@ -100,7 +100,7 @@ private:
Q_SIGNALS:
void numConnectionsChanged(int count);
- void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, bool header);
+ void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state);
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes);
void networkActiveChanged(bool networkActive);
void alertsChanged(const QString &warnings);
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 18554aef1f..7a15503228 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -664,7 +664,7 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat
QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(parent);
- TransactionRecord *data = priv->index(walletModel->wallet(), walletModel->clientModel().getNumBlocks(), row);
+ TransactionRecord *data = priv->index(walletModel->wallet(), walletModel->getNumBlocks(), row);
if(data)
{
return createIndex(row, column, data);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 70ee7f4917..1084ec9725 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -39,14 +39,15 @@
WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel& client_model, const PlatformStyle *platformStyle, QObject *parent) :
QObject(parent),
m_wallet(std::move(wallet)),
- m_client_model(client_model),
+ m_client_model(&client_model),
m_node(client_model.node()),
optionsModel(client_model.getOptionsModel()),
addressTableModel(nullptr),
transactionTableModel(nullptr),
recentRequestsTableModel(nullptr),
cachedEncryptionStatus(Unencrypted),
- cachedNumBlocks(0)
+ cachedNumBlocks(0),
+ timer(new QTimer(this))
{
fHaveWatchOnly = m_wallet->haveWatchOnly();
addressTableModel = new AddressTableModel(this);
@@ -64,11 +65,16 @@ WalletModel::~WalletModel()
void WalletModel::startPollBalance()
{
// This timer will be fired repeatedly to update the balance
- QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &WalletModel::pollBalanceChanged);
timer->start(MODEL_UPDATE_DELAY);
}
+void WalletModel::setClientModel(ClientModel* client_model)
+{
+ m_client_model = client_model;
+ if (!m_client_model) timer->stop();
+}
+
void WalletModel::updateStatus()
{
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
@@ -80,24 +86,31 @@ void WalletModel::updateStatus()
void WalletModel::pollBalanceChanged()
{
+ // Avoid recomputing wallet balances unless a TransactionChanged or
+ // BlockTip notification was received.
+ if (!fForceCheckBalanceChanged && cachedNumBlocks == m_client_model->getNumBlocks()) return;
+
// Try to get balances and return early if locks can't be acquired. This
// avoids the GUI from getting stuck on periodical polls if the core is
// holding the locks for a longer time - for example, during a wallet
// rescan.
interfaces::WalletBalances new_balances;
int numBlocks = -1;
- if (!m_wallet->tryGetBalances(new_balances, numBlocks, fForceCheckBalanceChanged, cachedNumBlocks)) {
+ if (!m_wallet->tryGetBalances(new_balances, numBlocks)) {
return;
}
- fForceCheckBalanceChanged = false;
+ if(fForceCheckBalanceChanged || numBlocks != cachedNumBlocks)
+ {
+ fForceCheckBalanceChanged = false;
- // Balance and number of transactions might have changed
- cachedNumBlocks = numBlocks;
+ // Balance and number of transactions might have changed
+ cachedNumBlocks = numBlocks;
- checkBalanceChanged(new_balances);
- if(transactionTableModel)
- transactionTableModel->updateConfirmations();
+ checkBalanceChanged(new_balances);
+ if(transactionTableModel)
+ transactionTableModel->updateConfirmations();
+ }
}
void WalletModel::checkBalanceChanged(const interfaces::WalletBalances& new_balances)
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 07004b7c6b..23232ec66b 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -144,7 +144,8 @@ public:
interfaces::Node& node() const { return m_node; }
interfaces::Wallet& wallet() const { return *m_wallet; }
- ClientModel& clientModel() const { return m_client_model; }
+ void setClientModel(ClientModel* client_model);
+ int getNumBlocks() const { return cachedNumBlocks; }
QString getWalletName() const;
QString getDisplayName() const;
@@ -161,7 +162,7 @@ private:
std::unique_ptr<interfaces::Handler> m_handler_show_progress;
std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed;
std::unique_ptr<interfaces::Handler> m_handler_can_get_addrs_changed;
- ClientModel& m_client_model;
+ ClientModel* m_client_model;
interfaces::Node& m_node;
bool fHaveWatchOnly;
@@ -179,6 +180,7 @@ private:
interfaces::WalletBalances m_cached_balances;
EncryptionStatus cachedEncryptionStatus;
int cachedNumBlocks;
+ QTimer* timer;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 5d9b420df7..c4e607990a 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -97,6 +97,7 @@ void WalletView::setClientModel(ClientModel *_clientModel)
overviewPage->setClientModel(_clientModel);
sendCoinsPage->setClientModel(_clientModel);
+ if (walletModel) walletModel->setClientModel(_clientModel);
}
void WalletView::setWalletModel(WalletModel *_walletModel)
diff --git a/src/random.cpp b/src/random.cpp
index 5b8782d1ce..9c9a35709a 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -14,16 +14,14 @@
#include <wincrypt.h>
#endif
#include <logging.h> // for LogPrintf()
+#include <randomenv.h>
+#include <support/allocators/secure.h>
#include <sync.h> // for Mutex
#include <util/time.h> // for GetTimeMicros()
#include <stdlib.h>
#include <thread>
-#include <randomenv.h>
-
-#include <support/allocators/secure.h>
-
#ifndef WIN32
#include <fcntl.h>
#include <sys/time.h>
@@ -590,16 +588,6 @@ uint64_t GetRand(uint64_t nMax) noexcept
return FastRandomContext(g_mock_deterministic_tests).randrange(nMax);
}
-std::chrono::microseconds GetRandMicros(std::chrono::microseconds duration_max) noexcept
-{
- return std::chrono::microseconds{GetRand(duration_max.count())};
-}
-
-std::chrono::milliseconds GetRandMillis(std::chrono::milliseconds duration_max) noexcept
-{
- return std::chrono::milliseconds{GetRand(duration_max.count())};
-}
-
int GetRandInt(int nMax) noexcept
{
return GetRand(nMax);
diff --git a/src/random.h b/src/random.h
index 690125079b..0c6dc24983 100644
--- a/src/random.h
+++ b/src/random.h
@@ -67,9 +67,21 @@
* Thread-safe.
*/
void GetRandBytes(unsigned char* buf, int num) noexcept;
+/** Generate a uniform random integer in the range [0..range). Precondition: range > 0 */
uint64_t GetRand(uint64_t nMax) noexcept;
-std::chrono::microseconds GetRandMicros(std::chrono::microseconds duration_max) noexcept;
-std::chrono::milliseconds GetRandMillis(std::chrono::milliseconds duration_max) noexcept;
+/** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */
+template <typename D>
+D GetRandomDuration(typename std::common_type<D>::type max) noexcept
+// Having the compiler infer the template argument from the function argument
+// is dangerous, because the desired return value generally has a different
+// type than the function argument. So std::common_type is used to force the
+// call site to specify the type of the return value.
+{
+ assert(max.count() > 0);
+ return D{GetRand(max.count())};
+};
+constexpr auto GetRandMicros = GetRandomDuration<std::chrono::microseconds>;
+constexpr auto GetRandMillis = GetRandomDuration<std::chrono::milliseconds>;
int GetRandInt(int nMax) noexcept;
uint256 GetRandHash() noexcept;
diff --git a/src/rest.cpp b/src/rest.cpp
index 02b35f92ab..cde8b472d3 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -50,18 +50,13 @@ struct CCoin {
uint32_t nHeight;
CTxOut out;
- ADD_SERIALIZE_METHODS;
-
CCoin() : nHeight(0) {}
explicit CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action)
+ SERIALIZE_METHODS(CCoin, obj)
{
uint32_t nTxVerDummy = 0;
- READWRITE(nTxVerDummy);
- READWRITE(nHeight);
- READWRITE(out);
+ READWRITE(nTxVerDummy, obj.nHeight, obj.out);
}
};
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index c04e4fc77b..3c5fd565e3 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -214,7 +214,7 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
return ::ChainActive().Tip()->GetBlockHash().GetHex();
}
-void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
+void RPCNotifyBlockChange(const CBlockIndex* pindex)
{
if(pindex) {
std::lock_guard<std::mutex> lock(cs_blockchange);
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 2417340d64..453d0bc650 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -33,7 +33,7 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
double GetDifficulty(const CBlockIndex* blockindex);
/** Callback for when block tip changed. */
-void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
+void RPCNotifyBlockChange(const CBlockIndex*);
/** Block description to JSON */
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false) LOCKS_EXCLUDED(cs_main);
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 28b3582866..bcaed1ef88 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -788,6 +788,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
result.pushKV("capabilities", aCaps);
UniValue aRules(UniValue::VARR);
+ aRules.push_back("csv");
+ if (!fPreSegWit) aRules.push_back("!segwit");
UniValue vbavailable(UniValue::VOBJ);
for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
Consensus::DeploymentPos pos = Consensus::DeploymentPos(j);
@@ -875,7 +877,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
return result;
}
-class submitblock_StateCatcher : public CValidationInterface
+class submitblock_StateCatcher final : public CValidationInterface
{
public:
uint256 hash;
@@ -943,17 +945,17 @@ static UniValue submitblock(const JSONRPCRequest& request)
}
bool new_block;
- submitblock_StateCatcher sc(block.GetHash());
- RegisterValidationInterface(&sc);
+ auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
+ RegisterSharedValidationInterface(sc);
bool accepted = ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
- UnregisterValidationInterface(&sc);
+ UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
return "duplicate";
}
- if (!sc.found) {
+ if (!sc->found) {
return "inconclusive";
}
- return BIP22ValidationResult(sc.state);
+ return BIP22ValidationResult(sc->state);
}
static UniValue submitheader(const JSONRPCRequest& request)
diff --git a/src/script/keyorigin.h b/src/script/keyorigin.h
index 467605ce46..a318ff0f9d 100644
--- a/src/script/keyorigin.h
+++ b/src/script/keyorigin.h
@@ -18,13 +18,7 @@ struct KeyOriginInfo
return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path;
}
- ADD_SERIALIZE_METHODS;
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action)
- {
- READWRITE(fingerprint);
- READWRITE(path);
- }
+ SERIALIZE_METHODS(KeyOriginInfo, obj) { READWRITE(obj.fingerprint, obj.path); }
void clear()
{
diff --git a/src/script/script.h b/src/script/script.h
index 773ffbb985..b61581767f 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -412,12 +412,7 @@ public:
CScript(std::vector<unsigned char>::const_iterator pbegin, std::vector<unsigned char>::const_iterator pend) : CScriptBase(pbegin, pend) { }
CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { }
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITEAS(CScriptBase, *this);
- }
+ SERIALIZE_METHODS(CScript, obj) { READWRITEAS(CScriptBase, obj); }
explicit CScript(int64_t b) { operator<<(b); }
explicit CScript(opcodetype b) { operator<<(b); }
diff --git a/src/serialize.h b/src/serialize.h
index fe53eeed31..af75c50ff9 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -190,6 +190,8 @@ template<typename X> const X& ReadWriteAsHelper(const X& x) { return x; }
#define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__))
#define READWRITEAS(type, obj) (::SerReadWriteMany(s, ser_action, ReadWriteAsHelper<type>(obj)))
+#define SER_READ(obj, code) ::SerRead(s, ser_action, obj, [&](Stream& s, typename std::remove_const<Type>::type& obj) { code; })
+#define SER_WRITE(obj, code) ::SerWrite(s, ser_action, obj, [&](Stream& s, const Type& obj) { code; })
/**
* Implement three methods for serializable objects. These are actually wrappers over
@@ -518,7 +520,16 @@ struct VarIntFormatter
}
};
-template<int Bytes>
+/** Serialization wrapper class for custom integers and enums.
+ *
+ * It permits specifying the serialized size (1 to 8 bytes) and endianness.
+ *
+ * Use the big endian mode for values that are stored in memory in native
+ * byte order, but serialized in big endian notation. This is only intended
+ * to implement serializers that are compatible with existing formats, and
+ * its use is not recommended for new data structures.
+ */
+template<int Bytes, bool BigEndian = false>
struct CustomUintFormatter
{
static_assert(Bytes > 0 && Bytes <= 8, "CustomUintFormatter Bytes out of range");
@@ -527,52 +538,31 @@ struct CustomUintFormatter
template <typename Stream, typename I> void Ser(Stream& s, I v)
{
if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range");
- uint64_t raw = htole64(v);
- s.write((const char*)&raw, Bytes);
+ if (BigEndian) {
+ uint64_t raw = htobe64(v);
+ s.write(((const char*)&raw) + 8 - Bytes, Bytes);
+ } else {
+ uint64_t raw = htole64(v);
+ s.write((const char*)&raw, Bytes);
+ }
}
template <typename Stream, typename I> void Unser(Stream& s, I& v)
{
- static_assert(std::numeric_limits<I>::max() >= MAX && std::numeric_limits<I>::min() <= 0, "CustomUintFormatter type too small");
+ using U = typename std::conditional<std::is_enum<I>::value, std::underlying_type<I>, std::common_type<I>>::type::type;
+ static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");
uint64_t raw = 0;
- s.read((char*)&raw, Bytes);
- v = le64toh(raw);
+ if (BigEndian) {
+ s.read(((char*)&raw) + 8 - Bytes, Bytes);
+ v = static_cast<I>(be64toh(raw));
+ } else {
+ s.read((char*)&raw, Bytes);
+ v = static_cast<I>(le64toh(raw));
+ }
}
};
-/** Serialization wrapper class for big-endian integers.
- *
- * Use this wrapper around integer types that are stored in memory in native
- * byte order, but serialized in big endian notation. This is only intended
- * to implement serializers that are compatible with existing formats, and
- * its use is not recommended for new data structures.
- *
- * Only 16-bit types are supported for now.
- */
-template<typename I>
-class BigEndian
-{
-protected:
- I& m_val;
-public:
- explicit BigEndian(I& val) : m_val(val)
- {
- static_assert(std::is_unsigned<I>::value, "BigEndian type must be unsigned integer");
- static_assert(sizeof(I) == 2 && std::numeric_limits<I>::min() == 0 && std::numeric_limits<I>::max() == std::numeric_limits<uint16_t>::max(), "Unsupported BigEndian size");
- }
-
- template<typename Stream>
- void Serialize(Stream& s) const
- {
- ser_writedata16be(s, m_val);
- }
-
- template<typename Stream>
- void Unserialize(Stream& s)
- {
- m_val = ser_readdata16be(s);
- }
-};
+template<int Bytes> using BigEndianFormatter = CustomUintFormatter<Bytes, true>;
/** Formatter for integers in CompactSize format. */
struct CompactSizeFormatter
@@ -626,9 +616,6 @@ public:
}
};
-template<typename I>
-BigEndian<I> WrapBigEndian(I& n) { return BigEndian<I>(n); }
-
/** Formatter to serialize/deserialize vector elements using another formatter
*
* Example:
@@ -1124,6 +1111,28 @@ inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&&
::UnserializeMany(s, args...);
}
+template<typename Stream, typename Type, typename Fn>
+inline void SerRead(Stream& s, CSerActionSerialize ser_action, Type&&, Fn&&)
+{
+}
+
+template<typename Stream, typename Type, typename Fn>
+inline void SerRead(Stream& s, CSerActionUnserialize ser_action, Type&& obj, Fn&& fn)
+{
+ fn(s, std::forward<Type>(obj));
+}
+
+template<typename Stream, typename Type, typename Fn>
+inline void SerWrite(Stream& s, CSerActionSerialize ser_action, Type&& obj, Fn&& fn)
+{
+ fn(s, std::forward<Type>(obj));
+}
+
+template<typename Stream, typename Type, typename Fn>
+inline void SerWrite(Stream& s, CSerActionUnserialize ser_action, Type&&, Fn&&)
+{
+}
+
template<typename I>
inline void WriteVarInt(CSizeComputer &s, I n)
{
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 8694891a51..14cf1a4a76 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -132,24 +132,7 @@ public:
return base.GetShortID(txhash);
}
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(header);
- READWRITE(nonce);
- size_t shorttxids_size = shorttxids.size();
- READWRITE(VARINT(shorttxids_size));
- shorttxids.resize(shorttxids_size);
- for (size_t i = 0; i < shorttxids.size(); i++) {
- uint32_t lsb = shorttxids[i] & 0xffffffff;
- uint16_t msb = (shorttxids[i] >> 32) & 0xffff;
- READWRITE(lsb);
- READWRITE(msb);
- shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb);
- }
- READWRITE(prefilledtxn);
- }
+ SERIALIZE_METHODS(TestHeaderAndShortIDs, obj) { READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<CBlockHeaderAndShortTxIDs::SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn); }
};
BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index c378546e8b..3d802cbeb3 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -331,24 +331,26 @@ struct StringContentsSerializer {
}
StringContentsSerializer& operator+=(const StringContentsSerializer& s) { return *this += s.str; }
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- if (ser_action.ForRead()) {
- str.clear();
- char c = 0;
- while (true) {
- try {
- READWRITE(c);
- str.push_back(c);
- } catch (const std::ios_base::failure&) {
- break;
- }
+ template<typename Stream>
+ void Serialize(Stream& s) const
+ {
+ for (size_t i = 0; i < str.size(); i++) {
+ s << str[i];
+ }
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream& s)
+ {
+ str.clear();
+ char c = 0;
+ while (true) {
+ try {
+ s >> c;
+ str.push_back(c);
+ } catch (const std::ios_base::failure&) {
+ break;
}
- } else {
- for (size_t i = 0; i < str.size(); i++)
- READWRITE(str[i]);
}
}
};
diff --git a/src/test/fuzz/addrdb.cpp b/src/test/fuzz/addrdb.cpp
index f21ff3fac3..524cea83fe 100644
--- a/src/test/fuzz/addrdb.cpp
+++ b/src/test/fuzz/addrdb.cpp
@@ -3,13 +3,13 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <addrdb.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cassert>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -30,7 +30,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
})};
break;
case 2: {
- const Optional<CBanEntry> ban_entry = ConsumeDeserializable<CBanEntry>(fuzzed_data_provider);
+ const std::optional<CBanEntry> ban_entry = ConsumeDeserializable<CBanEntry>(fuzzed_data_provider);
if (ban_entry) {
return *ban_entry;
}
diff --git a/src/test/fuzz/asmap.cpp b/src/test/fuzz/asmap.cpp
index ea56277eac..40ca01bd9f 100644
--- a/src/test/fuzz/asmap.cpp
+++ b/src/test/fuzz/asmap.cpp
@@ -23,8 +23,8 @@ static const std::vector<bool> IPV4_PREFIX_ASMAP = {
true, true, false, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, // Match 0x00
true, true, false, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, // Match 0x00
true, true, false, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, // Match 0x00
- true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, // Match 0xFF
- true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true // Match 0xFF
+ true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, // Match 0xFF
+ true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true // Match 0xFF
};
void test_one_input(const std::vector<uint8_t>& buffer)
diff --git a/src/test/fuzz/asmap_direct.cpp b/src/test/fuzz/asmap_direct.cpp
index 6d8a65f5ab..2d21eff9d6 100644
--- a/src/test/fuzz/asmap_direct.cpp
+++ b/src/test/fuzz/asmap_direct.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/asmap.h>
#include <test/fuzz/fuzz.h>
+#include <util/asmap.h>
#include <cstdint>
#include <optional>
@@ -34,7 +34,9 @@ void test_one_input(const std::vector<uint8_t>& buffer)
if (SanityCheckASMap(asmap, buffer.size() - 1 - sep_pos)) {
// Verify that for valid asmaps, no prefix (except up to 7 zero padding bits) is valid.
std::vector<bool> asmap_prefix = asmap;
- while (!asmap_prefix.empty() && asmap_prefix.size() + 7 > asmap.size() && asmap_prefix.back() == false) asmap_prefix.pop_back();
+ while (!asmap_prefix.empty() && asmap_prefix.size() + 7 > asmap.size() && asmap_prefix.back() == false) {
+ asmap_prefix.pop_back();
+ }
while (!asmap_prefix.empty()) {
asmap_prefix.pop_back();
assert(!SanityCheckASMap(asmap_prefix, buffer.size() - 1 - sep_pos));
diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp
index f30fa03e0b..91bd34a251 100644
--- a/src/test/fuzz/block.cpp
+++ b/src/test/fuzz/block.cpp
@@ -38,12 +38,17 @@ void test_one_input(const std::vector<uint8_t>& buffer)
const Consensus::Params& consensus_params = Params().GetConsensus();
BlockValidationState validation_state_pow_and_merkle;
const bool valid_incl_pow_and_merkle = CheckBlock(block, validation_state_pow_and_merkle, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ true);
+ assert(validation_state_pow_and_merkle.IsValid() || validation_state_pow_and_merkle.IsInvalid() || validation_state_pow_and_merkle.IsError());
+ (void)validation_state_pow_and_merkle.Error("");
BlockValidationState validation_state_pow;
const bool valid_incl_pow = CheckBlock(block, validation_state_pow, consensus_params, /* fCheckPOW= */ true, /* fCheckMerkleRoot= */ false);
+ assert(validation_state_pow.IsValid() || validation_state_pow.IsInvalid() || validation_state_pow.IsError());
BlockValidationState validation_state_merkle;
const bool valid_incl_merkle = CheckBlock(block, validation_state_merkle, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ true);
+ assert(validation_state_merkle.IsValid() || validation_state_merkle.IsInvalid() || validation_state_merkle.IsError());
BlockValidationState validation_state_none;
const bool valid_incl_none = CheckBlock(block, validation_state_none, consensus_params, /* fCheckPOW= */ false, /* fCheckMerkleRoot= */ false);
+ assert(validation_state_none.IsValid() || validation_state_none.IsInvalid() || validation_state_none.IsError());
if (valid_incl_pow_and_merkle) {
assert(valid_incl_pow && valid_incl_merkle && valid_incl_none);
} else if (valid_incl_merkle || valid_incl_pow) {
diff --git a/src/test/fuzz/block_header.cpp b/src/test/fuzz/block_header.cpp
index 92dcccc0e1..09c2b4a951 100644
--- a/src/test/fuzz/block_header.cpp
+++ b/src/test/fuzz/block_header.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 <optional.h>
#include <primitives/block.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -11,13 +10,14 @@
#include <cassert>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- const Optional<CBlockHeader> block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider);
+ const std::optional<CBlockHeader> block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider);
if (!block_header) {
return;
}
@@ -38,4 +38,12 @@ void test_one_input(const std::vector<uint8_t>& buffer)
block.SetNull();
assert(block.GetBlockHeader().GetHash() == mut_block_header.GetHash());
}
+ {
+ std::optional<CBlockLocator> block_locator = ConsumeDeserializable<CBlockLocator>(fuzzed_data_provider);
+ if (block_locator) {
+ (void)block_locator->IsNull();
+ block_locator->SetNull();
+ assert(block_locator->IsNull());
+ }
+ }
}
diff --git a/src/test/fuzz/blockfilter.cpp b/src/test/fuzz/blockfilter.cpp
index be9320dcbf..7232325a20 100644
--- a/src/test/fuzz/blockfilter.cpp
+++ b/src/test/fuzz/blockfilter.cpp
@@ -3,19 +3,19 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <blockfilter.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- const Optional<BlockFilter> block_filter = ConsumeDeserializable<BlockFilter>(fuzzed_data_provider);
+ const std::optional<BlockFilter> block_filter = ConsumeDeserializable<BlockFilter>(fuzzed_data_provider);
if (!block_filter) {
return;
}
diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp
index 7039bf16c1..d955c71bc9 100644
--- a/src/test/fuzz/bloom_filter.cpp
+++ b/src/test/fuzz/bloom_filter.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bloom.h>
-#include <optional.h>
#include <primitives/transaction.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -12,6 +11,7 @@
#include <cassert>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -35,7 +35,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
break;
}
case 1: {
- const Optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
if (!out_point) {
break;
}
@@ -46,7 +46,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
break;
}
case 2: {
- const Optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
+ const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
if (!u256) {
break;
}
@@ -57,7 +57,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
break;
}
case 3: {
- const Optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ const std::optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (!mut_tx) {
break;
}
diff --git a/src/test/fuzz/chain.cpp b/src/test/fuzz/chain.cpp
index b322516cc7..47c71850ce 100644
--- a/src/test/fuzz/chain.cpp
+++ b/src/test/fuzz/chain.cpp
@@ -3,18 +3,18 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chain.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
+#include <optional>
#include <vector>
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- Optional<CDiskBlockIndex> disk_block_index = ConsumeDeserializable<CDiskBlockIndex>(fuzzed_data_provider);
+ std::optional<CDiskBlockIndex> disk_block_index = ConsumeDeserializable<CDiskBlockIndex>(fuzzed_data_provider);
if (!disk_block_index) {
return;
}
diff --git a/src/test/fuzz/checkqueue.cpp b/src/test/fuzz/checkqueue.cpp
index 2ed097b827..c69043bb6b 100644
--- a/src/test/fuzz/checkqueue.cpp
+++ b/src/test/fuzz/checkqueue.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <checkqueue.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
diff --git a/src/test/fuzz/cuckoocache.cpp b/src/test/fuzz/cuckoocache.cpp
index f674efe1b1..5b45aa79d8 100644
--- a/src/test/fuzz/cuckoocache.cpp
+++ b/src/test/fuzz/cuckoocache.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <cuckoocache.h>
-#include <optional.h>
#include <script/sigcache.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/fuzz/fees.cpp b/src/test/fuzz/fees.cpp
index f29acace23..ce8700befa 100644
--- a/src/test/fuzz/fees.cpp
+++ b/src/test/fuzz/fees.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <amount.h>
-#include <optional.h>
#include <policy/fees.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/fuzz/flatfile.cpp b/src/test/fuzz/flatfile.cpp
index a55de77df7..95dabb8bab 100644
--- a/src/test/fuzz/flatfile.cpp
+++ b/src/test/fuzz/flatfile.cpp
@@ -3,24 +3,24 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <flatfile.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cassert>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- Optional<FlatFilePos> flat_file_pos = ConsumeDeserializable<FlatFilePos>(fuzzed_data_provider);
+ std::optional<FlatFilePos> flat_file_pos = ConsumeDeserializable<FlatFilePos>(fuzzed_data_provider);
if (!flat_file_pos) {
return;
}
- Optional<FlatFilePos> another_flat_file_pos = ConsumeDeserializable<FlatFilePos>(fuzzed_data_provider);
+ std::optional<FlatFilePos> another_flat_file_pos = ConsumeDeserializable<FlatFilePos>(fuzzed_data_provider);
if (another_flat_file_pos) {
assert((*flat_file_pos == *another_flat_file_pos) != (*flat_file_pos != *another_flat_file_pos));
}
diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp
index 3e20416116..a9f450b0c4 100644
--- a/src/test/fuzz/golomb_rice.cpp
+++ b/src/test/fuzz/golomb_rice.cpp
@@ -5,8 +5,8 @@
#include <blockfilter.h>
#include <serialize.h>
#include <streams.h>
-#include <test/fuzz/fuzz.h>
#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <util/bytevectorhash.h>
#include <util/golombrice.h>
diff --git a/src/test/fuzz/hex.cpp b/src/test/fuzz/hex.cpp
index 5fed17c17c..6a8699fd0f 100644
--- a/src/test/fuzz/hex.cpp
+++ b/src/test/fuzz/hex.cpp
@@ -16,7 +16,8 @@
#include <string>
#include <vector>
-void initialize() {
+void initialize()
+{
static const ECCVerifyHandle verify_handle;
}
diff --git a/src/test/fuzz/merkleblock.cpp b/src/test/fuzz/merkleblock.cpp
index eb8fa1d421..c44e334272 100644
--- a/src/test/fuzz/merkleblock.cpp
+++ b/src/test/fuzz/merkleblock.cpp
@@ -3,20 +3,20 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <merkleblock.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <uint256.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- Optional<CPartialMerkleTree> partial_merkle_tree = ConsumeDeserializable<CPartialMerkleTree>(fuzzed_data_provider);
+ std::optional<CPartialMerkleTree> partial_merkle_tree = ConsumeDeserializable<CPartialMerkleTree>(fuzzed_data_provider);
if (!partial_merkle_tree) {
return;
}
diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp
index dfa98a812b..fa0322a391 100644
--- a/src/test/fuzz/message.cpp
+++ b/src/test/fuzz/message.cpp
@@ -4,7 +4,6 @@
#include <chainparams.h>
#include <key_io.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp
index bfc5d21427..c071283467 100644
--- a/src/test/fuzz/net_permissions.cpp
+++ b/src/test/fuzz/net_permissions.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <net_permissions.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 201f49c87b..1cbf9b347f 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.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 <optional.h>
#include <policy/fees.h>
#include <primitives/transaction.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -11,6 +10,7 @@
#include <txmempool.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -21,7 +21,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
while (fuzzed_data_provider.ConsumeBool()) {
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 3)) {
case 0: {
- const Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (!mtx) {
break;
}
@@ -35,7 +35,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
case 1: {
std::vector<CTxMemPoolEntry> mempool_entries;
while (fuzzed_data_provider.ConsumeBool()) {
- const Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (!mtx) {
break;
}
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index 0343d33401..b7fc72373d 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -4,7 +4,6 @@
#include <chain.h>
#include <chainparams.h>
-#include <optional.h>
#include <pow.h>
#include <primitives/block.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -12,6 +11,7 @@
#include <test/fuzz/util.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -28,7 +28,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
const uint32_t fixed_time = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const uint32_t fixed_bits = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
while (fuzzed_data_provider.remaining_bytes() > 0) {
- const Optional<CBlockHeader> block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider);
+ const std::optional<CBlockHeader> block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider);
if (!block_header) {
continue;
}
@@ -72,7 +72,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
}
}
{
- const Optional<uint256> hash = ConsumeDeserializable<uint256>(fuzzed_data_provider);
+ const std::optional<uint256> hash = ConsumeDeserializable<uint256>(fuzzed_data_provider);
if (hash) {
(void)CheckProofOfWork(*hash, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), consensus_params);
}
diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp
index 64920f4af5..626e187cbd 100644
--- a/src/test/fuzz/prevector.cpp
+++ b/src/test/fuzz/prevector.cpp
@@ -14,8 +14,9 @@
namespace {
-template<unsigned int N, typename T>
-class prevector_tester {
+template <unsigned int N, typename T>
+class prevector_tester
+{
typedef std::vector<T> realtype;
realtype real_vector;
realtype real_vector_alt;
@@ -27,35 +28,36 @@ class prevector_tester {
typedef typename pretype::size_type Size;
public:
- void test() const {
+ void test() const
+ {
const pretype& const_pre_vector = pre_vector;
assert(real_vector.size() == pre_vector.size());
assert(real_vector.empty() == pre_vector.empty());
for (Size s = 0; s < real_vector.size(); s++) {
- assert(real_vector[s] == pre_vector[s]);
- assert(&(pre_vector[s]) == &(pre_vector.begin()[s]));
- assert(&(pre_vector[s]) == &*(pre_vector.begin() + s));
- assert(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
+ assert(real_vector[s] == pre_vector[s]);
+ assert(&(pre_vector[s]) == &(pre_vector.begin()[s]));
+ assert(&(pre_vector[s]) == &*(pre_vector.begin() + s));
+ assert(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
}
// assert(realtype(pre_vector) == real_vector);
assert(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
assert(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
size_t pos = 0;
for (const T& v : pre_vector) {
- assert(v == real_vector[pos]);
- ++pos;
+ assert(v == real_vector[pos]);
+ ++pos;
}
for (const T& v : reverse_iterate(pre_vector)) {
- --pos;
- assert(v == real_vector[pos]);
+ --pos;
+ assert(v == real_vector[pos]);
}
for (const T& v : const_pre_vector) {
- assert(v == real_vector[pos]);
- ++pos;
+ assert(v == real_vector[pos]);
+ ++pos;
}
for (const T& v : reverse_iterate(const_pre_vector)) {
- --pos;
- assert(v == real_vector[pos]);
+ --pos;
+ assert(v == real_vector[pos]);
}
CDataStream ss1(SER_DISK, 0);
CDataStream ss2(SER_DISK, 0);
@@ -67,101 +69,120 @@ public:
}
}
- void resize(Size s) {
+ void resize(Size s)
+ {
real_vector.resize(s);
assert(real_vector.size() == s);
pre_vector.resize(s);
assert(pre_vector.size() == s);
}
- void reserve(Size s) {
+ void reserve(Size s)
+ {
real_vector.reserve(s);
assert(real_vector.capacity() >= s);
pre_vector.reserve(s);
assert(pre_vector.capacity() >= s);
}
- void insert(Size position, const T& value) {
+ void insert(Size position, const T& value)
+ {
real_vector.insert(real_vector.begin() + position, value);
pre_vector.insert(pre_vector.begin() + position, value);
}
- void insert(Size position, Size count, const T& value) {
+ void insert(Size position, Size count, const T& value)
+ {
real_vector.insert(real_vector.begin() + position, count, value);
pre_vector.insert(pre_vector.begin() + position, count, value);
}
- template<typename I>
- void insert_range(Size position, I first, I last) {
+ template <typename I>
+ void insert_range(Size position, I first, I last)
+ {
real_vector.insert(real_vector.begin() + position, first, last);
pre_vector.insert(pre_vector.begin() + position, first, last);
}
- void erase(Size position) {
+ void erase(Size position)
+ {
real_vector.erase(real_vector.begin() + position);
pre_vector.erase(pre_vector.begin() + position);
}
- void erase(Size first, Size last) {
+ void erase(Size first, Size last)
+ {
real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);
pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);
}
- void update(Size pos, const T& value) {
+ void update(Size pos, const T& value)
+ {
real_vector[pos] = value;
pre_vector[pos] = value;
}
- void push_back(const T& value) {
+ void push_back(const T& value)
+ {
real_vector.push_back(value);
pre_vector.push_back(value);
}
- void pop_back() {
+ void pop_back()
+ {
real_vector.pop_back();
pre_vector.pop_back();
}
- void clear() {
+ void clear()
+ {
real_vector.clear();
pre_vector.clear();
}
- void assign(Size n, const T& value) {
+ void assign(Size n, const T& value)
+ {
real_vector.assign(n, value);
pre_vector.assign(n, value);
}
- Size size() const {
+ Size size() const
+ {
return real_vector.size();
}
- Size capacity() const {
+ Size capacity() const
+ {
return pre_vector.capacity();
}
- void shrink_to_fit() {
+ void shrink_to_fit()
+ {
pre_vector.shrink_to_fit();
}
- void swap() {
+ void swap()
+ {
real_vector.swap(real_vector_alt);
pre_vector.swap(pre_vector_alt);
}
- void move() {
+ void move()
+ {
real_vector = std::move(real_vector_alt);
real_vector_alt.clear();
pre_vector = std::move(pre_vector_alt);
pre_vector_alt.clear();
}
- void copy() {
+ void copy()
+ {
real_vector = real_vector_alt;
pre_vector = pre_vector_alt;
}
- void resize_uninitialized(realtype values) {
+ void resize_uninitialized(realtype values)
+ {
size_t r = values.size();
size_t s = real_vector.size() / 2;
if (real_vector.capacity() < s + r) {
@@ -181,7 +202,7 @@ public:
}
};
-}
+} // namespace
void test_one_input(const std::vector<uint8_t>& buffer)
{
diff --git a/src/test/fuzz/primitives_transaction.cpp b/src/test/fuzz/primitives_transaction.cpp
index 2e5ba6bdb0..4a0f920f58 100644
--- a/src/test/fuzz/primitives_transaction.cpp
+++ b/src/test/fuzz/primitives_transaction.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <optional.h>
#include <primitives/transaction.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -16,7 +16,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const CScript script = ConsumeScript(fuzzed_data_provider);
- const Optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
if (out_point) {
const CTxIn tx_in{*out_point, script, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
(void)tx_in;
@@ -24,8 +24,8 @@ void test_one_input(const std::vector<uint8_t>& buffer)
const CTxOut tx_out_1{ConsumeMoney(fuzzed_data_provider), script};
const CTxOut tx_out_2{ConsumeMoney(fuzzed_data_provider), ConsumeScript(fuzzed_data_provider)};
assert((tx_out_1 == tx_out_2) != (tx_out_1 != tx_out_2));
- const Optional<CMutableTransaction> mutable_tx_1 = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
- const Optional<CMutableTransaction> mutable_tx_2 = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ const std::optional<CMutableTransaction> mutable_tx_1 = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ const std::optional<CMutableTransaction> mutable_tx_2 = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (mutable_tx_1 && mutable_tx_2) {
const CTransaction tx_1{*mutable_tx_1};
const CTransaction tx_2{*mutable_tx_2};
diff --git a/src/test/fuzz/protocol.cpp b/src/test/fuzz/protocol.cpp
index 954471de6c..78df0f89e7 100644
--- a/src/test/fuzz/protocol.cpp
+++ b/src/test/fuzz/protocol.cpp
@@ -2,20 +2,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <optional.h>
#include <protocol.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
+#include <optional>
#include <stdexcept>
#include <vector>
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- const Optional<CInv> inv = ConsumeDeserializable<CInv>(fuzzed_data_provider);
+ const std::optional<CInv> inv = ConsumeDeserializable<CInv>(fuzzed_data_provider);
if (!inv) {
return;
}
@@ -24,7 +24,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
} catch (const std::out_of_range&) {
}
(void)inv->ToString();
- const Optional<CInv> another_inv = ConsumeDeserializable<CInv>(fuzzed_data_provider);
+ const std::optional<CInv> another_inv = ConsumeDeserializable<CInv>(fuzzed_data_provider);
if (!another_inv) {
return;
}
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index eb54b05df9..1fd88a5f7b 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.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 <optional.h>
#include <policy/rbf.h>
#include <primitives/transaction.h>
#include <sync.h>
@@ -12,19 +11,20 @@
#include <txmempool.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- Optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (!mtx) {
return;
}
CTxMemPool pool;
while (fuzzed_data_provider.ConsumeBool()) {
- const Optional<CMutableTransaction> another_mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ const std::optional<CMutableTransaction> another_mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (!another_mtx) {
break;
}
diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp
index 3b37321977..623b8cff3a 100644
--- a/src/test/fuzz/rolling_bloom_filter.cpp
+++ b/src/test/fuzz/rolling_bloom_filter.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bloom.h>
-#include <optional.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
@@ -11,6 +10,7 @@
#include <cassert>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -32,7 +32,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
break;
}
case 1: {
- const Optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
+ const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
if (!u256) {
break;
}
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index de82122dd6..e0c4ad7eb7 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -21,6 +21,11 @@
#include <univalue.h>
#include <util/memory.h>
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <vector>
+
void initialize()
{
// Fuzzers using pubkey must hold an ECCVerifyHandle.
@@ -32,7 +37,7 @@ void initialize()
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- const Optional<CScript> script_opt = ConsumeDeserializable<CScript>(fuzzed_data_provider);
+ const std::optional<CScript> script_opt = ConsumeDeserializable<CScript>(fuzzed_data_provider);
if (!script_opt) return;
const CScript script{*script_opt};
@@ -101,7 +106,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
}
}
- const Optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
+ const std::optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
if (other_script) {
{
CScript script_mut{script};
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index 49bee0e81f..3c1f911f7e 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -119,4 +119,10 @@ void test_one_input(const std::vector<uint8_t>& buffer)
int64_t amount_out;
(void)ParseFixedPoint(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 1024), &amount_out);
}
+ {
+ (void)Untranslated(random_string_1);
+ const bilingual_str bs1{random_string_1, random_string_2};
+ const bilingual_str bs2{random_string_2, random_string_1};
+ (void)(bs1 + bs2);
+ }
}
diff --git a/src/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp
index d5be1070bd..29064bc45c 100644
--- a/src/test/fuzz/strprintf.cpp
+++ b/src/test/fuzz/strprintf.cpp
@@ -6,6 +6,7 @@
#include <test/fuzz/fuzz.h>
#include <tinyformat.h>
#include <util/strencodings.h>
+#include <util/translation.h>
#include <algorithm>
#include <cstdint>
@@ -16,6 +17,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const std::string format_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
+ const bilingual_str bilingual_string{format_string, format_string};
const int digits_in_format_specifier = std::count_if(format_string.begin(), format_string.end(), IsDigit);
@@ -47,50 +49,62 @@ void test_one_input(const std::vector<uint8_t>& buffer)
try {
(void)strprintf(format_string, (signed char*)nullptr);
+ (void)tinyformat::format(bilingual_string, (signed char*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (unsigned char*)nullptr);
+ (void)tinyformat::format(bilingual_string, (unsigned char*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (void*)nullptr);
+ (void)tinyformat::format(bilingual_string, (void*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (bool*)nullptr);
+ (void)tinyformat::format(bilingual_string, (bool*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (float*)nullptr);
+ (void)tinyformat::format(bilingual_string, (float*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (double*)nullptr);
+ (void)tinyformat::format(bilingual_string, (double*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (int16_t*)nullptr);
+ (void)tinyformat::format(bilingual_string, (int16_t*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (uint16_t*)nullptr);
+ (void)tinyformat::format(bilingual_string, (uint16_t*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (int32_t*)nullptr);
+ (void)tinyformat::format(bilingual_string, (int32_t*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (uint32_t*)nullptr);
+ (void)tinyformat::format(bilingual_string, (uint32_t*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (int64_t*)nullptr);
+ (void)tinyformat::format(bilingual_string, (int64_t*)nullptr);
} catch (const tinyformat::format_error&) {
}
try {
(void)strprintf(format_string, (uint64_t*)nullptr);
+ (void)tinyformat::format(bilingual_string, (uint64_t*)nullptr);
} catch (const tinyformat::format_error&) {
}
@@ -98,21 +112,27 @@ void test_one_input(const std::vector<uint8_t>& buffer)
switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) {
case 0:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
break;
case 1:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
break;
case 2:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
break;
case 3:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
break;
case 4:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>());
break;
case 5:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeBool());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool());
break;
}
} catch (const tinyformat::format_error&) {
@@ -138,27 +158,35 @@ void test_one_input(const std::vector<uint8_t>& buffer)
switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) {
case 0:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
break;
case 1:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
break;
case 2:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
break;
case 3:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
break;
case 4:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
break;
case 5:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
break;
case 6:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
break;
case 7:
(void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
break;
}
} catch (const tinyformat::format_error&) {
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 501bb1de5a..f72d9380eb 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -9,7 +9,6 @@
#include <arith_uint256.h>
#include <attributes.h>
#include <consensus/consensus.h>
-#include <optional.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <serialize.h>
@@ -21,6 +20,7 @@
#include <version.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -52,7 +52,7 @@ NODISCARD inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProv
}
template <typename T>
-NODISCARD inline Optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
+NODISCARD inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION};
@@ -60,7 +60,7 @@ NODISCARD inline Optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_da
try {
ds >> obj;
} catch (const std::ios_base::failure&) {
- return nullopt;
+ return std::nullopt;
}
return obj;
}
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index d1f60e8972..978a7bee4d 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -28,6 +28,8 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
for (int i = 10; i > 0; --i) {
BOOST_CHECK_EQUAL(GetRand(std::numeric_limits<uint64_t>::max()), uint64_t{10393729187455219830U});
BOOST_CHECK_EQUAL(GetRandInt(std::numeric_limits<int>::max()), int{769702006});
+ BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2917185654);
+ BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2144374);
}
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
@@ -47,6 +49,8 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
for (int i = 10; i > 0; --i) {
BOOST_CHECK(GetRand(std::numeric_limits<uint64_t>::max()) != uint64_t{10393729187455219830U});
BOOST_CHECK(GetRandInt(std::numeric_limits<int>::max()) != int{769702006});
+ BOOST_CHECK(GetRandMicros(std::chrono::hours{1}) != std::chrono::microseconds{2917185654});
+ BOOST_CHECK(GetRandMillis(std::chrono::hours{1}) != std::chrono::milliseconds{2144374});
}
{
FastRandomContext ctx3, ctx4;
@@ -87,7 +91,7 @@ BOOST_AUTO_TEST_CASE(stdrandom_test)
BOOST_CHECK(x >= 3);
BOOST_CHECK(x <= 9);
- std::vector<int> test{1,2,3,4,5,6,7,8,9,10};
+ std::vector<int> test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::shuffle(test.begin(), test.end(), ctx);
for (int j = 1; j <= 10; ++j) {
BOOST_CHECK(std::find(test.begin(), test.end(), j) != test.end());
@@ -97,7 +101,6 @@ BOOST_AUTO_TEST_CASE(stdrandom_test)
BOOST_CHECK(std::find(test.begin(), test.end(), j) != test.end());
}
}
-
}
/** Test that Shuffle reaches every permutation with equal probability. */
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 9a6c721ab8..c2328f931c 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -29,15 +29,13 @@ public:
memcpy(charstrval, charstrvalin, sizeof(charstrval));
}
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(intval);
- READWRITE(boolval);
- READWRITE(stringval);
- READWRITE(charstrval);
- READWRITE(txval);
+ SERIALIZE_METHODS(CSerializeMethodsTestSingle, obj)
+ {
+ READWRITE(obj.intval);
+ READWRITE(obj.boolval);
+ READWRITE(obj.stringval);
+ READWRITE(obj.charstrval);
+ READWRITE(obj.txval);
}
bool operator==(const CSerializeMethodsTestSingle& rhs)
@@ -54,11 +52,10 @@ class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle
{
public:
using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle;
- ADD_SERIALIZE_METHODS;
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(intval, boolval, stringval, charstrval, txval);
+ SERIALIZE_METHODS(CSerializeMethodsTestMany, obj)
+ {
+ READWRITE(obj.intval, obj.boolval, obj.stringval, obj.charstrval, obj.txval);
}
};
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index c345f1eafb..899f054b83 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -32,7 +32,7 @@ struct MinerTestingSetup : public RegTestingSetup {
BOOST_FIXTURE_TEST_SUITE(validation_block_tests, MinerTestingSetup)
-struct TestSubscriber : public CValidationInterface {
+struct TestSubscriber final : public CValidationInterface {
uint256 m_expected_tip;
explicit TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
@@ -175,8 +175,8 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
LOCK(cs_main);
initial_tip = ::ChainActive().Tip();
}
- TestSubscriber sub(initial_tip->GetBlockHash());
- RegisterValidationInterface(&sub);
+ auto sub = std::make_shared<TestSubscriber>(initial_tip->GetBlockHash());
+ RegisterSharedValidationInterface(sub);
// create a bunch of threads that repeatedly process a block generated above at random
// this will create parallelism and randomness inside validation - the ValidationInterface
@@ -204,14 +204,12 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
for (auto& t : threads) {
t.join();
}
- while (GetMainSignals().CallbacksPending() > 0) {
- UninterruptibleSleep(std::chrono::milliseconds{100});
- }
+ SyncWithValidationInterfaceQueue();
- UnregisterValidationInterface(&sub);
+ UnregisterSharedValidationInterface(sub);
LOCK(cs_main);
- BOOST_CHECK_EQUAL(sub.m_expected_tip, ::ChainActive().Tip()->GetBlockHash());
+ BOOST_CHECK_EQUAL(sub->m_expected_tip, ::ChainActive().Tip()->GetBlockHash());
}
/**
diff --git a/src/test/validationinterface_tests.cpp b/src/test/validationinterface_tests.cpp
index 208be92852..ceba689e52 100644
--- a/src/test/validationinterface_tests.cpp
+++ b/src/test/validationinterface_tests.cpp
@@ -12,6 +12,40 @@
BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, TestingSetup)
+struct TestSubscriberNoop final : public CValidationInterface {
+ void BlockChecked(const CBlock&, const BlockValidationState&) override {}
+};
+
+BOOST_AUTO_TEST_CASE(unregister_validation_interface_race)
+{
+ std::atomic<bool> generate{true};
+
+ // Start thread to generate notifications
+ std::thread gen{[&] {
+ const CBlock block_dummy;
+ BlockValidationState state_dummy;
+ while (generate) {
+ GetMainSignals().BlockChecked(block_dummy, state_dummy);
+ }
+ }};
+
+ // Start thread to consume notifications
+ std::thread sub{[&] {
+ // keep going for about 1 sec, which is 250k iterations
+ for (int i = 0; i < 250000; i++) {
+ auto sub = std::make_shared<TestSubscriberNoop>();
+ RegisterSharedValidationInterface(sub);
+ UnregisterSharedValidationInterface(sub);
+ }
+ // tell the other thread we are done
+ generate = false;
+ }};
+
+ gen.join();
+ sub.join();
+ BOOST_CHECK(!generate);
+}
+
class TestInterface : public CValidationInterface
{
public:
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 071aa1336b..129697f0e7 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -36,19 +36,7 @@ struct CoinEntry {
char key;
explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
- template<typename Stream>
- void Serialize(Stream &s) const {
- s << key;
- s << outpoint->hash;
- s << VARINT(outpoint->n);
- }
-
- template<typename Stream>
- void Unserialize(Stream& s) {
- s >> key;
- s >> outpoint->hash;
- s >> VARINT(outpoint->n);
- }
+ SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
};
}
diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp
index bb41154afc..15795bd67f 100644
--- a/src/ui_interface.cpp
+++ b/src/ui_interface.cpp
@@ -49,8 +49,8 @@ void CClientUIInterface::NotifyNumConnectionsChanged(int newNumConnections) { re
void CClientUIInterface::NotifyNetworkActiveChanged(bool networkActive) { return g_ui_signals.NotifyNetworkActiveChanged(networkActive); }
void CClientUIInterface::NotifyAlertChanged() { return g_ui_signals.NotifyAlertChanged(); }
void CClientUIInterface::ShowProgress(const std::string& title, int nProgress, bool resume_possible) { return g_ui_signals.ShowProgress(title, nProgress, resume_possible); }
-void CClientUIInterface::NotifyBlockTip(bool b, const CBlockIndex* i) { return g_ui_signals.NotifyBlockTip(b, i); }
-void CClientUIInterface::NotifyHeaderTip(bool b, const CBlockIndex* i) { return g_ui_signals.NotifyHeaderTip(b, i); }
+void CClientUIInterface::NotifyBlockTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyBlockTip(s, i); }
+void CClientUIInterface::NotifyHeaderTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyHeaderTip(s, i); }
void CClientUIInterface::BannedListChanged() { return g_ui_signals.BannedListChanged(); }
bool InitError(const bilingual_str& str)
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 9c49451e84..d45811178f 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -11,6 +11,7 @@
#include <string>
class CBlockIndex;
+enum class SynchronizationState;
struct bilingual_str;
namespace boost {
@@ -110,10 +111,10 @@ public:
ADD_SIGNALS_DECL_WRAPPER(ShowProgress, void, const std::string& title, int nProgress, bool resume_possible);
/** New block has been accepted */
- ADD_SIGNALS_DECL_WRAPPER(NotifyBlockTip, void, bool, const CBlockIndex*);
+ ADD_SIGNALS_DECL_WRAPPER(NotifyBlockTip, void, SynchronizationState, const CBlockIndex*);
/** Best header has changed */
- ADD_SIGNALS_DECL_WRAPPER(NotifyHeaderTip, void, bool, const CBlockIndex*);
+ ADD_SIGNALS_DECL_WRAPPER(NotifyHeaderTip, void, SynchronizationState, const CBlockIndex*);
/** Banlist did change. */
ADD_SIGNALS_DECL_WRAPPER(BannedListChanged, void, void);
diff --git a/src/validation.cpp b/src/validation.cpp
index 8a454c8d1b..a9dfa5c171 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2800,6 +2800,13 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
return true;
}
+static SynchronizationState GetSynchronizationState(bool init)
+{
+ if (!init) return SynchronizationState::POST_INIT;
+ if (::fReindex) return SynchronizationState::INIT_REINDEX;
+ return SynchronizationState::INIT_DOWNLOAD;
+}
+
static bool NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) {
bool fNotify = false;
bool fInitialBlockDownload = false;
@@ -2817,7 +2824,7 @@ static bool NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) {
}
// Send block tip changed notifications without cs_main
if (fNotify) {
- uiInterface.NotifyHeaderTip(fInitialBlockDownload, pindexHeader);
+ uiInterface.NotifyHeaderTip(GetSynchronizationState(fInitialBlockDownload), pindexHeader);
}
return fNotify;
}
@@ -2906,7 +2913,7 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
// Always notify the UI if a new block tip was connected
- uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
+ uiInterface.NotifyBlockTip(GetSynchronizationState(fInitialDownload), pindexNewTip);
}
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
@@ -3097,7 +3104,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParam
// Only notify about a new block tip if the active chain was modified.
if (pindex_was_in_chain) {
- uiInterface.NotifyBlockTip(IsInitialBlockDownload(), to_mark_failed->pprev);
+ uiInterface.NotifyBlockTip(GetSynchronizationState(IsInitialBlockDownload()), to_mark_failed->pprev);
}
return true;
}
diff --git a/src/validation.h b/src/validation.h
index c4a5cc4593..cbab65e79e 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -103,6 +103,13 @@ struct BlockHasher
size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
};
+/** Current sync state passed to tip changed callbacks. */
+enum class SynchronizationState {
+ INIT_REINDEX,
+ INIT_DOWNLOAD,
+ POST_INIT
+};
+
extern RecursiveMutex cs_main;
extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 11000774c0..9437f9c817 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -89,22 +89,26 @@ public:
static CMainSignals g_signals;
-void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) {
+void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler)
+{
assert(!m_internals);
m_internals.reset(new MainSignalsInstance(&scheduler));
}
-void CMainSignals::UnregisterBackgroundSignalScheduler() {
+void CMainSignals::UnregisterBackgroundSignalScheduler()
+{
m_internals.reset(nullptr);
}
-void CMainSignals::FlushBackgroundCallbacks() {
+void CMainSignals::FlushBackgroundCallbacks()
+{
if (m_internals) {
m_internals->m_schedulerClient.EmptyQueue();
}
}
-size_t CMainSignals::CallbacksPending() {
+size_t CMainSignals::CallbacksPending()
+{
if (!m_internals) return 0;
return m_internals->m_schedulerClient.CallbacksPending();
}
@@ -114,10 +118,11 @@ CMainSignals& GetMainSignals()
return g_signals;
}
-void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> pwalletIn) {
- // Each connection captures pwalletIn to ensure that each callback is
- // executed before pwalletIn is destroyed. For more details see #18338.
- g_signals.m_internals->Register(std::move(pwalletIn));
+void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
+{
+ // Each connection captures the shared_ptr to ensure that each callback is
+ // executed before the subscriber is destroyed. For more details see #18338.
+ g_signals.m_internals->Register(std::move(callbacks));
}
void RegisterValidationInterface(CValidationInterface* callbacks)
@@ -132,24 +137,28 @@ void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> c
UnregisterValidationInterface(callbacks.get());
}
-void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
+void UnregisterValidationInterface(CValidationInterface* callbacks)
+{
if (g_signals.m_internals) {
- g_signals.m_internals->Unregister(pwalletIn);
+ g_signals.m_internals->Unregister(callbacks);
}
}
-void UnregisterAllValidationInterfaces() {
+void UnregisterAllValidationInterfaces()
+{
if (!g_signals.m_internals) {
return;
}
g_signals.m_internals->Clear();
}
-void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
+void CallFunctionInValidationInterfaceQueue(std::function<void()> func)
+{
g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
}
-void SyncWithValidationInterfaceQueue() {
+void SyncWithValidationInterfaceQueue()
+{
AssertLockNotHeld(cs_main);
// Block until the validation queue drains
std::promise<void> promise;
diff --git a/src/validationinterface.h b/src/validationinterface.h
index cb0204a555..9c23965bc1 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -22,20 +22,20 @@ class CValidationInterface;
class uint256;
class CScheduler;
-// These functions dispatch to one or all registered wallets
-
-/** Register a wallet to receive updates from core */
-void RegisterValidationInterface(CValidationInterface* pwalletIn);
-/** Unregister a wallet from core */
-void UnregisterValidationInterface(CValidationInterface* pwalletIn);
-/** Unregister all wallets from core */
+/** Register subscriber */
+void RegisterValidationInterface(CValidationInterface* callbacks);
+/** Unregister subscriber. DEPRECATED. This is not safe to use when the RPC server or main message handler thread is running. */
+void UnregisterValidationInterface(CValidationInterface* callbacks);
+/** Unregister all subscribers */
void UnregisterAllValidationInterfaces();
// Alternate registration functions that release a shared_ptr after the last
// notification is sent. These are useful for race-free cleanup, since
// unregistration is nonblocking and can return before the last notification is
// processed.
+/** Register subscriber */
void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks);
+/** Unregister subscriber */
void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks);
/**
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 250a4503f5..2a57248705 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1482,10 +1482,9 @@ UniValue listtransactions(const JSONRPCRequest& request)
static UniValue listsinceblock(const JSONRPCRequest& request)
{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- const CWallet* const pwallet = wallet.get();
+ std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ if (!EnsureWalletIsAvailable(pwallet.get(), request.fHelp)) {
return NullUniValue;
}
@@ -1542,11 +1541,12 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
},
}.Check(request);
+ const CWallet& wallet = *pwallet;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
- pwallet->BlockUntilSyncedToCurrentChain();
+ wallet.BlockUntilSyncedToCurrentChain();
- LOCK(pwallet->cs_wallet);
+ LOCK(wallet.cs_wallet);
// The way the 'height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
Optional<int> height = MakeOptional(false, int()); // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
@@ -1557,9 +1557,9 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
uint256 blockId;
if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
blockId = ParseHashV(request.params[0], "blockhash");
- height.emplace();
- altheight.emplace();
- if (!pwallet->chain().findCommonAncestor(blockId, pwallet->GetLastBlockHash(), /* ancestor out */ FoundBlock().height(*height), /* blockId out */ FoundBlock().height(*altheight))) {
+ height = int{};
+ altheight = int{};
+ if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /* ancestor out */ FoundBlock().height(*height), /* blockId out */ FoundBlock().height(*altheight))) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
}
@@ -1572,21 +1572,21 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
}
}
- if (ParseIncludeWatchonly(request.params[2], *pwallet)) {
+ if (ParseIncludeWatchonly(request.params[2], wallet)) {
filter |= ISMINE_WATCH_ONLY;
}
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
- int depth = height ? pwallet->GetLastBlockHeight() + 1 - *height : -1;
+ int depth = height ? wallet.GetLastBlockHeight() + 1 - *height : -1;
UniValue transactions(UniValue::VARR);
- for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) {
const CWalletTx& tx = pairWtx.second;
if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
- ListTransactions(pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
+ ListTransactions(&wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
}
}
@@ -1595,15 +1595,15 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
UniValue removed(UniValue::VARR);
while (include_removed && altheight && *altheight > *height) {
CBlock block;
- if (!pwallet->chain().findBlock(blockId, FoundBlock().data(block)) || block.IsNull()) {
+ if (!wallet.chain().findBlock(blockId, FoundBlock().data(block)) || block.IsNull()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
}
for (const CTransactionRef& tx : block.vtx) {
- auto it = pwallet->mapWallet.find(tx->GetHash());
- if (it != pwallet->mapWallet.end()) {
+ auto it = wallet.mapWallet.find(tx->GetHash());
+ if (it != wallet.mapWallet.end()) {
// We want all transactions regardless of confirmation count to appear here,
// even negative confirmation ones, hence the big negative.
- ListTransactions(pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
+ ListTransactions(&wallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
}
}
blockId = block.hashPrevBlock;
@@ -1611,7 +1611,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
}
uint256 lastblock;
- CHECK_NONFATAL(pwallet->chain().findAncestorByHeight(pwallet->GetLastBlockHash(), pwallet->GetLastBlockHeight() + 1 - target_confirms, FoundBlock().hash(lastblock)));
+ CHECK_NONFATAL(wallet.chain().findAncestorByHeight(wallet.GetLastBlockHash(), wallet.GetLastBlockHeight() + 1 - target_confirms, FoundBlock().hash(lastblock)));
UniValue ret(UniValue::VOBJ);
ret.pushKV("transactions", transactions);
diff --git a/test/README.md b/test/README.md
index e1dab92a06..0210907878 100644
--- a/test/README.md
+++ b/test/README.md
@@ -225,6 +225,10 @@ gdb /home/example/bitcoind <pid>
Note: gdb attach step may require ptrace_scope to be modified, or `sudo` preceding the `gdb`.
See this link for considerations: https://www.kernel.org/doc/Documentation/security/Yama.txt
+Often while debugging rpc calls from functional tests, the test might reach timeout before
+process can return a response. Use `--timeout-factor 0` to disable all rpc timeouts for that partcular
+functional test. Ex: `test/functional/wallet_hd.py --timeout-factor 0`.
+
##### Profiling
An easy way to profile node performance during functional tests is provided
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index 70dfe81d4e..5d782026dc 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -15,7 +15,7 @@ from collections import defaultdict
# Avoid wildcard * imports
from test_framework.blocktools import (create_block, create_coinbase)
-from test_framework.messages import CInv
+from test_framework.messages import CInv, MSG_BLOCK
from test_framework.mininode import (
P2PInterface,
mininode_lock,
@@ -198,7 +198,7 @@ class ExampleTest(BitcoinTestFramework):
getdata_request = msg_getdata()
for block in blocks:
- getdata_request.inv.append(CInv(2, block))
+ getdata_request.inv.append(CInv(MSG_BLOCK, block))
self.nodes[2].p2p.send_message(getdata_request)
# wait_until() will loop until a predicate condition is met. Use it to test properties of the
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index d4a8f8a715..9579a1715d 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -13,7 +13,7 @@ if uploadtarget has been reached.
from collections import defaultdict
import time
-from test_framework.messages import CInv, msg_getdata
+from test_framework.messages import CInv, MSG_BLOCK, msg_getdata
from test_framework.mininode import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, mine_large_block
@@ -84,7 +84,7 @@ class MaxUploadTest(BitcoinTestFramework):
# the same big old block too many times (expect: disconnect)
getdata_request = msg_getdata()
- getdata_request.inv.append(CInv(2, big_old_block))
+ getdata_request.inv.append(CInv(MSG_BLOCK, big_old_block))
max_bytes_per_day = 800*1024*1024
daily_buffer = 144 * 4000000
@@ -109,7 +109,7 @@ class MaxUploadTest(BitcoinTestFramework):
# Requesting the current block on p2p_conns[1] should succeed indefinitely,
# even when over the max upload target.
# We'll try 800 times
- getdata_request.inv = [CInv(2, big_new_block)]
+ getdata_request.inv = [CInv(MSG_BLOCK, big_new_block)]
for i in range(800):
p2p_conns[1].send_and_ping(getdata_request)
assert_equal(p2p_conns[1].block_receive_map[big_new_block], i+1)
@@ -117,7 +117,7 @@ class MaxUploadTest(BitcoinTestFramework):
self.log.info("Peer 1 able to repeatedly download new block")
# But if p2p_conns[1] tries for an old block, it gets disconnected too.
- getdata_request.inv = [CInv(2, big_old_block)]
+ getdata_request.inv = [CInv(MSG_BLOCK, big_old_block)]
p2p_conns[1].send_message(getdata_request)
p2p_conns[1].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 1)
@@ -145,12 +145,12 @@ class MaxUploadTest(BitcoinTestFramework):
self.nodes[0].add_p2p_connection(TestP2PConn())
#retrieve 20 blocks which should be enough to break the 1MB limit
- getdata_request.inv = [CInv(2, big_new_block)]
+ getdata_request.inv = [CInv(MSG_BLOCK, big_new_block)]
for i in range(20):
self.nodes[0].p2p.send_and_ping(getdata_request)
assert_equal(self.nodes[0].p2p.block_receive_map[big_new_block], i+1)
- getdata_request.inv = [CInv(2, big_old_block)]
+ getdata_request.inv = [CInv(MSG_BLOCK, big_old_block)]
self.nodes[0].p2p.send_and_ping(getdata_request)
assert_equal(len(self.nodes[0].getpeerinfo()), 1) #node is still connected because of the whitelist
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index fdd86310c0..24c357091f 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -108,12 +108,7 @@ class SegWitTest(BitcoinTestFramework):
assert tmpl['sigoplimit'] == 20000
assert tmpl['transactions'][0]['hash'] == txid
assert tmpl['transactions'][0]['sigops'] == 2
- tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
- assert tmpl['sizelimit'] == 1000000
- assert 'weightlimit' not in tmpl
- assert tmpl['sigoplimit'] == 20000
- assert tmpl['transactions'][0]['hash'] == txid
- assert tmpl['transactions'][0]['sigops'] == 2
+ assert '!segwit' not in tmpl['rules']
self.nodes[0].generate(1) # block 162
balance_presetup = self.nodes[0].getbalance()
@@ -213,6 +208,7 @@ class SegWitTest(BitcoinTestFramework):
assert tmpl['sigoplimit'] == 80000
assert tmpl['transactions'][0]['txid'] == txid
assert tmpl['transactions'][0]['sigops'] == 8
+ assert '!segwit' in tmpl['rules']
self.nodes[0].generate(1) # Mine a block to clear the gbt cache
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 66e6f8c424..d77a744758 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -10,7 +10,7 @@ Version 2 compact blocks are post-segwit (wtxids)
import random
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
-from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_no_witness_block, msg_no_witness_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_block, msg_blocktxn, MSG_WITNESS_FLAG, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex
+from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_no_witness_block, msg_no_witness_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_block, msg_blocktxn, MSG_BLOCK, MSG_CMPCT_BLOCK, MSG_WITNESS_FLAG, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.script import CScript, OP_TRUE, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
@@ -44,7 +44,7 @@ class TestP2PConn(P2PInterface):
def on_inv(self, message):
for x in self.last_message["inv"].inv:
- if x.type == 2:
+ if x.type == MSG_BLOCK:
self.block_announced = True
self.announced_blockhashes.add(x.hash)
@@ -307,7 +307,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Now fetch the compact block using a normal non-announce getdata
with mininode_lock:
test_node.clear_block_announcement()
- inv = CInv(4, block_hash) # 4 == "CompactBlock"
+ inv = CInv(MSG_CMPCT_BLOCK, block_hash)
test_node.send_message(msg_getdata([inv]))
wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
@@ -380,7 +380,7 @@ class CompactBlocksTest(BitcoinTestFramework):
block = self.build_block_on_tip(node, segwit=segwit)
if announce == "inv":
- test_node.send_message(msg_inv([CInv(2, block.sha256)]))
+ test_node.send_message(msg_inv([CInv(MSG_BLOCK, block.sha256)]))
wait_until(lambda: "getheaders" in test_node.last_message, timeout=30, lock=mininode_lock)
test_node.send_header_for_blocks([block])
else:
@@ -564,7 +564,8 @@ class CompactBlocksTest(BitcoinTestFramework):
# We should receive a getdata request
test_node.wait_for_getdata([block.sha256], timeout=10)
- assert test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2 | MSG_WITNESS_FLAG
+ assert test_node.last_message["getdata"].inv[0].type == MSG_BLOCK or \
+ test_node.last_message["getdata"].inv[0].type == MSG_BLOCK | MSG_WITNESS_FLAG
# Deliver the block
if version == 2:
@@ -633,7 +634,7 @@ class CompactBlocksTest(BitcoinTestFramework):
wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
test_node.clear_block_announcement()
- test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))
+ test_node.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))]))
wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock)
test_node.clear_block_announcement()
@@ -642,7 +643,7 @@ class CompactBlocksTest(BitcoinTestFramework):
test_node.clear_block_announcement()
with mininode_lock:
test_node.last_message.pop("block", None)
- test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))
+ test_node.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))]))
wait_until(lambda: "block" in test_node.last_message, timeout=30, lock=mininode_lock)
with mininode_lock:
test_node.last_message["block"].block.calc_sha256()
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index 4f242bd94a..805cb1e84f 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -7,7 +7,7 @@
from decimal import Decimal
import time
-from test_framework.messages import msg_feefilter
+from test_framework.messages import MSG_TX, msg_feefilter
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.test_framework import BitcoinTestFramework
@@ -31,7 +31,7 @@ class TestP2PConn(P2PInterface):
def on_inv(self, message):
for i in message.inv:
- if (i.type == 1):
+ if (i.type == MSG_TX):
self.txinvs.append(hashToHex(i.hash))
def clear_invs(self):
diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py
index c9fbb830c8..d743abe681 100755
--- a/test/functional/p2p_fingerprint.py
+++ b/test/functional/p2p_fingerprint.py
@@ -11,7 +11,7 @@ the node should pretend that it does not have it to avoid fingerprinting.
import time
from test_framework.blocktools import (create_block, create_coinbase)
-from test_framework.messages import CInv
+from test_framework.messages import CInv, MSG_BLOCK
from test_framework.mininode import (
P2PInterface,
msg_headers,
@@ -48,7 +48,7 @@ class P2PFingerprintTest(BitcoinTestFramework):
# Send a getdata request for a given block hash
def send_block_request(self, block_hash, node):
msg = msg_getdata()
- msg.inv.append(CInv(2, block_hash)) # 2 == "Block"
+ msg.inv.append(CInv(MSG_BLOCK, block_hash))
node.send_message(msg)
# Send a getheaders request for a given single block hash
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index 4bd832e8f7..81302374c9 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -7,7 +7,16 @@ import asyncio
import struct
import sys
-from test_framework import messages
+from test_framework.messages import (
+ CBlockHeader,
+ CInv,
+ msg_getdata,
+ msg_headers,
+ msg_inv,
+ msg_ping,
+ MSG_TX,
+ ser_string,
+)
from test_framework.mininode import (
NetworkThread,
P2PDataStore,
@@ -25,7 +34,7 @@ class msg_unrecognized:
self.str_data = str_data.encode() if not isinstance(str_data, bytes) else str_data
def serialize(self):
- return messages.ser_string(self.str_data)
+ return ser_string(self.str_data)
def __repr__(self):
return "{}(data={})".format(self.msgtype, self.str_data)
@@ -135,7 +144,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
# For some reason unknown to me, we sometimes have to push additional data to the
# peer in order for it to realize a disconnect.
try:
- node.p2p.send_message(messages.msg_ping(nonce=123123))
+ node.p2p.send_message(msg_ping(nonce=123123))
except IOError:
pass
@@ -158,7 +167,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
asyncio.run_coroutine_threadsafe(swap_magic_bytes(), NetworkThread.network_event_loop).result()
with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: INVALID MESSAGESTART ping']):
- conn.send_message(messages.msg_ping(nonce=0xff))
+ conn.send_message(msg_ping(nonce=0xff))
conn.wait_for_disconnect(timeout=1)
self.nodes[0].disconnect_p2ps()
@@ -206,13 +215,13 @@ class InvalidMessagesTest(BitcoinTestFramework):
def test_large_inv(self):
conn = self.nodes[0].add_p2p_connection(P2PInterface())
with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (0 -> 20): message inv size() = 50001']):
- msg = messages.msg_inv([messages.CInv(1, 1)] * 50001)
+ msg = msg_inv([CInv(MSG_TX, 1)] * 50001)
conn.send_and_ping(msg)
with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (20 -> 40): message getdata size() = 50001']):
- msg = messages.msg_getdata([messages.CInv(1, 1)] * 50001)
+ msg = msg_getdata([CInv(MSG_TX, 1)] * 50001)
conn.send_and_ping(msg)
with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (40 -> 60): headers message size = 2001']):
- msg = messages.msg_headers([messages.CBlockHeader()] * 2001)
+ msg = msg_headers([CBlockHeader()] * 2001)
conn.send_and_ping(msg)
self.nodes[0].disconnect_p2ps()
diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py
index 6b3436fa5f..da30ad5977 100755
--- a/test/functional/p2p_leak_tx.py
+++ b/test/functional/p2p_leak_tx.py
@@ -4,7 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that we don't leak txs to inbound peers that we haven't yet announced to"""
-from test_framework.messages import msg_getdata, CInv
+from test_framework.messages import msg_getdata, CInv, MSG_TX
from test_framework.mininode import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -37,7 +37,7 @@ class P2PLeakTxTest(BitcoinTestFramework):
txid = gen_node.sendtoaddress(gen_node.getnewaddress(), 0.01)
want_tx = msg_getdata()
- want_tx.inv.append(CInv(t=1, h=int(txid, 16)))
+ want_tx.inv.append(CInv(t=MSG_TX, h=int(txid, 16)))
inbound_peer.last_message.pop('notfound', None)
inbound_peer.send_and_ping(want_tx)
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index e6451d9f18..9c8c36c89e 100755
--- a/test/functional/p2p_node_network_limited.py
+++ b/test/functional/p2p_node_network_limited.py
@@ -8,7 +8,7 @@ Tests that a node configured with -prune=550 signals NODE_NETWORK_LIMITED correc
and that it responds to getdata requests for blocks correctly:
- send a block within 288 + 2 of the tip
- disconnect peers who request blocks older than that."""
-from test_framework.messages import CInv, msg_getdata, msg_verack, NODE_NETWORK_LIMITED, NODE_WITNESS
+from test_framework.messages import CInv, MSG_BLOCK, msg_getdata, msg_verack, NODE_NETWORK_LIMITED, NODE_WITNESS
from test_framework.mininode import P2PInterface, mininode_lock
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -31,7 +31,7 @@ class P2PIgnoreInv(P2PInterface):
wait_until(test_function, timeout=timeout, lock=mininode_lock)
def send_getdata_for_block(self, blockhash):
getdata_request = msg_getdata()
- getdata_request.inv.append(CInv(2, int(blockhash, 16)))
+ getdata_request.inv.append(CInv(MSG_BLOCK, int(blockhash, 16)))
self.send_message(getdata_request)
class NodeNetworkLimitedTest(BitcoinTestFramework):
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 6fb0fec32b..8a989097b4 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -22,6 +22,8 @@ from test_framework.messages import (
CTxOut,
CTxWitness,
MAX_BLOCK_BASE_SIZE,
+ MSG_BLOCK,
+ MSG_TX,
MSG_WITNESS_FLAG,
NODE_NETWORK,
NODE_WITNESS,
@@ -157,7 +159,7 @@ class TestP2PConn(P2PInterface):
def announce_tx_and_wait_for_getdata(self, tx, timeout=60, success=True):
with mininode_lock:
self.last_message.pop("getdata", None)
- self.send_message(msg_inv(inv=[CInv(1, tx.sha256)]))
+ self.send_message(msg_inv(inv=[CInv(MSG_TX, tx.sha256)]))
if success:
self.wait_for_getdata([tx.sha256], timeout)
else:
@@ -173,7 +175,7 @@ class TestP2PConn(P2PInterface):
if use_header:
self.send_message(msg)
else:
- self.send_message(msg_inv(inv=[CInv(2, block.sha256)]))
+ self.send_message(msg_inv(inv=[CInv(MSG_BLOCK, block.sha256)]))
self.wait_for_getheaders()
self.send_message(msg)
self.wait_for_getdata([block.sha256])
@@ -576,7 +578,7 @@ class SegWitTest(BitcoinTestFramework):
# Verify that if a peer doesn't set nServices to include NODE_WITNESS,
# the getdata is just for the non-witness portion.
self.old_node.announce_tx_and_wait_for_getdata(tx)
- assert self.old_node.last_message["getdata"].inv[0].type == 1
+ assert self.old_node.last_message["getdata"].inv[0].type == MSG_TX
# Since we haven't delivered the tx yet, inv'ing the same tx from
# a witness transaction ought not result in a getdata.
@@ -1310,9 +1312,9 @@ class SegWitTest(BitcoinTestFramework):
tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
# Also check that old_node gets a tx announcement, even though this is
# a witness transaction.
- self.old_node.wait_for_inv([CInv(1, tx2.sha256)]) # wait until tx2 was inv'ed
+ self.old_node.wait_for_inv([CInv(MSG_TX, tx2.sha256)]) # wait until tx2 was inv'ed
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
- self.old_node.wait_for_inv([CInv(1, tx3.sha256)])
+ self.old_node.wait_for_inv([CInv(MSG_TX, tx3.sha256)])
# Test that getrawtransaction returns correct witness information
# hash, size, vsize
diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py
index a8fba306a7..481b1c1841 100755
--- a/test/functional/p2p_sendheaders.py
+++ b/test/functional/p2p_sendheaders.py
@@ -92,6 +92,7 @@ from test_framework.mininode import (
NODE_WITNESS,
P2PInterface,
mininode_lock,
+ MSG_BLOCK,
msg_block,
msg_getblocks,
msg_getdata,
@@ -120,7 +121,7 @@ class BaseNode(P2PInterface):
"""Request data for a list of block hashes."""
msg = msg_getdata()
for x in block_hashes:
- msg.inv.append(CInv(2, x))
+ msg.inv.append(CInv(MSG_BLOCK, x))
self.send_message(msg)
def send_get_headers(self, locator, hashstop):
@@ -131,7 +132,7 @@ class BaseNode(P2PInterface):
def send_block_inv(self, blockhash):
msg = msg_inv()
- msg.inv = [CInv(2, blockhash)]
+ msg.inv = [CInv(MSG_BLOCK, blockhash)]
self.send_message(msg)
def send_header_for_blocks(self, new_blocks):
diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py
index a999fba818..10f5eea0e5 100755
--- a/test/functional/p2p_tx_download.py
+++ b/test/functional/p2p_tx_download.py
@@ -63,7 +63,7 @@ class TxDownloadTest(BitcoinTestFramework):
txid = 0xdeadbeef
self.log.info("Announce the txid from each incoming peer to node 0")
- msg = msg_inv([CInv(t=1, h=txid)])
+ msg = msg_inv([CInv(t=MSG_TX, h=txid)])
for p in self.nodes[0].p2ps:
p.send_and_ping(msg)
@@ -104,7 +104,7 @@ class TxDownloadTest(BitcoinTestFramework):
self.log.info(
"Announce the transaction to all nodes from all {} incoming peers, but never send it".format(NUM_INBOUND))
- msg = msg_inv([CInv(t=1, h=txid)])
+ msg = msg_inv([CInv(t=MSG_TX, h=txid)])
for p in self.peers:
p.send_and_ping(msg)
@@ -135,13 +135,13 @@ class TxDownloadTest(BitcoinTestFramework):
with mininode_lock:
p.tx_getdata_count = 0
- p.send_message(msg_inv([CInv(t=1, h=i) for i in txids]))
+ p.send_message(msg_inv([CInv(t=MSG_TX, h=i) for i in txids]))
wait_until(lambda: p.tx_getdata_count >= MAX_GETDATA_IN_FLIGHT, lock=mininode_lock)
with mininode_lock:
assert_equal(p.tx_getdata_count, MAX_GETDATA_IN_FLIGHT)
self.log.info("Now check that if we send a NOTFOUND for a transaction, we'll get one more request")
- p.send_message(msg_notfound(vec=[CInv(t=1, h=txids[0])]))
+ p.send_message(msg_notfound(vec=[CInv(t=MSG_TX, h=txids[0])]))
wait_until(lambda: p.tx_getdata_count >= MAX_GETDATA_IN_FLIGHT + 1, timeout=10, lock=mininode_lock)
with mininode_lock:
assert_equal(p.tx_getdata_count, MAX_GETDATA_IN_FLIGHT + 1)
@@ -154,7 +154,7 @@ class TxDownloadTest(BitcoinTestFramework):
def test_spurious_notfound(self):
self.log.info('Check that spurious notfound is ignored')
- self.nodes[0].p2ps[0].send_message(msg_notfound(vec=[CInv(1, 1)]))
+ self.nodes[0].p2ps[0].send_message(msg_notfound(vec=[CInv(MSG_TX, 1)]))
def run_test(self):
# Setup the p2p connections
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index 3aaf4b9977..c323168848 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -54,7 +54,7 @@ Node1 is unused in tests 3-7:
import time
from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script
-from test_framework.messages import CBlockHeader, CInv, msg_block, msg_headers, msg_inv
+from test_framework.messages import CBlockHeader, CInv, MSG_BLOCK, msg_block, msg_headers, msg_inv
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -210,7 +210,7 @@ class AcceptBlockTest(BitcoinTestFramework):
with mininode_lock:
# Clear state so we can check the getdata request
test_node.last_message.pop("getdata", None)
- test_node.send_message(msg_inv([CInv(2, block_h3.sha256)]))
+ test_node.send_message(msg_inv([CInv(MSG_BLOCK, block_h3.sha256)]))
test_node.sync_with_ping()
with mininode_lock:
diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py
index b75ce15f2e..daf02fc4f3 100755
--- a/test/functional/rpc_users.py
+++ b/test/functional/rpc_users.py
@@ -20,6 +20,7 @@ import string
import configparser
import sys
+
def call_with_auth(node, user, password):
url = urllib.parse.urlparse(node.url)
headers = {"Authorization": "Basic " + str_to_b64str('{}:{}'.format(user, password))}
@@ -64,9 +65,9 @@ class HTTPBasicsTest(BitcoinTestFramework):
self.password = lines[3]
with open(os.path.join(get_datadir_path(self.options.tmpdir, 0), "bitcoin.conf"), 'a', encoding='utf8') as f:
- f.write(rpcauth+"\n")
- f.write(rpcauth2+"\n")
- f.write(rpcauth3+"\n")
+ f.write(rpcauth + "\n")
+ f.write(rpcauth2 + "\n")
+ f.write(rpcauth3 + "\n")
with open(os.path.join(get_datadir_path(self.options.tmpdir, 1), "bitcoin.conf"), 'a', encoding='utf8') as f:
f.write("rpcuser={}\n".format(self.rpcuser))
f.write("rpcpassword={}\n".format(self.rpcpassword))
@@ -76,19 +77,16 @@ class HTTPBasicsTest(BitcoinTestFramework):
assert_equal(200, call_with_auth(node, user, password).status)
self.log.info('Wrong...')
- assert_equal(401, call_with_auth(node, user, password+'wrong').status)
+ assert_equal(401, call_with_auth(node, user, password + 'wrong').status)
self.log.info('Wrong...')
- assert_equal(401, call_with_auth(node, user+'wrong', password).status)
+ assert_equal(401, call_with_auth(node, user + 'wrong', password).status)
self.log.info('Wrong...')
- assert_equal(401, call_with_auth(node, user+'wrong', password+'wrong').status)
+ assert_equal(401, call_with_auth(node, user + 'wrong', password + 'wrong').status)
def run_test(self):
-
- ##################################################
- # Check correctness of the rpcauth config option #
- ##################################################
+ self.log.info('Check correctness of the rpcauth config option')
url = urllib.parse.urlparse(self.nodes[0].url)
self.test_auth(self.nodes[0], url.username, url.password)
@@ -96,12 +94,18 @@ class HTTPBasicsTest(BitcoinTestFramework):
self.test_auth(self.nodes[0], 'rt2', self.rt2password)
self.test_auth(self.nodes[0], self.user, self.password)
- ###############################################################
- # Check correctness of the rpcuser/rpcpassword config options #
- ###############################################################
+ self.log.info('Check correctness of the rpcuser/rpcpassword config options')
url = urllib.parse.urlparse(self.nodes[1].url)
self.test_auth(self.nodes[1], self.rpcuser, self.rpcpassword)
+ self.log.info('Check that failure to write cookie file will abort the node gracefully')
+ self.stop_node(0)
+ cookie_file = os.path.join(get_datadir_path(self.options.tmpdir, 0), self.chain, '.cookie.tmp')
+ os.mkdir(cookie_file)
+ init_error = 'Error: Unable to start HTTP server. See debug log for details.'
+ self.nodes[0].assert_start_raises_init_error(expected_msg=init_error)
+
+
if __name__ == '__main__':
- HTTPBasicsTest ().main ()
+ HTTPBasicsTest().main()
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index ef5ef49eaf..6c9c8a7397 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -54,6 +54,7 @@ NODE_NETWORK_LIMITED = (1 << 10)
MSG_TX = 1
MSG_BLOCK = 2
MSG_FILTERED_BLOCK = 3
+MSG_CMPCT_BLOCK = 4
MSG_WITNESS_FLAG = 1 << 30
MSG_TYPE_MASK = 0xffffffff >> 2
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index ba0391625e..bbd7350bf1 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -122,9 +122,9 @@ class P2PConnection(asyncio.Protocol):
def is_connected(self):
return self._transport is not None
- def peer_connect(self, dstaddr, dstport, *, net, factor):
+ def peer_connect(self, dstaddr, dstport, *, net, timeout_factor):
assert not self.is_connected
- self.factor = factor
+ self.timeout_factor = timeout_factor
self.dstaddr = dstaddr
self.dstport = dstport
# The initial message to send after the connection was made:
@@ -372,7 +372,7 @@ class P2PInterface(P2PConnection):
# Connection helper methods
def wait_until(self, test_function, timeout):
- wait_until(test_function, timeout=timeout, lock=mininode_lock, factor=self.factor)
+ wait_until(test_function, timeout=timeout, lock=mininode_lock, timeout_factor=self.timeout_factor)
def wait_for_disconnect(self, timeout=60):
test_function = lambda: not self.is_connected
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 11c96deefb..6126efd842 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -102,7 +102,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.bind_to_localhost_only = True
self.set_test_params()
self.parse_args()
- self.rpc_timeout = int(self.rpc_timeout * self.options.factor) # optionally, increase timeout by a factor
+ if self.options.timeout_factor == 0 :
+ self.options.timeout_factor = 99999
+ self.rpc_timeout = int(self.rpc_timeout * self.options.timeout_factor) # optionally, increase timeout by a factor
def main(self):
"""Main function. This should not be overridden by the subclass test scripts."""
@@ -169,7 +171,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
help="set a random seed for deterministically reproducing a previous test run")
parser.add_argument("--descriptors", default=False, action="store_true",
help="Run test using a descriptor wallet")
- parser.add_argument('--factor', type=float, default=1.0, help='adjust test timeouts by a factor')
+ parser.add_argument('--timeout-factor', dest="timeout_factor", type=float, default=1.0, help='adjust test timeouts by a factor. Setting it to 0 disables all timeouts')
self.add_options(parser)
self.options = parser.parse_args()
@@ -185,8 +187,18 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
config = configparser.ConfigParser()
config.read_file(open(self.options.configfile))
self.config = config
- self.options.bitcoind = os.getenv("BITCOIND", default=config["environment"]["BUILDDIR"] + '/src/bitcoind' + config["environment"]["EXEEXT"])
- self.options.bitcoincli = os.getenv("BITCOINCLI", default=config["environment"]["BUILDDIR"] + '/src/bitcoin-cli' + config["environment"]["EXEEXT"])
+ fname_bitcoind = os.path.join(
+ config["environment"]["BUILDDIR"],
+ "src",
+ "bitcoind" + config["environment"]["EXEEXT"]
+ )
+ fname_bitcoincli = os.path.join(
+ config["environment"]["BUILDDIR"],
+ "src",
+ "bitcoin-cli" + config["environment"]["EXEEXT"]
+ )
+ self.options.bitcoind = os.getenv("BITCOIND", default=fname_bitcoind)
+ self.options.bitcoincli = os.getenv("BITCOINCLI", default=fname_bitcoincli)
self.options.previous_releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases"
@@ -435,7 +447,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
chain=self.chain,
rpchost=rpchost,
timewait=self.rpc_timeout,
- factor=self.options.factor,
+ timeout_factor=self.options.timeout_factor,
bitcoind=binary[i],
bitcoin_cli=binary_cli[i],
version=versions[i],
@@ -582,7 +594,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
extra_args=['-disablewallet'],
rpchost=None,
timewait=self.rpc_timeout,
- factor=self.options.factor,
+ timeout_factor=self.options.timeout_factor,
bitcoind=self.options.bitcoind,
bitcoin_cli=self.options.bitcoincli,
coverage_dir=None,
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 826faece68..d52aff6f7e 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -62,7 +62,7 @@ class TestNode():
To make things easier for the test writer, any unrecognised messages will
be dispatched to the RPC connection."""
- def __init__(self, i, datadir, *, chain, rpchost, timewait, factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False):
+ def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False):
"""
Kwargs:
start_perf (bool): If True, begin profiling the node with `perf` as soon as
@@ -128,7 +128,7 @@ class TestNode():
self.perf_subprocesses = {}
self.p2ps = []
- self.factor = factor
+ self.timeout_factor = timeout_factor
AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
PRIV_KEYS = [
@@ -241,7 +241,7 @@ class TestNode():
# The wait is done here to make tests as robust as possible
# and prevent racy tests and intermittent failures as much
# as possible. Some tests might not need this, but the
- # overhead is trivial, and the added gurantees are worth
+ # overhead is trivial, and the added guarantees are worth
# the minimal performance cost.
self.log.debug("RPC successfully started")
if self.use_cli:
@@ -349,13 +349,13 @@ class TestNode():
return True
def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
- wait_until(self.is_node_stopped, timeout=timeout, factor=self.factor)
+ wait_until(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor)
@contextlib.contextmanager
def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2):
if unexpected_msgs is None:
unexpected_msgs = []
- time_end = time.time() + timeout * self.factor
+ time_end = time.time() + timeout * self.timeout_factor
debug_log = os.path.join(self.datadir, self.chain, 'debug.log')
with open(debug_log, encoding='utf-8') as dl:
dl.seek(0, 2)
@@ -512,7 +512,7 @@ class TestNode():
if 'dstaddr' not in kwargs:
kwargs['dstaddr'] = '127.0.0.1'
- p2p_conn.peer_connect(**kwargs, net=self.chain, factor=self.factor)()
+ p2p_conn.peer_connect(**kwargs, net=self.chain, timeout_factor=self.timeout_factor)()
self.p2ps.append(p2p_conn)
if wait_for_verack:
# Wait for the node to send us the version and verack
@@ -526,7 +526,7 @@ class TestNode():
# transaction that will be added to the mempool as soon as we return here.
#
# So syncing here is redundant when we only want to send a message, but the cost is low (a few milliseconds)
- # in comparision to the upside of making tests less fragile and unexpected intermittent errors less likely.
+ # in comparison to the upside of making tests less fragile and unexpected intermittent errors less likely.
p2p_conn.sync_with_ping()
return p2p_conn
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 7466a3cab3..6dfea7efd2 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -208,10 +208,10 @@ def str_to_b64str(string):
def satoshi_round(amount):
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
-def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, factor=1.0):
+def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, timeout_factor=1.0):
if attempts == float('inf') and timeout == float('inf'):
timeout = 60
- timeout = timeout * factor
+ timeout = timeout * timeout_factor
attempt = 0
time_end = time.time() + timeout