aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--build-aux/m4/ax_boost_process.m4121
-rw-r--r--build_msvc/bitcoin_config.h3
-rw-r--r--build_msvc/vcpkg-packages.txt2
-rw-r--r--ci/test/00_setup_env_arm.sh2
-rw-r--r--ci/test/00_setup_env_i686_centos.sh2
-rw-r--r--ci/test/00_setup_env_mac.sh2
-rw-r--r--ci/test/00_setup_env_mac_host.sh2
-rw-r--r--ci/test/00_setup_env_native_asan.sh2
-rw-r--r--ci/test/00_setup_env_native_fuzz.sh2
-rw-r--r--ci/test/00_setup_env_native_multiprocess.sh2
-rw-r--r--ci/test/00_setup_env_native_nowallet.sh2
-rw-r--r--ci/test/00_setup_env_native_qt5.sh2
-rw-r--r--ci/test/00_setup_env_native_tsan.sh2
-rw-r--r--ci/test/00_setup_env_s390x.sh2
-rw-r--r--ci/test/00_setup_env_win64.sh2
-rw-r--r--configure.ac71
-rw-r--r--contrib/valgrind.supp1
-rw-r--r--depends/packages/boost.mk2
-rw-r--r--doc/Doxyfile.in2
-rw-r--r--doc/dependencies.md2
-rw-r--r--doc/release-notes/release-notes-0.20.1.md158
-rw-r--r--src/Makefile.test.include3
-rw-r--r--src/addrman.h2
-rw-r--r--src/base58.cpp4
-rw-r--r--src/bench/chacha_poly_aead.cpp2
-rw-r--r--src/bench/verify_script.cpp2
-rw-r--r--src/blockfilter.cpp8
-rw-r--r--src/consensus/validation.h3
-rw-r--r--src/hash.cpp2
-rw-r--r--src/hash.h59
-rw-r--r--src/interfaces/node.cpp74
-rw-r--r--src/interfaces/node.h6
-rw-r--r--src/key.cpp2
-rw-r--r--src/merkleblock.cpp4
-rw-r--r--src/net.cpp25
-rw-r--r--src/net.h34
-rw-r--r--src/net_permissions.cpp3
-rw-r--r--src/net_permissions.h4
-rw-r--r--src/net_processing.cpp53
-rw-r--r--src/netaddress.cpp2
-rw-r--r--src/policy/policy.cpp8
-rw-r--r--src/protocol.h20
-rw-r--r--src/pubkey.h4
-rw-r--r--src/qt/bitcoin.cpp4
-rw-r--r--src/qt/test/addressbooktests.cpp2
-rw-r--r--src/qt/test/test_main.cpp3
-rw-r--r--src/qt/test/wallettests.cpp3
-rw-r--r--src/rpc/rawtransaction.cpp2
-rw-r--r--src/script/interpreter.cpp4
-rw-r--r--src/script/standard.cpp6
-rw-r--r--src/script/standard.h3
-rw-r--r--src/span.h12
-rw-r--r--src/sync.cpp22
-rw-r--r--src/sync.h14
-rw-r--r--src/test/crypto_tests.cpp2
-rw-r--r--src/test/fuzz/crypto.cpp11
-rw-r--r--src/test/fuzz/key.cpp2
-rw-r--r--src/test/fuzz/net_permissions.cpp1
-rw-r--r--src/test/key_tests.cpp10
-rw-r--r--src/test/merkle_tests.cpp13
-rw-r--r--src/test/netbase_tests.cpp3
-rw-r--r--src/test/script_standard_tests.cpp2
-rw-r--r--src/test/script_tests.cpp2
-rw-r--r--src/test/serialize_tests.cpp4
-rw-r--r--src/test/settings_tests.cpp2
-rw-r--r--src/test/sync_tests.cpp6
-rw-r--r--src/test/system_tests.cpp95
-rw-r--r--src/test/util/setup_common.cpp4
-rw-r--r--src/test/util_tests.cpp8
-rw-r--r--src/uint256.cpp10
-rw-r--r--src/uint256.h29
-rw-r--r--src/util/system.cpp43
-rw-r--r--src/util/system.h12
-rw-r--r--src/validation.cpp9
-rw-r--r--src/wallet/rpcwallet.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp4
-rw-r--r--src/wallet/walletdb.cpp12
-rwxr-xr-xtest/functional/p2p_filter.py6
-rwxr-xr-xtest/functional/p2p_getaddr_caching.py109
-rwxr-xr-xtest/functional/p2p_permissions.py2
-rwxr-xr-xtest/functional/p2p_ping.py21
-rwxr-xr-xtest/functional/p2p_segwit.py12
-rwxr-xr-xtest/functional/test_framework/mininode.py29
-rwxr-xr-xtest/functional/test_framework/test_node.py2
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/lint/lint-git-commit-check.sh19
-rwxr-xr-xtest/lint/lint-includes.sh1
88 files changed, 944 insertions, 331 deletions
diff --git a/.travis.yml b/.travis.yml
index f9932cfaca..f1cee7133f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -80,7 +80,7 @@ jobs:
QEMU_USER_CMD=""
- stage: test
- name: 'Win64 [GOAL: deploy] [unit tests, no gui, no functional tests]'
+ name: 'Win64 [GOAL: deploy] [unit tests, no gui, no boost::process, no functional tests]'
env: >-
FILE_ENV="./ci/test/00_setup_env_win64.sh"
diff --git a/build-aux/m4/ax_boost_process.m4 b/build-aux/m4/ax_boost_process.m4
new file mode 100644
index 0000000000..5d20e67464
--- /dev/null
+++ b/build-aux/m4/ax_boost_process.m4
@@ -0,0 +1,121 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_boost_process.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_BOOST_PROCESS
+#
+# DESCRIPTION
+#
+# Test for Process library from the Boost C++ libraries. The macro
+# requires a preceding call to AX_BOOST_BASE. Further documentation is
+# available at <http://randspringer.de/boost/index.html>.
+#
+# This macro calls:
+#
+# AC_SUBST(BOOST_PROCESS_LIB)
+#
+# And sets:
+#
+# HAVE_BOOST_PROCESS
+#
+# LICENSE
+#
+# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
+# Copyright (c) 2008 Michael Tindal
+# Copyright (c) 2008 Daniel Casimiro <dan.casimiro@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 2
+
+AC_DEFUN([AX_BOOST_PROCESS],
+[
+ AC_ARG_WITH([boost-process],
+ AS_HELP_STRING([--with-boost-process@<:@=special-lib@:>@],
+ [use the Process library from boost - it is possible to specify a certain library for the linker
+ e.g. --with-boost-process=boost_process-gcc-mt ]),
+ [
+ if test "$withval" = "no"; then
+ want_boost_process="no"
+ elif test "$withval" = "yes"; then
+ want_boost_process="yes"
+ ax_boost_user_process_lib=""
+ else
+ want_boost_process="yes"
+ ax_boost_user_process_lib="$withval"
+ fi
+ ],
+ [want_boost_process="yes"]
+ )
+
+ if test "x$want_boost_process" = "xyes"; then
+ AC_REQUIRE([AC_PROG_CC])
+ AC_REQUIRE([AC_CANONICAL_BUILD])
+ CPPFLAGS_SAVED="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+ export CPPFLAGS
+
+ LDFLAGS_SAVED="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
+ export LDFLAGS
+
+ AC_CACHE_CHECK(whether the Boost::Process library is available,
+ ax_cv_boost_process,
+ [AC_LANG_PUSH([C++])
+ CXXFLAGS_SAVE=$CXXFLAGS
+ CXXFLAGS=
+
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/process.hpp>]],
+ [[boost::process::child* child = new boost::process::child; delete child;]])],
+ ax_cv_boost_process=yes, ax_cv_boost_process=no)
+ CXXFLAGS=$CXXFLAGS_SAVE
+ AC_LANG_POP([C++])
+ ])
+ if test "x$ax_cv_boost_process" = "xyes"; then
+ AC_SUBST(BOOST_CPPFLAGS)
+
+ AC_DEFINE(HAVE_BOOST_PROCESS,,[define if the Boost::Process library is available])
+ BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
+
+ LDFLAGS_SAVE=$LDFLAGS
+ if test "x$ax_boost_user_process_lib" = "x"; then
+ for libextension in `ls -r $BOOSTLIBDIR/libboost_process* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
+ ax_lib=${libextension}
+ AC_CHECK_LIB($ax_lib, exit,
+ [BOOST_PROCESS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROCESS_LIB) link_process="yes"; break],
+ [link_process="no"])
+ done
+ if test "x$link_process" != "xyes"; then
+ for libextension in `ls -r $BOOSTLIBDIR/boost_process* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
+ ax_lib=${libextension}
+ AC_CHECK_LIB($ax_lib, exit,
+ [BOOST_PROCESS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROCESS_LIB) link_process="yes"; break],
+ [link_process="no"])
+ done
+ fi
+
+ else
+ for ax_lib in $ax_boost_user_process_lib boost_process-$ax_boost_user_process_lib; do
+ AC_CHECK_LIB($ax_lib, exit,
+ [BOOST_PROCESS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROCESS_LIB) link_process="yes"; break],
+ [link_process="no"])
+ done
+
+ fi
+ if test "x$ax_lib" = "x"; then
+ AC_MSG_ERROR(Could not find a version of the Boost::Process library!)
+ fi
+ if test "x$link_process" = "xno"; then
+ AC_MSG_ERROR(Could not link against $ax_lib !)
+ fi
+ fi
+
+ CPPFLAGS="$CPPFLAGS_SAVED"
+ LDFLAGS="$LDFLAGS_SAVED"
+ fi
+])
diff --git a/build_msvc/bitcoin_config.h b/build_msvc/bitcoin_config.h
index fbbe1a2156..9d0b50a0b4 100644
--- a/build_msvc/bitcoin_config.h
+++ b/build_msvc/bitcoin_config.h
@@ -47,6 +47,9 @@
/* define if the Boost::Filesystem library is available */
#define HAVE_BOOST_FILESYSTEM /**/
+/* define if the Boost::Process library is available */
+#define HAVE_BOOST_PROCESS /**/
+
/* define if the Boost::System library is available */
#define HAVE_BOOST_SYSTEM /**/
diff --git a/build_msvc/vcpkg-packages.txt b/build_msvc/vcpkg-packages.txt
index 307f295f08..edce8576c3 100644
--- a/build_msvc/vcpkg-packages.txt
+++ b/build_msvc/vcpkg-packages.txt
@@ -1 +1 @@
-berkeleydb boost-filesystem boost-multi-index boost-signals2 boost-test boost-thread libevent[thread] zeromq double-conversion \ No newline at end of file
+berkeleydb boost-filesystem boost-multi-index boost-process boost-signals2 boost-test boost-thread libevent[thread] zeromq double-conversion
diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh
index b70a581532..2e445c126d 100644
--- a/ci/test/00_setup_env_arm.sh
+++ b/ci/test/00_setup_env_arm.sh
@@ -25,4 +25,4 @@ export RUN_FUNCTIONAL_TESTS=true
export GOAL="install"
# -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1"
# This could be removed once the ABI change warning does not show up by default
-export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi --enable-werror"
+export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi --enable-werror --with-boost-process"
diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh
index 5688799f9e..e58003ab19 100644
--- a/ci/test/00_setup_env_i686_centos.sh
+++ b/ci/test/00_setup_env_i686_centos.sh
@@ -11,5 +11,5 @@ export CONTAINER_NAME=ci_i686_centos_7
export DOCKER_NAME_TAG=centos:7
export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python36-zmq which patch lbzip2 dash"
export GOAL="install"
-export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports"
+export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --with-boost-process"
export CONFIG_SHELL="/bin/dash"
diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh
index 7ec66eeb4f..b62f1603f4 100644
--- a/ci/test/00_setup_env_mac.sh
+++ b/ci/test/00_setup_env_mac.sh
@@ -14,4 +14,4 @@ export XCODE_BUILD_ID=11C505
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export GOAL="deploy"
-export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --enable-werror"
+export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --enable-werror --with-boost-process"
diff --git a/ci/test/00_setup_env_mac_host.sh b/ci/test/00_setup_env_mac_host.sh
index b8a9ccaae5..5fb127b762 100644
--- a/ci/test/00_setup_env_mac_host.sh
+++ b/ci/test/00_setup_env_mac_host.sh
@@ -10,7 +10,7 @@ export HOST=x86_64-apple-darwin16
export DOCKER_NAME_TAG=ubuntu:18.04 # Check that bionic can cross-compile to macos (bionic is used in the gitian build as well)
export PIP_PACKAGES="zmq"
export GOAL="install"
-export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --enable-werror"
+export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --enable-werror --with-boost-process"
export NO_DEPENDS=1
export OSX_SDK=""
export CCACHE_SIZE=300M
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index d57c673069..5995964f17 100644
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -12,4 +12,4 @@ export DOCKER_NAME_TAG=ubuntu:20.04
export NO_DEPENDS=1
export TEST_RUNNER_EXTRA="--timeout-factor=4" # Increase timeout because sanitizers slow down
export GOAL="install"
-export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
+export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++ --with-boost-process"
diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh
index 31f437f0e8..a32de4a6b5 100644
--- a/ci/test/00_setup_env_native_fuzz.sh
+++ b/ci/test/00_setup_env_native_fuzz.sh
@@ -14,5 +14,5 @@ export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=true
export GOAL="install"
-export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=clang CXX=clang++"
+export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=clang CXX=clang++ --with-boost-process"
export CCACHE_SIZE=200M
diff --git a/ci/test/00_setup_env_native_multiprocess.sh b/ci/test/00_setup_env_native_multiprocess.sh
index 786f0f927f..522a5d9fc2 100644
--- a/ci/test/00_setup_env_native_multiprocess.sh
+++ b/ci/test/00_setup_env_native_multiprocess.sh
@@ -11,5 +11,5 @@ export DOCKER_NAME_TAG=ubuntu:20.04
export PACKAGES="cmake python3"
export DEP_OPTS="MULTIPROCESS=1"
export GOAL="install"
-export BITCOIN_CONFIG=""
+export BITCOIN_CONFIG="--with-boost-process"
export TEST_RUNNER_ENV="BITCOIND=bitcoin-node"
diff --git a/ci/test/00_setup_env_native_nowallet.sh b/ci/test/00_setup_env_native_nowallet.sh
index 1a0b14b62b..0a09bfe230 100644
--- a/ci/test/00_setup_env_native_nowallet.sh
+++ b/ci/test/00_setup_env_native_nowallet.sh
@@ -11,4 +11,4 @@ export DOCKER_NAME_TAG=ubuntu:16.04 # Use xenial to have one config run the tes
export PACKAGES="python3-zmq clang-3.8 llvm-3.8" # Use clang-3.8 to test C++11 compatibility, see doc/dependencies.md
export DEP_OPTS="NO_WALLET=1"
export GOAL="install"
-export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CC=clang-3.8 CXX=clang++-3.8"
+export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CC=clang-3.8 CXX=clang++-3.8 --with-boost-process"
diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh
index 6e2ff729a2..f9d869b4fd 100644
--- a/ci/test/00_setup_env_native_qt5.sh
+++ b/ci/test/00_setup_env_native_qt5.sh
@@ -16,4 +16,4 @@ export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"
export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.15.2 v0.16.3 v0.17.1 v0.18.1 v0.19.1"
-export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-c++17 --enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\""
+export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-c++17 --enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\" --with-boost-process"
diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh
index 5695c43ec3..fc18483425 100644
--- a/ci/test/00_setup_env_native_tsan.sh
+++ b/ci/test/00_setup_env_native_tsan.sh
@@ -12,4 +12,4 @@ export PACKAGES="clang llvm libc++abi-dev libc++-dev python3-zmq"
export DEP_OPTS="CC=clang CXX='clang++ -stdlib=libc++'"
export TEST_RUNNER_EXTRA="--exclude feature_block --timeout-factor=4" # Increase timeout because sanitizers slow down. Low memory on Travis machines, exclude feature_block.
export GOAL="install"
-export BITCOIN_CONFIG="--enable-zmq --with-gui=no CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' CXXFLAGS='-g' --with-sanitizers=thread CC=clang CXX='clang++ -stdlib=libc++'"
+export BITCOIN_CONFIG="--enable-zmq --with-gui=no CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' CXXFLAGS='-g' --with-sanitizers=thread CC=clang CXX='clang++ -stdlib=libc++' --with-boost-process"
diff --git a/ci/test/00_setup_env_s390x.sh b/ci/test/00_setup_env_s390x.sh
index c180d023de..fe330920d0 100644
--- a/ci/test/00_setup_env_s390x.sh
+++ b/ci/test/00_setup_env_s390x.sh
@@ -22,4 +22,4 @@ export DOCKER_NAME_TAG="debian:buster"
export RUN_UNIT_TESTS=true
export RUN_FUNCTIONAL_TESTS=true
export GOAL="install"
-export BITCOIN_CONFIG="--enable-reduce-exports --with-incompatible-bdb"
+export BITCOIN_CONFIG="--enable-reduce-exports --with-incompatible-bdb --with-boost-process"
diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh
index eb8b870dd6..2b351dff6d 100644
--- a/ci/test/00_setup_env_win64.sh
+++ b/ci/test/00_setup_env_win64.sh
@@ -13,4 +13,4 @@ export PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64"
export RUN_FUNCTIONAL_TESTS=false
export RUN_SECURITY_TESTS="true"
export GOAL="deploy"
-export BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests"
+export BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests --without-boost-process"
diff --git a/configure.ac b/configure.ac
index f11f2b2059..2381c5dd08 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1180,9 +1180,9 @@ fi
if test x$use_boost = xyes; then
dnl Minimum required Boost version
-define(MINIMUM_REQUIRED_BOOST, 1.47.0)
+define(MINIMUM_REQUIRED_BOOST, 1.58.0)
-dnl Check for boost libs
+dnl Check for Boost libs
AX_BOOST_BASE([MINIMUM_REQUIRED_BOOST])
if test x$want_boost = xno; then
AC_MSG_ERROR([[only libbitcoinconsensus can be built without boost]])
@@ -1191,30 +1191,15 @@ AX_BOOST_SYSTEM
AX_BOOST_FILESYSTEM
AX_BOOST_THREAD
+dnl Opt-in to boost-process
+AS_IF([ test x$with_boost_process != x ], [ AX_BOOST_PROCESS ], [ ax_cv_boost_process=no ] )
+
dnl Boost 1.56 through 1.62 allow using std::atomic instead of its own atomic
dnl counter implementations. In 1.63 and later the std::atomic approach is default.
m4_pattern_allow(DBOOST_AC_USE_STD_ATOMIC) dnl otherwise it's treated like a macro
BOOST_CPPFLAGS="-DBOOST_SP_USE_STD_ATOMIC -DBOOST_AC_USE_STD_ATOMIC $BOOST_CPPFLAGS"
-if test x$use_reduce_exports = xyes; then
- AC_MSG_CHECKING([for working boost reduced exports])
- TEMP_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS"
- AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[
- @%:@include <boost/version.hpp>
- ]], [[
- #if BOOST_VERSION >= 104900
- // Everything is okay
- #else
- # error Boost version is too old
- #endif
- ]])],[
- AC_MSG_RESULT(yes)
- ],[
- AC_MSG_ERROR([boost versions < 1.49 are known to be broken with reduced exports. Use --disable-reduce-exports.])
- ])
- CPPFLAGS="$TEMP_CPPFLAGS"
-fi
+BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_THREAD_LIB"
fi
if test x$use_reduce_exports = xyes; then
@@ -1228,7 +1213,6 @@ if test x$use_tests = xyes; then
AC_MSG_ERROR(hexdump is required for tests)
fi
-
if test x$use_boost = xyes; then
AX_BOOST_UNIT_TEST_FRAMEWORK
@@ -1254,48 +1238,6 @@ if test x$use_tests = xyes; then
fi
fi
-if test x$use_boost = xyes; then
-
-BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_THREAD_LIB"
-
-
-dnl If boost (prior to 1.57) was built without c++11, it emulated scoped enums
-dnl using c++98 constructs. Unfortunately, this implementation detail leaked into
-dnl the abi. This was fixed in 1.57.
-
-dnl When building against that installed version using c++11, the headers pick up
-dnl on the native c++11 scoped enum support and enable it, however it will fail to
-dnl link. This can be worked around by disabling c++11 scoped enums if linking will
-dnl fail.
-dnl BOOST_NO_SCOPED_ENUMS was changed to BOOST_NO_CXX11_SCOPED_ENUMS in 1.51.
-
-TEMP_LIBS="$LIBS"
-LIBS="$BOOST_LIBS $LIBS"
-TEMP_CPPFLAGS="$CPPFLAGS"
-CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-AC_MSG_CHECKING([for mismatched boost c++11 scoped enums])
-AC_LINK_IFELSE([AC_LANG_PROGRAM([[
- #include <boost/config.hpp>
- #include <boost/version.hpp>
- #if !defined(BOOST_NO_SCOPED_ENUMS) && !defined(BOOST_NO_CXX11_SCOPED_ENUMS) && BOOST_VERSION < 105700
- #define BOOST_NO_SCOPED_ENUMS
- #define BOOST_NO_CXX11_SCOPED_ENUMS
- #define CHECK
- #endif
- #include <boost/filesystem.hpp>
- ]],[[
- #if defined(CHECK)
- boost::filesystem::copy_file("foo", "bar");
- #else
- choke;
- #endif
- ]])],
- [AC_MSG_RESULT(mismatched); BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS"], [AC_MSG_RESULT(ok)])
-LIBS="$TEMP_LIBS"
-CPPFLAGS="$TEMP_CPPFLAGS"
-
-fi
-
dnl libevent check
if test x$build_bitcoin_cli$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench != xnonononono; then
@@ -1683,6 +1625,7 @@ esac
echo
echo "Options used to compile and link:"
+echo " boost process = $ax_cv_boost_process"
echo " multiprocess = $build_multiprocess"
echo " with wallet = $enable_wallet"
echo " with gui / qt = $bitcoin_enable_qt"
diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp
index d2652119b4..ece02dc24e 100644
--- a/contrib/valgrind.supp
+++ b/contrib/valgrind.supp
@@ -123,7 +123,6 @@
Memcheck:Cond
...
fun:_ZN5boost10filesystem6detail11unique_pathERKNS0_4pathEPNS_6system10error_codeE
- fun:unique_path
}
{
Suppress boost warning
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index 3a7e605b4f..4f6b543aff 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -31,7 +31,9 @@ $(package)_cxxflags_linux=-fPIC
$(package)_cxxflags_android=-fPIC
endef
+# Fix unused variable in boost_process, can be removed after upgrading to 1.72
define $(package)_preprocess_cmds
+ sed -i.old "s/int ret_sig = 0;//" boost/process/detail/posix/wait_group.hpp && \
echo "using $($(package)_toolset_$(host_os)) : : $($(package)_cxx) : <cxxflags>\"$($(package)_cxxflags) $($(package)_cppflags)\" <linkflags>\"$($(package)_ldflags)\" <archiver>\"$($(package)_archiver_$(host_os))\" <striper>\"$(host_STRIP)\" <ranlib>\"$(host_RANLIB)\" <rc>\"$(host_WINDRES)\" : ;" > user-config.jam
endef
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index 7e307ab7c8..2f79168212 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -2073,7 +2073,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-PREDEFINED =
+PREDEFINED = HAVE_BOOST_PROCESS
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 0cb5311e8b..92dea65309 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -6,7 +6,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| Dependency | Version used | Minimum required | CVEs | Shared | [Bundled Qt library](https://doc.qt.io/qt-5/configure-options.html#third-party-libraries) |
| --- | --- | --- | --- | --- | --- |
| Berkeley DB | [4.8.30](https://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) | 4.8.x | No | | |
-| Boost | [1.70.0](https://www.boost.org/users/download/) | [1.47.0](https://github.com/bitcoin/bitcoin/pull/8920) | No | | |
+| Boost | [1.70.0](https://www.boost.org/users/download/) | [1.58.0](https://github.com/bitcoin/bitcoin/pull/19667) | No | | |
| Clang | | [3.3+](https://releases.llvm.org/download.html) (C++11 support) | | | |
| Expat | [2.2.7](https://libexpat.github.io/) | | No | Yes | |
| fontconfig | [2.12.1](https://www.freedesktop.org/software/fontconfig/release/) | | No | Yes | |
diff --git a/doc/release-notes/release-notes-0.20.1.md b/doc/release-notes/release-notes-0.20.1.md
new file mode 100644
index 0000000000..9fbb29cb82
--- /dev/null
+++ b/doc/release-notes/release-notes-0.20.1.md
@@ -0,0 +1,158 @@
+0.20.1 Release Notes
+====================
+
+Bitcoin Core version 0.20.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-0.20.1/>
+
+This minor release includes various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.12+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+From Bitcoin Core 0.20.0 onwards, macOS versions earlier than 10.12 are no
+longer supported. Additionally, Bitcoin Core does not yet change appearance
+when macOS "dark mode" is activated.
+
+Known Bugs
+==========
+
+The process for generating the source code release ("tarball") has changed in an
+effort to make it more complete, however, there are a few regressions in
+this release:
+
+- The generated `configure` script is currently missing, and you will need to
+ install autotools and run `./autogen.sh` before you can run
+ `./configure`. This is the same as when checking out from git.
+
+- Instead of running `make` simply, you should instead run
+ `BITCOIN_GENBUILD_NO_GIT=1 make`.
+
+Notable changes
+===============
+
+Changes regarding misbehaving peers
+-----------------------------------
+
+Peers that misbehave (e.g. send us invalid blocks) are now referred to as
+discouraged nodes in log output, as they're not (and weren't) strictly banned:
+incoming connections are still allowed from them, but they're preferred for
+eviction.
+
+Furthermore, a few additional changes are introduced to how discouraged
+addresses are treated:
+
+- Discouraging an address does not time out automatically after 24 hours
+ (or the `-bantime` setting). Depending on traffic from other peers,
+ discouragement may time out at an indeterminate time.
+
+- Discouragement is not persisted over restarts.
+
+- There is no method to list discouraged addresses. They are not returned by
+ the `listbanned` RPC. That RPC also no longer reports the `ban_reason`
+ field, as `"manually added"` is the only remaining option.
+
+- Discouragement cannot be removed with the `setban remove` RPC command.
+ If you need to remove a discouragement, you can remove all discouragements by
+ stop-starting your node.
+
+Notification changes
+--------------------
+
+`-walletnotify` notifications are now sent for wallet transactions that are
+removed from the mempool because they conflict with a new block. These
+notifications were sent previously before the v0.19 release, but had been
+broken since that release (bug
+[#18325](https://github.com/bitcoin/bitcoin/issues/18325)).
+
+PSBT changes
+------------
+
+PSBTs will contain both the non-witness utxo and the witness utxo for segwit
+inputs in order to restore compatibility with wallet software that are now
+requiring the full previous transaction for segwit inputs. The witness utxo
+is still provided to maintain compatibility with software which relied on its
+existence to determine whether an input was segwit.
+
+0.20.1 change log
+=================
+
+### Mining
+- #19019 Fix GBT: Restore "!segwit" and "csv" to "rules" key (luke-jr)
+
+### P2P protocol and network code
+- #19219 Replace automatic bans with discouragement filter (sipa)
+
+### Wallet
+- #19300 Handle concurrent wallet loading (promag)
+- #18982 Minimal fix to restore conflicted transaction notifications (ryanofsky)
+
+### RPC and other APIs
+- #19524 Increment input value sum only once per UTXO in decodepsbt (fanquake)
+- #19517 psbt: Increment input value sum only once per UTXO in decodepsbt (achow101)
+- #19215 psbt: Include and allow both non_witness_utxo and witness_utxo for segwit inputs (achow101)
+
+### GUI
+- #19097 Add missing QPainterPath include (achow101)
+- #19059 update Qt base translations for macOS release (fanquake)
+
+### Build system
+- #19152 improve build OS configure output (skmcontrib)
+- #19536 qt, build: Fix QFileDialog for static builds (hebasto)
+
+### Tests and QA
+- #19444 Remove cached directories and associated script blocks from appveyor config (sipsorcery)
+- #18640 appveyor: Remove clcache (MarcoFalke)
+
+### Miscellaneous
+- #19194 util: Don't reference errno when pthread fails (miztake)
+- #18700 Fix locking on WSL using flock instead of fcntl (meshcollider)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Aaron Clauson
+- Andrew Chow
+- fanquake
+- Hennadii Stepanov
+- João Barbosa
+- Luke Dashjr
+- MarcoFalke
+- MIZUTA Takeshi
+- Pieter Wuille
+- Russell Yanofsky
+- sachinkm77
+- Samuel Dobson
+- Wladimir J. van der Laan
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index b961f8d5b9..c3e46c0def 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -265,6 +265,7 @@ BITCOIN_TESTS =\
test/skiplist_tests.cpp \
test/streams_tests.cpp \
test/sync_tests.cpp \
+ test/system_tests.cpp \
test/util_threadnames_tests.cpp \
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
@@ -1207,7 +1208,7 @@ nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
$(BITCOIN_TESTS): $(GENERATED_TEST_FILES)
-CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) $(BITCOIN_TESTS:=.log)
+CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno test/fuzz/*.gcda test/fuzz/*.gcno $(GENERATED_TEST_FILES) $(BITCOIN_TESTS:=.log)
CLEANFILES += $(CLEAN_BITCOIN_TEST)
diff --git a/src/addrman.h b/src/addrman.h
index 8e82020df0..9e742339db 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -157,7 +157,7 @@ public:
#define ADDRMAN_GETADDR_MAX_PCT 23
//! the maximum number of nodes to return in a getaddr call
-#define ADDRMAN_GETADDR_MAX 2500
+#define ADDRMAN_GETADDR_MAX 1000
//! Convenience
#define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
diff --git a/src/base58.cpp b/src/base58.cpp
index 6a9e21ffc2..9b2946e7a9 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -141,7 +141,7 @@ std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
{
// add 4-byte hash check to the end
std::vector<unsigned char> vch(vchIn);
- uint256 hash = Hash(vch.begin(), vch.end());
+ uint256 hash = Hash(vch);
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
return EncodeBase58(vch);
}
@@ -154,7 +154,7 @@ bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int
return false;
}
// re-calculate the checksum, ensure it matches the included 4-byte checksum
- uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
+ uint256 hash = Hash(MakeSpan(vchRet).first(vchRet.size() - 4));
if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {
vchRet.clear();
return false;
diff --git a/src/bench/chacha_poly_aead.cpp b/src/bench/chacha_poly_aead.cpp
index 30d7851b7f..3b1d3e697a 100644
--- a/src/bench/chacha_poly_aead.cpp
+++ b/src/bench/chacha_poly_aead.cpp
@@ -93,7 +93,7 @@ static void HASH(benchmark::Bench& bench, size_t buffersize)
uint8_t hash[CHash256::OUTPUT_SIZE];
std::vector<uint8_t> in(buffersize,0);
bench.batch(in.size()).unit("byte").run([&] {
- CHash256().Write(in.data(), in.size()).Finalize(hash);
+ CHash256().Write(in).Finalize(hash);
});
}
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index c489bae4f6..9af0b502eb 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -34,7 +34,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
key.Set(vchKey.begin(), vchKey.end(), false);
CPubKey pubkey = key.GetPubKey();
uint160 pubkeyHash;
- CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin());
+ CHash160().Write(pubkey).Finalize(pubkeyHash);
// Script.
CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 5f5bed5bda..9a6fb4abd0 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -291,7 +291,7 @@ uint256 BlockFilter::GetHash() const
const std::vector<unsigned char>& data = GetEncodedFilter();
uint256 result;
- CHash256().Write(data.data(), data.size()).Finalize(result.begin());
+ CHash256().Write(data).Finalize(result);
return result;
}
@@ -301,8 +301,8 @@ uint256 BlockFilter::ComputeHeader(const uint256& prev_header) const
uint256 result;
CHash256()
- .Write(filter_hash.begin(), filter_hash.size())
- .Write(prev_header.begin(), prev_header.size())
- .Finalize(result.begin());
+ .Write(filter_hash)
+ .Write(prev_header)
+ .Finalize(result);
return result;
}
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 8de7a8f2d8..2a93a090d6 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -26,7 +26,8 @@ enum class TxValidationResult {
* is uninteresting.
*/
TX_RECENT_CONSENSUS_CHANGE,
- TX_NOT_STANDARD, //!< didn't meet our local policy rules
+ TX_INPUTS_NOT_STANDARD, //!< inputs (covered by txid) failed policy rules
+ TX_NOT_STANDARD, //!< otherwise didn't meet our local policy rules
TX_MISSING_INPUTS, //!< transaction was missing some of its inputs
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
/**
diff --git a/src/hash.cpp b/src/hash.cpp
index 26150e5ca8..4c09f5f646 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -12,7 +12,7 @@ inline uint32_t ROTL32(uint32_t x, int8_t r)
return (x << r) | (x >> (32 - r));
}
-unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash)
+unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vDataToHash)
{
// The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
uint32_t h1 = nHashSeed;
diff --git a/src/hash.h b/src/hash.h
index c295568a3e..71806483ff 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -25,14 +25,15 @@ private:
public:
static const size_t OUTPUT_SIZE = CSHA256::OUTPUT_SIZE;
- void Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ void Finalize(Span<unsigned char> output) {
+ assert(output.size() == OUTPUT_SIZE);
unsigned char buf[CSHA256::OUTPUT_SIZE];
sha.Finalize(buf);
- sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
+ sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(output.data());
}
- CHash256& Write(const unsigned char *data, size_t len) {
- sha.Write(data, len);
+ CHash256& Write(Span<const unsigned char> input) {
+ sha.Write(input.data(), input.size());
return *this;
}
@@ -49,14 +50,15 @@ private:
public:
static const size_t OUTPUT_SIZE = CRIPEMD160::OUTPUT_SIZE;
- void Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ void Finalize(Span<unsigned char> output) {
+ assert(output.size() == OUTPUT_SIZE);
unsigned char buf[CSHA256::OUTPUT_SIZE];
sha.Finalize(buf);
- CRIPEMD160().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
+ CRIPEMD160().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(output.data());
}
- CHash160& Write(const unsigned char *data, size_t len) {
- sha.Write(data, len);
+ CHash160& Write(Span<const unsigned char> input) {
+ sha.Write(input.data(), input.size());
return *this;
}
@@ -67,52 +69,31 @@ public:
};
/** Compute the 256-bit hash of an object. */
-template<typename T1>
-inline uint256 Hash(const T1 pbegin, const T1 pend)
+template<typename T>
+inline uint256 Hash(const T& in1)
{
- static const unsigned char pblank[1] = {};
uint256 result;
- CHash256().Write(pbegin == pend ? pblank : (const unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]))
- .Finalize((unsigned char*)&result);
+ CHash256().Write(MakeUCharSpan(in1)).Finalize(result);
return result;
}
/** Compute the 256-bit hash of the concatenation of two objects. */
template<typename T1, typename T2>
-inline uint256 Hash(const T1 p1begin, const T1 p1end,
- const T2 p2begin, const T2 p2end) {
- static const unsigned char pblank[1] = {};
+inline uint256 Hash(const T1& in1, const T2& in2) {
uint256 result;
- CHash256().Write(p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]))
- .Write(p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]))
- .Finalize((unsigned char*)&result);
+ CHash256().Write(MakeUCharSpan(in1)).Write(MakeUCharSpan(in2)).Finalize(result);
return result;
}
/** Compute the 160-bit hash an object. */
template<typename T1>
-inline uint160 Hash160(const T1 pbegin, const T1 pend)
+inline uint160 Hash160(const T1& in1)
{
- static unsigned char pblank[1] = {};
uint160 result;
- CHash160().Write(pbegin == pend ? pblank : (const unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]))
- .Finalize((unsigned char*)&result);
+ CHash160().Write(MakeUCharSpan(in1)).Finalize(result);
return result;
}
-/** Compute the 160-bit hash of a vector. */
-inline uint160 Hash160(const std::vector<unsigned char>& vch)
-{
- return Hash160(vch.begin(), vch.end());
-}
-
-/** Compute the 160-bit hash of a vector. */
-template<unsigned int N>
-inline uint160 Hash160(const prevector<N, unsigned char>& vch)
-{
- return Hash160(vch.begin(), vch.end());
-}
-
/** A writer stream (for serialization) that computes a 256-bit hash. */
class CHashWriter
{
@@ -129,13 +110,13 @@ public:
int GetVersion() const { return nVersion; }
void write(const char *pch, size_t size) {
- ctx.Write((const unsigned char*)pch, size);
+ ctx.Write({(const unsigned char*)pch, size});
}
// invalidates the object
uint256 GetHash() {
uint256 result;
- ctx.Finalize((unsigned char*)&result);
+ ctx.Finalize(result);
return result;
}
@@ -200,7 +181,7 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
return ss.GetHash();
}
-unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
+unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vDataToHash);
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 33f0dac263..969767b90f 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -56,6 +56,7 @@ namespace {
class NodeImpl : public Node
{
public:
+ NodeImpl(NodeContext* context) { setContext(context); }
void initError(const bilingual_str& message) override { InitError(message); }
bool parseParameters(int argc, const char* const argv[], std::string& error) override
{
@@ -81,13 +82,13 @@ public:
}
bool appInitMain() override
{
- m_context.chain = MakeChain(m_context);
- return AppInitMain(m_context_ref, m_context);
+ m_context->chain = MakeChain(*m_context);
+ return AppInitMain(m_context_ref, *m_context);
}
void appShutdown() override
{
- Interrupt(m_context);
- Shutdown(m_context);
+ Interrupt(*m_context);
+ Shutdown(*m_context);
}
void startShutdown() override
{
@@ -108,19 +109,19 @@ public:
StopMapPort();
}
}
- void setupServerArgs() override { return SetupServerArgs(m_context); }
+ void setupServerArgs() override { return SetupServerArgs(*m_context); }
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
size_t getNodeCount(CConnman::NumConnections flags) override
{
- return m_context.connman ? m_context.connman->GetNodeCount(flags) : 0;
+ return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0;
}
bool getNodesStats(NodesStats& stats) override
{
stats.clear();
- if (m_context.connman) {
+ if (m_context->connman) {
std::vector<CNodeStats> stats_temp;
- m_context.connman->GetNodeStats(stats_temp);
+ m_context->connman->GetNodeStats(stats_temp);
stats.reserve(stats_temp.size());
for (auto& node_stats_temp : stats_temp) {
@@ -141,46 +142,46 @@ public:
}
bool getBanned(banmap_t& banmap) override
{
- if (m_context.banman) {
- m_context.banman->GetBanned(banmap);
+ if (m_context->banman) {
+ m_context->banman->GetBanned(banmap);
return true;
}
return false;
}
bool ban(const CNetAddr& net_addr, int64_t ban_time_offset) override
{
- if (m_context.banman) {
- m_context.banman->Ban(net_addr, ban_time_offset);
+ if (m_context->banman) {
+ m_context->banman->Ban(net_addr, ban_time_offset);
return true;
}
return false;
}
bool unban(const CSubNet& ip) override
{
- if (m_context.banman) {
- m_context.banman->Unban(ip);
+ if (m_context->banman) {
+ m_context->banman->Unban(ip);
return true;
}
return false;
}
bool disconnectByAddress(const CNetAddr& net_addr) override
{
- if (m_context.connman) {
- return m_context.connman->DisconnectNode(net_addr);
+ if (m_context->connman) {
+ return m_context->connman->DisconnectNode(net_addr);
}
return false;
}
bool disconnectById(NodeId id) override
{
- if (m_context.connman) {
- return m_context.connman->DisconnectNode(id);
+ if (m_context->connman) {
+ return m_context->connman->DisconnectNode(id);
}
return false;
}
- int64_t getTotalBytesRecv() override { return m_context.connman ? m_context.connman->GetTotalBytesRecv() : 0; }
- int64_t getTotalBytesSent() override { return m_context.connman ? m_context.connman->GetTotalBytesSent() : 0; }
- size_t getMempoolSize() override { return m_context.mempool ? m_context.mempool->size() : 0; }
- size_t getMempoolDynamicUsage() override { return m_context.mempool ? m_context.mempool->DynamicMemoryUsage() : 0; }
+ int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; }
+ int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; }
+ size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; }
+ size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; }
bool getHeaderTip(int& height, int64_t& block_time) override
{
LOCK(::cs_main);
@@ -223,11 +224,11 @@ public:
bool getImporting() override { return ::fImporting; }
void setNetworkActive(bool active) override
{
- if (m_context.connman) {
- m_context.connman->SetNetworkActive(active);
+ if (m_context->connman) {
+ m_context->connman->SetNetworkActive(active);
}
}
- bool getNetworkActive() override { return m_context.connman && m_context.connman->GetNetworkActive(); }
+ bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override
{
FeeCalculation fee_calc;
@@ -269,7 +270,7 @@ public:
std::vector<std::unique_ptr<Wallet>> getWallets() override
{
std::vector<std::unique_ptr<Wallet>> wallets;
- for (auto& client : m_context.chain_clients) {
+ for (auto& client : m_context->chain_clients) {
auto client_wallets = client->getWallets();
std::move(client_wallets.begin(), client_wallets.end(), std::back_inserter(wallets));
}
@@ -277,12 +278,12 @@ public:
}
std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
- return MakeWallet(LoadWallet(*m_context.chain, name, error, warnings));
+ return MakeWallet(LoadWallet(*m_context->chain, name, error, warnings));
}
std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) override
{
std::shared_ptr<CWallet> wallet;
- status = CreateWallet(*m_context.chain, passphrase, wallet_creation_flags, name, error, warnings, wallet);
+ status = CreateWallet(*m_context->chain, passphrase, wallet_creation_flags, name, error, warnings, wallet);
return MakeWallet(wallet);
}
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
@@ -336,13 +337,22 @@ public:
/* verification progress is unused when a header was received */ 0);
}));
}
- NodeContext* context() override { return &m_context; }
- NodeContext m_context;
- util::Ref m_context_ref{m_context};
+ NodeContext* context() override { return m_context; }
+ void setContext(NodeContext* context) override
+ {
+ m_context = context;
+ if (context) {
+ m_context_ref.Set(*context);
+ } else {
+ m_context_ref.Clear();
+ }
+ }
+ NodeContext* m_context{nullptr};
+ util::Ref m_context_ref;
};
} // namespace
-std::unique_ptr<Node> MakeNode() { return MakeUnique<NodeImpl>(); }
+std::unique_ptr<Node> MakeNode(NodeContext* context) { return MakeUnique<NodeImpl>(context); }
} // namespace interfaces
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index a9680c42b5..cd3cfe487d 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -268,12 +268,14 @@ public:
std::function<void(SynchronizationState, interfaces::BlockTip tip, double verification_progress)>;
virtual std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0;
- //! Return pointer to internal chain interface, useful for testing.
+ //! Get and set internal node context. Useful for testing, but not
+ //! accessible across processes.
virtual NodeContext* context() { return nullptr; }
+ virtual void setContext(NodeContext* context) { }
};
//! Return implementation of Node interface.
-std::unique_ptr<Node> MakeNode();
+std::unique_ptr<Node> MakeNode(NodeContext* context = nullptr);
//! Block tip (could be a header or not, depends on the subscribed signal).
struct BlockTip {
diff --git a/src/key.cpp b/src/key.cpp
index 7eecc6e083..4ed74a39b1 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -237,7 +237,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
std::string str = "Bitcoin key verification\n";
GetRandBytes(rnd, sizeof(rnd));
uint256 hash;
- CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin());
+ CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
std::vector<unsigned char> vchSig;
Sign(hash, vchSig);
return pubkey.Verify(hash, vchSig);
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index 8072b12119..b571d463c9 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -70,7 +70,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve
else
right = left;
// combine subhashes
- return Hash(left.begin(), left.end(), right.begin(), right.end());
+ return Hash(left, right);
}
}
@@ -126,7 +126,7 @@ uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, uns
right = left;
}
// and combine them before returning
- return Hash(left.begin(), left.end(), right.begin(), right.end());
+ return Hash(left, right);
}
}
diff --git a/src/net.cpp b/src/net.cpp
index 0c56cddbdc..9c72c62df9 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -685,7 +685,7 @@ int V1TransportDeserializer::readData(const char *pch, unsigned int nBytes)
vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
}
- hasher.Write((const unsigned char*)pch, nCopy);
+ hasher.Write({(const unsigned char*)pch, nCopy});
memcpy(&vRecv[nDataPos], pch, nCopy);
nDataPos += nCopy;
@@ -696,7 +696,7 @@ const uint256& V1TransportDeserializer::GetMessageHash() const
{
assert(Complete());
if (data_hash.IsNull())
- hasher.Finalize(data_hash.begin());
+ hasher.Finalize(data_hash);
return data_hash;
}
@@ -736,7 +736,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const CMessageHeader::MessageSta
void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) {
// create dbl-sha256 checksum
- uint256 hash = Hash(msg.data.begin(), msg.data.end());
+ uint256 hash = Hash(msg.data);
// create header
CMessageHeader hdr(Params().MessageStart(), msg.m_type.c_str(), msg.data.size());
@@ -2530,7 +2530,24 @@ void CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddres
std::vector<CAddress> CConnman::GetAddresses()
{
- return addrman.GetAddr();
+ std::vector<CAddress> addresses = addrman.GetAddr();
+ if (m_banman) {
+ addresses.erase(std::remove_if(addresses.begin(), addresses.end(),
+ [this](const CAddress& addr){return m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr);}),
+ addresses.end());
+ }
+ return addresses;
+}
+
+std::vector<CAddress> CConnman::GetAddresses(Network requestor_network)
+{
+ const auto current_time = GetTime<std::chrono::microseconds>();
+ if (m_addr_response_caches.find(requestor_network) == m_addr_response_caches.end() ||
+ m_addr_response_caches[requestor_network].m_update_addr_response < current_time) {
+ m_addr_response_caches[requestor_network].m_addrs_response_cache = GetAddresses();
+ m_addr_response_caches[requestor_network].m_update_addr_response = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6));
+ }
+ return m_addr_response_caches[requestor_network].m_addrs_response_cache;
}
bool CConnman::AddNode(const std::string& strNode)
diff --git a/src/net.h b/src/net.h
index 17d8fda372..1c558ee810 100644
--- a/src/net.h
+++ b/src/net.h
@@ -27,6 +27,7 @@
#include <atomic>
#include <cstdint>
#include <deque>
+#include <map>
#include <thread>
#include <memory>
#include <condition_variable>
@@ -52,6 +53,9 @@ static const int TIMEOUT_INTERVAL = 20 * 60;
static const int FEELER_INTERVAL = 120;
/** The maximum number of new addresses to accumulate before announcing. */
static const unsigned int MAX_ADDR_TO_SEND = 1000;
+// TODO: remove ADDRMAN_GETADDR_MAX and let the caller specify this limit with MAX_ADDR_TO_SEND.
+static_assert(MAX_ADDR_TO_SEND == ADDRMAN_GETADDR_MAX,
+ "Max allowed ADDR message size should be equal to the max number of records returned from AddrMan.");
/** Maximum length of incoming protocol messages (no message over 4 MB is currently acceptable). */
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
/** Maximum length of the user agent string in `version` message */
@@ -251,6 +255,13 @@ public:
void MarkAddressGood(const CAddress& addr);
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
std::vector<CAddress> GetAddresses();
+ /**
+ * Cache is used to minimize topology leaks, so it should
+ * be used for all non-trusted calls, for example, p2p.
+ * A non-malicious call (from RPC or a peer with addr permission) should
+ * call the function without a parameter to avoid using the cache.
+ */
+ std::vector<CAddress> GetAddresses(Network requestor_network);
// This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
// a peer that is better than all our current peers.
@@ -416,6 +427,29 @@ private:
unsigned int nPrevNodeCount{0};
/**
+ * Cache responses to addr requests to minimize privacy leak.
+ * Attack example: scraping addrs in real-time may allow an attacker
+ * to infer new connections of the victim by detecting new records
+ * with fresh timestamps (per self-announcement).
+ */
+ struct CachedAddrResponse {
+ std::vector<CAddress> m_addrs_response_cache;
+ std::chrono::microseconds m_update_addr_response{0};
+ };
+
+ /**
+ * Addr responses stored in different caches
+ * per network prevent cross-network node identification.
+ * If a node for example is multi-homed under Tor and IPv6,
+ * a single cache (or no cache at all) would let an attacker
+ * to easily detect that it is the same node by comparing responses.
+ * The used memory equals to 1000 CAddress records (or around 32 bytes) per
+ * distinct Network (up to 5) we have/had an inbound peer from,
+ * resulting in at most ~160 KB.
+ */
+ std::map<Network, CachedAddrResponse> m_addr_response_caches;
+
+ /**
* Services this instance offers.
*
* This data is replicated in each CNode instance we create during peer
diff --git a/src/net_permissions.cpp b/src/net_permissions.cpp
index a75838307c..53648deb40 100644
--- a/src/net_permissions.cpp
+++ b/src/net_permissions.cpp
@@ -15,6 +15,7 @@ const std::vector<std::string> NET_PERMISSIONS_DOC{
"relay (relay even in -blocksonly mode)",
"mempool (allow requesting BIP35 mempool contents)",
"download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",
+ "addr (responses to GETADDR avoid hitting the cache and contain random records with the most up-to-date info)"
};
namespace {
@@ -50,6 +51,7 @@ bool TryParsePermissionFlags(const std::string str, NetPermissionFlags& output,
else if (permission == "download") NetPermissions::AddFlag(flags, PF_DOWNLOAD);
else if (permission == "all") NetPermissions::AddFlag(flags, PF_ALL);
else if (permission == "relay") NetPermissions::AddFlag(flags, PF_RELAY);
+ else if (permission == "addr") NetPermissions::AddFlag(flags, PF_ADDR);
else if (permission.length() == 0); // Allow empty entries
else {
error = strprintf(_("Invalid P2P permission: '%s'"), permission);
@@ -75,6 +77,7 @@ std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
if (NetPermissions::HasFlag(flags, PF_RELAY)) strings.push_back("relay");
if (NetPermissions::HasFlag(flags, PF_MEMPOOL)) strings.push_back("mempool");
if (NetPermissions::HasFlag(flags, PF_DOWNLOAD)) strings.push_back("download");
+ if (NetPermissions::HasFlag(flags, PF_ADDR)) strings.push_back("addr");
return strings;
}
diff --git a/src/net_permissions.h b/src/net_permissions.h
index a9633ee2ae..5b68f635a7 100644
--- a/src/net_permissions.h
+++ b/src/net_permissions.h
@@ -29,10 +29,12 @@ enum NetPermissionFlags {
PF_NOBAN = (1U << 4) | PF_DOWNLOAD,
// Can query the mempool
PF_MEMPOOL = (1U << 5),
+ // Can request addrs without hitting a privacy-preserving cache
+ PF_ADDR = (1U << 7),
// True if the user did not specifically set fine grained permissions
PF_ISIMPLICIT = (1U << 31),
- PF_ALL = PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY | PF_NOBAN | PF_MEMPOOL | PF_DOWNLOAD,
+ PF_ALL = PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY | PF_NOBAN | PF_MEMPOOL | PF_DOWNLOAD | PF_ADDR,
};
class NetPermissions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 88e73cd804..72c8e65c6b 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -187,7 +187,7 @@ namespace {
* million to make it highly unlikely for users to have issues with this
* filter.
*
- * We only need to add wtxids to this filter. For non-segwit
+ * We typically only add wtxids to this filter. For non-segwit
* transactions, the txid == wtxid, so this only prevents us from
* re-downloading non-segwit transactions when communicating with
* non-wtxidrelay peers -- which is important for avoiding malleation
@@ -196,6 +196,12 @@ namespace {
* the reject filter store wtxids is exactly what we want to avoid
* redownload of a rejected transaction.
*
+ * In cases where we can tell that a segwit transaction will fail
+ * validation no matter the witness, we may add the txid of such
+ * transaction to the filter as well. This can be helpful when
+ * communicating with txid-relay peers or if we were to otherwise fetch a
+ * transaction via txid (eg in our orphan handling).
+ *
* Memory used: 1.3 MB
*/
std::unique_ptr<CRollingBloomFilter> recentRejects GUARDED_BY(cs_main);
@@ -1161,6 +1167,7 @@ static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state,
}
// Conflicting (but not necessarily invalid) data or different policy:
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
+ case TxValidationResult::TX_INPUTS_NOT_STANDARD:
case TxValidationResult::TX_NOT_STANDARD:
case TxValidationResult::TX_MISSING_INPUTS:
case TxValidationResult::TX_PREMATURE_SPEND:
@@ -2052,6 +2059,19 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
// if we start doing this too early.
assert(recentRejects);
recentRejects->insert(orphanTx.GetWitnessHash());
+ // If the transaction failed for TX_INPUTS_NOT_STANDARD,
+ // then we know that the witness was irrelevant to the policy
+ // failure, since this check depends only on the txid
+ // (the scriptPubKey being spent is covered by the txid).
+ // Add the txid to the reject filter to prevent repeated
+ // processing of this transaction in the event that child
+ // transactions are later received (resulting in
+ // parent-fetching by txid via the orphan-handling logic).
+ if (orphan_state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && orphanTx.GetWitnessHash() != orphanTx.GetHash()) {
+ // We only add the txid if it differs from the wtxid, to
+ // avoid wasting entries in the rolling bloom filter.
+ recentRejects->insert(orphanTx.GetHash());
+ }
}
EraseOrphanTx(orphanHash);
done = true;
@@ -2541,7 +2561,7 @@ void ProcessMessage(
if (!pfrom.IsAddrRelayPeer()) {
return;
}
- if (vAddr.size() > 1000)
+ if (vAddr.size() > MAX_ADDR_TO_SEND)
{
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("addr message size = %u", vAddr.size()));
@@ -2943,7 +2963,7 @@ void ProcessMessage(
// We do the AlreadyHave() check using wtxid, rather than txid - in the
// absence of witness malleation, this is strictly better, because the
- // recent rejects filter may contain the wtxid but will never contain
+ // recent rejects filter may contain the wtxid but rarely contains
// the txid of a segwit transaction that has been rejected.
// In the presence of witness malleation, it's possible that by only
// doing the check with wtxid, we could overlook a transaction which
@@ -3035,6 +3055,17 @@ void ProcessMessage(
// if we start doing this too early.
assert(recentRejects);
recentRejects->insert(tx.GetWitnessHash());
+ // If the transaction failed for TX_INPUTS_NOT_STANDARD,
+ // then we know that the witness was irrelevant to the policy
+ // failure, since this check depends only on the txid
+ // (the scriptPubKey being spent is covered by the txid).
+ // Add the txid to the reject filter to prevent repeated
+ // processing of this transaction in the event that child
+ // transactions are later received (resulting in
+ // parent-fetching by txid via the orphan-handling logic).
+ if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && tx.GetWitnessHash() != tx.GetHash()) {
+ recentRejects->insert(tx.GetHash());
+ }
if (RecursiveDynamicUsage(*ptx) < 100000) {
AddToCompactExtraTransactions(ptx);
}
@@ -3474,13 +3505,15 @@ void ProcessMessage(
pfrom.fSentAddr = true;
pfrom.vAddrToSend.clear();
- std::vector<CAddress> vAddr = connman.GetAddresses();
+ std::vector<CAddress> vAddr;
+ if (pfrom.HasPermission(PF_ADDR)) {
+ vAddr = connman.GetAddresses();
+ } else {
+ vAddr = connman.GetAddresses(pfrom.addr.GetNetwork());
+ }
FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr) {
- bool banned_or_discouraged = banman && (banman->IsDiscouraged(addr) || banman->IsBanned(addr));
- if (!banned_or_discouraged) {
- pfrom.PushAddress(addr, insecure_rand);
- }
+ pfrom.PushAddress(addr, insecure_rand);
}
return;
}
@@ -4079,8 +4112,8 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
{
pto->m_addr_known->insert(addr.GetKey());
vAddr.push_back(addr);
- // receiver rejects addr messages larger than 1000
- if (vAddr.size() >= 1000)
+ // receiver rejects addr messages larger than MAX_ADDR_TO_SEND
+ if (vAddr.size() >= MAX_ADDR_TO_SEND)
{
connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
vAddr.clear();
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 0874b8dcea..d29aed6c8b 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -553,7 +553,7 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
uint64_t CNetAddr::GetHash() const
{
- uint256 hash = Hash(&ip[0], &ip[16]);
+ uint256 hash = Hash(ip);
uint64_t nRet;
memcpy(&nRet, &hash, sizeof(nRet));
return nRet;
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index c56abaf6c9..0e9820da1e 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -152,6 +152,8 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
* script can be anything; an attacker could use a very
* expensive-to-check-upon-redemption script like:
* DUP CHECKSIG DROP ... repeated 100 times... OP_1
+ *
+ * Note that only the non-witness portion of the transaction is checked here.
*/
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
@@ -164,7 +166,11 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
std::vector<std::vector<unsigned char> > vSolutions;
TxoutType whichType = Solver(prev.scriptPubKey, vSolutions);
- if (whichType == TxoutType::NONSTANDARD) {
+ if (whichType == TxoutType::NONSTANDARD || whichType == TxoutType::WITNESS_UNKNOWN) {
+ // WITNESS_UNKNOWN failures are typically also caught with a policy
+ // flag in the script interpreter, but it can be helpful to catch
+ // this type of NONSTANDARD transaction earlier in transaction
+ // validation.
return false;
} else if (whichType == TxoutType::SCRIPTHASH) {
std::vector<std::vector<unsigned char> > stack;
diff --git a/src/protocol.h b/src/protocol.h
index d6767cc3e0..1d0adaae6e 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -64,100 +64,84 @@ namespace NetMsgType {
/**
* The version message provides information about the transmitting node to the
* receiving node at the beginning of a connection.
- * @see https://bitcoin.org/en/developer-reference#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;
/**
* 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;
/**
* 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;
/**
* The getdata message requests one or more data objects from another node.
- * @see https://bitcoin.org/en/developer-reference#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;
/**
* 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;
/**
* 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;
/**
* The tx message transmits a single transaction.
- * @see https://bitcoin.org/en/developer-reference#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;
/**
* The block message transmits a single serialized block.
- * @see https://bitcoin.org/en/developer-reference#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;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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;
/**
@@ -166,7 +150,6 @@ extern const char* NOTFOUND;
* @since protocol version 70001 as described by BIP37.
* Only available with service bit NODE_BLOOM since protocol version
* 70011 as described by BIP111.
- * @see https://bitcoin.org/en/developer-reference#filterload
*/
extern const char* FILTERLOAD;
/**
@@ -175,7 +158,6 @@ extern const char* FILTERLOAD;
* @since protocol version 70001 as described by BIP37.
* Only available with service bit NODE_BLOOM since protocol version
* 70011 as described by BIP111.
- * @see https://bitcoin.org/en/developer-reference#filteradd
*/
extern const char* FILTERADD;
/**
@@ -184,14 +166,12 @@ extern const char* FILTERADD;
* @since protocol version 70001 as described by BIP37.
* Only available with service bit NODE_BLOOM since protocol version
* 70011 as described by BIP111.
- * @see https://bitcoin.org/en/developer-reference#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;
/**
diff --git a/src/pubkey.h b/src/pubkey.h
index 4c28af4a4d..fcbc7e8416 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -157,13 +157,13 @@ public:
//! Get the KeyID of this public key (hash of its serialization)
CKeyID GetID() const
{
- return CKeyID(Hash160(vch, vch + size()));
+ return CKeyID(Hash160(MakeSpan(vch).first(size())));
}
//! Get the 256-bit hash of this public key.
uint256 GetHash() const
{
- return Hash(vch, vch + size());
+ return Hash(MakeSpan(vch).first(size()));
}
/*
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 523f5c429b..4f1e0056be 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -29,6 +29,7 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
+#include <node/context.h>
#include <noui.h>
#include <uint256.h>
#include <util/system.h>
@@ -430,7 +431,8 @@ int GuiMain(int argc, char* argv[])
SetupEnvironment();
util::ThreadSetInternalName("main");
- std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
+ NodeContext node_context;
+ std::unique_ptr<interfaces::Node> node = interfaces::MakeNode(&node_context);
// Subscribe to global signals from core
std::unique_ptr<interfaces::Handler> handler_message_box = node->handleMessageBox(noui_ThreadSafeMessageBox);
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 9347ff9e42..035c8196bc 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -18,6 +18,7 @@
#include <key.h>
#include <key_io.h>
#include <wallet/wallet.h>
+#include <walletinitinterface.h>
#include <QApplication>
#include <QTimer>
@@ -59,6 +60,7 @@ void EditAddressAndSubmit(
void TestAddAddressesToSendBook(interfaces::Node& node)
{
TestChain100Setup test;
+ node.setContext(&test.m_node);
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), CreateMockWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
bool firstRun;
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 12efca2503..031913bd02 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -52,7 +52,8 @@ int main(int argc, char* argv[])
BasicTestingSetup dummy{CBaseChainParams::REGTEST};
}
- std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
+ NodeContext node_context;
+ std::unique_ptr<interfaces::Node> node = interfaces::MakeNode(&node_context);
bool fInvalid = false;
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 6648029bae..475fd589af 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -138,8 +138,7 @@ void TestGUI(interfaces::Node& node)
for (int i = 0; i < 5; ++i) {
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
}
- node.context()->connman = std::move(test.m_node.connman);
- node.context()->mempool = std::move(test.m_node.mempool);
+ node.setContext(&test.m_node);
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), CreateMockWalletDatabase());
bool firstRun;
wallet->LoadWallet(firstRun);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 70caf6009a..cf856af6e9 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -601,7 +601,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
UniValue sr(UniValue::VOBJ);
CScript segwitScr;
if (which_type == TxoutType::PUBKEY) {
- segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0].begin(), solutions_data[0].end())));
+ segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0])));
} else if (which_type == TxoutType::PUBKEYHASH) {
segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]}));
} else {
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 9415bba585..39feb4ccc9 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -986,9 +986,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
else if (opcode == OP_SHA256)
CSHA256().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_HASH160)
- CHash160().Write(vch.data(), vch.size()).Finalize(vchHash.data());
+ CHash160().Write(vch).Finalize(vchHash);
else if (opcode == OP_HASH256)
- CHash256().Write(vch.data(), vch.size()).Finalize(vchHash.data());
+ CHash256().Write(vch).Finalize(vchHash);
popstack(stack);
stack.push_back(vchHash);
}
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 1c4990791c..3a4882f280 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -16,10 +16,10 @@ typedef std::vector<unsigned char> valtype;
bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
-CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in.begin(), in.end())) {}
+CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in)) {}
CScriptID::CScriptID(const ScriptHash& in) : BaseHash(static_cast<uint160>(in)) {}
-ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in.begin(), in.end())) {}
+ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in)) {}
ScriptHash::ScriptHash(const CScriptID& in) : BaseHash(static_cast<uint160>(in)) {}
PKHash::PKHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
@@ -318,7 +318,7 @@ CScript GetScriptForWitness(const CScript& redeemscript)
std::vector<std::vector<unsigned char> > vSolutions;
TxoutType typ = Solver(redeemscript, vSolutions);
if (typ == TxoutType::PUBKEY) {
- return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
+ return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0])));
} else if (typ == TxoutType::PUBKEYHASH) {
return GetScriptForDestination(WitnessV0KeyHash(uint160{vSolutions[0]}));
}
diff --git a/src/script/standard.h b/src/script/standard.h
index fd29353886..992e37675f 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -79,6 +79,9 @@ public:
{
return m_hash.size();
}
+
+ unsigned char* data() { return m_hash.data(); }
+ const unsigned char* data() const { return m_hash.data(); }
};
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
diff --git a/src/span.h b/src/span.h
index 79f13c9203..4afb383a59 100644
--- a/src/span.h
+++ b/src/span.h
@@ -207,4 +207,16 @@ T& SpanPopBack(Span<T>& span)
return back;
}
+// Helper functions to safely cast to unsigned char pointers.
+inline unsigned char* UCharCast(char* c) { return (unsigned char*)c; }
+inline unsigned char* UCharCast(unsigned char* c) { return c; }
+inline const unsigned char* UCharCast(const char* c) { return (unsigned char*)c; }
+inline const unsigned char* UCharCast(const unsigned char* c) { return c; }
+
+// Helper function to safely convert a Span to a Span<[const] unsigned char>.
+template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename std::remove_pointer<decltype(UCharCast(s.data()))>::type> { return {UCharCast(s.data()), s.size()}; }
+
+/** Like MakeSpan, but for (const) unsigned char member types only. Only works for (un)signed char containers. */
+template <typename V> constexpr auto MakeUCharSpan(V&& v) -> decltype(UCharSpanCast(MakeSpan(std::forward<V>(v)))) { return UCharSpanCast(MakeSpan(std::forward<V>(v))); }
+
#endif
diff --git a/src/sync.cpp b/src/sync.cpp
index 10f0483189..4be13a3c48 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -149,12 +149,17 @@ static void push_lock(void* c, const CLockLocation& locklocation)
const LockPair p1 = std::make_pair(i.first, c);
if (lockdata.lockorders.count(p1))
continue;
- lockdata.lockorders.emplace(p1, lock_stack);
const LockPair p2 = std::make_pair(c, i.first);
+ if (lockdata.lockorders.count(p2)) {
+ auto lock_stack_copy = lock_stack;
+ lock_stack.pop_back();
+ potential_deadlock_detected(p1, lockdata.lockorders[p2], lock_stack_copy);
+ // potential_deadlock_detected() does not return.
+ }
+
+ lockdata.lockorders.emplace(p1, lock_stack);
lockdata.invlockorders.insert(p2);
- if (lockdata.lockorders.count(p2))
- potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
}
}
@@ -259,6 +264,17 @@ void DeleteLock(void* cs)
}
}
+bool LockStackEmpty()
+{
+ LockData& lockdata = GetLockData();
+ std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
+ const auto it = lockdata.m_lock_stacks.find(std::this_thread::get_id());
+ if (it == lockdata.m_lock_stacks.end()) {
+ return true;
+ }
+ return it->second.empty();
+}
+
bool g_debug_lockorder_abort = true;
#endif /* DEBUG_LOCKORDER */
diff --git a/src/sync.h b/src/sync.h
index 77327d8bfe..05ff2ee8a9 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -56,6 +56,7 @@ template <typename MutexType>
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) ASSERT_EXCLUSIVE_LOCK(cs);
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
void DeleteLock(void* cs);
+bool LockStackEmpty();
/**
* Call abort() if a potential lock order deadlock bug is detected, instead of
@@ -64,13 +65,14 @@ void DeleteLock(void* cs);
*/
extern bool g_debug_lockorder_abort;
#else
-void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
-void static inline LeaveCritical() {}
-void static inline CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
+inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
+inline void LeaveCritical() {}
+inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
template <typename MutexType>
-void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) ASSERT_EXCLUSIVE_LOCK(cs) {}
-void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
-void static inline DeleteLock(void* cs) {}
+inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) ASSERT_EXCLUSIVE_LOCK(cs) {}
+inline void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
+inline void DeleteLock(void* cs) {}
+inline bool LockStackEmpty() { return true; }
#endif
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index f64251fe32..bf5c587774 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -743,7 +743,7 @@ BOOST_AUTO_TEST_CASE(sha256d64)
in[j] = InsecureRandBits(8);
}
for (int j = 0; j < i; ++j) {
- CHash256().Write(in + 64 * j, 64).Finalize(out1 + 32 * j);
+ CHash256().Write({in + 64 * j, 64}).Finalize({out1 + 32 * j, 32});
}
SHA256D64(out2, in, i);
BOOST_CHECK(memcmp(out1, out2, 32 * i) == 0);
diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp
index 595cdf9abb..3edcf96495 100644
--- a/src/test/fuzz/crypto.cpp
+++ b/src/test/fuzz/crypto.cpp
@@ -44,8 +44,8 @@ void test_one_input(const std::vector<uint8_t>& buffer)
}
}
- (void)hash160.Write(data.data(), data.size());
- (void)hash256.Write(data.data(), data.size());
+ (void)hash160.Write(data);
+ (void)hash256.Write(data);
(void)hmac_sha256.Write(data.data(), data.size());
(void)hmac_sha512.Write(data.data(), data.size());
(void)ripemd160.Write(data.data(), data.size());
@@ -54,9 +54,8 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(void)sha512.Write(data.data(), data.size());
(void)sip_hasher.Write(data.data(), data.size());
- (void)Hash(data.begin(), data.end());
+ (void)Hash(data);
(void)Hash160(data);
- (void)Hash160(data.begin(), data.end());
(void)sha512.Size();
break;
}
@@ -73,12 +72,12 @@ void test_one_input(const std::vector<uint8_t>& buffer)
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 8)) {
case 0: {
data.resize(CHash160::OUTPUT_SIZE);
- hash160.Finalize(data.data());
+ hash160.Finalize(data);
break;
}
case 1: {
data.resize(CHash256::OUTPUT_SIZE);
- hash256.Finalize(data.data());
+ hash256.Finalize(data);
break;
}
case 2: {
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index c746374c61..955b954700 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -85,7 +85,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
assert(negated_key == key);
}
- const uint256 random_uint256 = Hash(buffer.begin(), buffer.end());
+ const uint256 random_uint256 = Hash(buffer);
{
CKey child_key;
diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp
index ae531f4462..8a674ac1e9 100644
--- a/src/test/fuzz/net_permissions.cpp
+++ b/src/test/fuzz/net_permissions.cpp
@@ -24,6 +24,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
NetPermissionFlags::PF_FORCERELAY,
NetPermissionFlags::PF_NOBAN,
NetPermissionFlags::PF_MEMPOOL,
+ NetPermissionFlags::PF_ADDR,
NetPermissionFlags::PF_ISIMPLICIT,
NetPermissionFlags::PF_ALL,
}) :
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index fd35537c77..4e4c44266a 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(key_test1)
for (int n=0; n<16; n++)
{
std::string strMsg = strprintf("Very secret message %i: 11", n);
- uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());
+ uint256 hashMsg = Hash(strMsg);
// normal signatures
@@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(key_test1)
std::vector<unsigned char> detsig, detsigc;
std::string strMsg = "Very deterministic message";
- uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());
+ uint256 hashMsg = Hash(strMsg);
BOOST_CHECK(key1.Sign(hashMsg, detsig));
BOOST_CHECK(key1C.Sign(hashMsg, detsigc));
BOOST_CHECK(detsig == detsigc);
@@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(key_signature_tests)
// When entropy is specified, we should see at least one high R signature within 20 signatures
CKey key = DecodeSecret(strSecret1);
std::string msg = "A message to be signed";
- uint256 msg_hash = Hash(msg.begin(), msg.end());
+ uint256 msg_hash = Hash(msg);
std::vector<unsigned char> sig;
bool found = false;
@@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(key_signature_tests)
for (int i = 0; i < 256; ++i) {
sig.clear();
std::string msg = "A message to be signed" + ToString(i);
- msg_hash = Hash(msg.begin(), msg.end());
+ msg_hash = Hash(msg);
BOOST_CHECK(key.Sign(msg_hash, sig));
found = sig[3] == 0x20;
BOOST_CHECK(sig.size() <= 70);
@@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(key_key_negation)
std::string str = "Bitcoin key verification\n";
GetRandBytes(rnd, sizeof(rnd));
uint256 hash;
- CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin());
+ CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
// import the static test key
CKey key = DecodeSecret(strSecret1C);
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index 03dce552fc..9bc7cc5dab 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -13,9 +13,9 @@ static uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vecto
uint256 hash = leaf;
for (std::vector<uint256>::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) {
if (nIndex & 1) {
- hash = Hash(it->begin(), it->end(), hash.begin(), hash.end());
+ hash = Hash(*it, hash);
} else {
- hash = Hash(hash.begin(), hash.end(), it->begin(), it->end());
+ hash = Hash(hash, *it);
}
nIndex >>= 1;
}
@@ -60,7 +60,7 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
}
}
mutated |= (inner[level] == h);
- CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin());
+ CHash256().Write(inner[level]).Write(h).Finalize(h);
}
// Store the resulting hash at inner position level.
inner[level] = h;
@@ -86,7 +86,7 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
if (pbranch && matchh) {
pbranch->push_back(h);
}
- CHash256().Write(h.begin(), 32).Write(h.begin(), 32).Finalize(h.begin());
+ CHash256().Write(h).Write(h).Finalize(h);
// Increment count to the value it would have if two entries at this
// level had existed.
count += (((uint32_t)1) << level);
@@ -101,7 +101,7 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
matchh = true;
}
}
- CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin());
+ CHash256().Write(inner[level]).Write(h).Finalize(h);
level++;
}
}
@@ -144,8 +144,7 @@ static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::ve
// Two identical hashes at the end of the list at a particular level.
mutated = true;
}
- vMerkleTree.push_back(Hash(vMerkleTree[j+i].begin(), vMerkleTree[j+i].end(),
- vMerkleTree[j+i2].begin(), vMerkleTree[j+i2].end()));
+ vMerkleTree.push_back(Hash(vMerkleTree[j+i], vMerkleTree[j+i2]));
}
j += nSize;
}
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 591b4ce49a..49073ea657 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -406,13 +406,14 @@ BOOST_AUTO_TEST_CASE(netpermissions_test)
BOOST_CHECK(NetWhitelistPermissions::TryParse("bloom,forcerelay,noban,relay,mempool@1.2.3.4/32", whitelistPermissions, error));
const auto strings = NetPermissions::ToStrings(PF_ALL);
- BOOST_CHECK_EQUAL(strings.size(), 6U);
+ BOOST_CHECK_EQUAL(strings.size(), 7U);
BOOST_CHECK(std::find(strings.begin(), strings.end(), "bloomfilter") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "forcerelay") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "relay") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "noban") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "mempool") != strings.end());
BOOST_CHECK(std::find(strings.begin(), strings.end(), "download") != strings.end());
+ BOOST_CHECK(std::find(strings.begin(), strings.end(), "addr") != strings.end());
}
BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 77d748241b..87678af4d1 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
s << OP_0 << ToByteVector(pubkey.GetID());
BOOST_CHECK(ExtractDestination(s, address));
WitnessV0KeyHash keyhash;
- CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(keyhash.begin());
+ CHash160().Write(pubkey).Finalize(keyhash);
BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash);
// TxoutType::WITNESS_V0_SCRIPTHASH
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index cb3ae290d1..0830743d61 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -282,7 +282,7 @@ public:
CScript scriptPubKey = script;
if (wm == WitnessMode::PKH) {
uint160 hash;
- CHash160().Write(&script[1], script.size() - 1).Finalize(hash.begin());
+ CHash160().Write(MakeSpan(script).subspan(1)).Finalize(hash);
script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(hash) << OP_EQUALVERIFY << OP_CHECKSIG;
scriptPubKey = CScript() << witnessversion << ToByteVector(hash);
} else if (wm == WitnessMode::SH) {
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index c2328f931c..f625b67c2a 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(floats)
for (int i = 0; i < 1000; i++) {
ss << float(i);
}
- BOOST_CHECK(Hash(ss.begin(), ss.end()) == uint256S("8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c"));
+ BOOST_CHECK(Hash(ss) == uint256S("8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c"));
// decode
for (int i = 0; i < 1000; i++) {
@@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(doubles)
for (int i = 0; i < 1000; i++) {
ss << double(i);
}
- BOOST_CHECK(Hash(ss.begin(), ss.end()) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96"));
+ BOOST_CHECK(Hash(ss) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96"));
// decode
for (int i = 0; i < 1000; i++) {
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index 1a2d775f49..91e039416c 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -228,7 +228,7 @@ BOOST_FIXTURE_TEST_CASE(Merge, MergeTestingSetup)
if (OnlyHasDefaultSectionSetting(settings, network, name)) desc += " ignored";
desc += "\n";
- out_sha.Write((const unsigned char*)desc.data(), desc.size());
+ out_sha.Write(MakeUCharSpan(desc));
if (out_file) {
BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
}
diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp
index 3ea8714f3a..19029ebd3c 100644
--- a/src/test/sync_tests.cpp
+++ b/src/test/sync_tests.cpp
@@ -14,6 +14,7 @@ void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2)
{
LOCK2(mutex1, mutex2);
}
+ BOOST_CHECK(LockStackEmpty());
bool error_thrown = false;
try {
LOCK2(mutex2, mutex1);
@@ -21,6 +22,7 @@ void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2)
BOOST_CHECK_EQUAL(e.what(), "potential deadlock detected: mutex1 -> mutex2 -> mutex1");
error_thrown = true;
}
+ BOOST_CHECK(LockStackEmpty());
#ifdef DEBUG_LOCKORDER
BOOST_CHECK(error_thrown);
#else
@@ -40,9 +42,13 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected)
RecursiveMutex rmutex1, rmutex2;
TestPotentialDeadLockDetected(rmutex1, rmutex2);
+ // The second test ensures that lock tracking data have not been broken by exception.
+ TestPotentialDeadLockDetected(rmutex1, rmutex2);
Mutex mutex1, mutex2;
TestPotentialDeadLockDetected(mutex1, mutex2);
+ // The second test ensures that lock tracking data have not been broken by exception.
+ TestPotentialDeadLockDetected(mutex1, mutex2);
#ifdef DEBUG_LOCKORDER
g_debug_lockorder_abort = prev;
diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp
new file mode 100644
index 0000000000..a55145c738
--- /dev/null
+++ b/src/test/system_tests.cpp
@@ -0,0 +1,95 @@
+// Copyright (c) 2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+//
+#include <test/util/setup_common.h>
+#include <util/system.h>
+#include <univalue.h>
+
+#ifdef HAVE_BOOST_PROCESS
+#include <boost/process.hpp>
+#endif // HAVE_BOOST_PROCESS
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup)
+
+// At least one test is required (in case HAVE_BOOST_PROCESS is not defined).
+// Workaround for https://github.com/bitcoin/bitcoin/issues/19128
+BOOST_AUTO_TEST_CASE(dummy)
+{
+ BOOST_CHECK(true);
+}
+
+#ifdef HAVE_BOOST_PROCESS
+
+bool checkMessage(const std::runtime_error& ex)
+{
+ // On Linux & Mac: "No such file or directory"
+ // On Windows: "The system cannot find the file specified."
+ const std::string what(ex.what());
+ BOOST_CHECK(what.find("file") != std::string::npos);
+ return true;
+}
+
+bool checkMessageFalse(const std::runtime_error& ex)
+{
+ BOOST_CHECK_EQUAL(ex.what(), std::string("RunCommandParseJSON error: process(false) returned 1: \n"));
+ return true;
+}
+
+bool checkMessageStdErr(const std::runtime_error& ex)
+{
+ const std::string what(ex.what());
+ BOOST_CHECK(what.find("RunCommandParseJSON error:") != std::string::npos);
+ return checkMessage(ex);
+}
+
+BOOST_AUTO_TEST_CASE(run_command)
+{
+ {
+ const UniValue result = RunCommandParseJSON("");
+ BOOST_CHECK(result.isNull());
+ }
+ {
+#ifdef WIN32
+ // Windows requires single quotes to prevent escaping double quotes from the JSON...
+ const UniValue result = RunCommandParseJSON("echo '{\"success\": true}'");
+#else
+ // ... but Linux and macOS echo a single quote if it's used
+ const UniValue result = RunCommandParseJSON("echo \"{\"success\": true}\"");
+#endif
+ BOOST_CHECK(result.isObject());
+ const UniValue& success = find_value(result, "success");
+ BOOST_CHECK(!success.isNull());
+ BOOST_CHECK_EQUAL(success.getBool(), true);
+ }
+ {
+ // An invalid command is handled by Boost
+ BOOST_CHECK_EXCEPTION(RunCommandParseJSON("invalid_command"), boost::process::process_error, checkMessage); // Command failed
+ }
+ {
+ // Return non-zero exit code, no output to stderr
+ BOOST_CHECK_EXCEPTION(RunCommandParseJSON("false"), std::runtime_error, checkMessageFalse);
+ }
+ {
+ // Return non-zero exit code, with error message for stderr
+ BOOST_CHECK_EXCEPTION(RunCommandParseJSON("ls nosuchfile"), std::runtime_error, checkMessageStdErr);
+ }
+ {
+ BOOST_REQUIRE_THROW(RunCommandParseJSON("echo \"{\""), std::runtime_error); // Unable to parse JSON
+ }
+ // Test std::in, except for Windows
+#ifndef WIN32
+ {
+ const UniValue result = RunCommandParseJSON("cat", "{\"success\": true}");
+ BOOST_CHECK(result.isObject());
+ const UniValue& success = find_value(result, "success");
+ BOOST_CHECK(!success.isNull());
+ BOOST_CHECK_EQUAL(success.getBool(), true);
+ }
+#endif
+}
+#endif // HAVE_BOOST_PROCESS
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 14f65dcb7c..b2ae1cb845 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -11,6 +11,7 @@
#include <consensus/validation.h>
#include <crypto/sha256.h>
#include <init.h>
+#include <interfaces/chain.h>
#include <miner.h>
#include <net.h>
#include <net_processing.h>
@@ -32,6 +33,7 @@
#include <util/vector.h>
#include <validation.h>
#include <validationinterface.h>
+#include <walletinitinterface.h>
#include <functional>
@@ -104,6 +106,8 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
SetupNetworking();
InitSignatureCache();
InitScriptExecutionCache();
+ m_node.chain = interfaces::MakeChain(m_node);
+ g_wallet_init_interface.Construct(m_node);
fCheckBlockIndex = true;
static bool noui_connected = false;
if (!noui_connected) {
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index a30e366028..15a2c1e300 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1009,7 +1009,7 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
desc += "\n";
- out_sha.Write((const unsigned char*)desc.data(), desc.size());
+ out_sha.Write(MakeUCharSpan(desc));
if (out_file) {
BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
}
@@ -1112,7 +1112,7 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
}
desc += "\n";
- out_sha.Write((const unsigned char*)desc.data(), desc.size());
+ out_sha.Write(MakeUCharSpan(desc));
if (out_file) {
BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
}
@@ -2186,8 +2186,8 @@ BOOST_AUTO_TEST_CASE(message_hash)
std::string(1, (char)unsigned_tx.length()) +
unsigned_tx;
- const uint256 signature_hash = Hash(unsigned_tx.begin(), unsigned_tx.end());
- const uint256 message_hash1 = Hash(prefixed_message.begin(), prefixed_message.end());
+ const uint256 signature_hash = Hash(unsigned_tx);
+ const uint256 message_hash1 = Hash(prefixed_message);
const uint256 message_hash2 = MessageHash(unsigned_tx);
BOOST_CHECK_EQUAL(message_hash1, message_hash2);
diff --git a/src/uint256.cpp b/src/uint256.cpp
index a943e71062..a5dfba41e2 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -12,20 +12,20 @@
template <unsigned int BITS>
base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)
{
- assert(vch.size() == sizeof(data));
- memcpy(data, vch.data(), sizeof(data));
+ assert(vch.size() == sizeof(m_data));
+ memcpy(m_data, vch.data(), sizeof(m_data));
}
template <unsigned int BITS>
std::string base_blob<BITS>::GetHex() const
{
- return HexStr(std::reverse_iterator<const uint8_t*>(data + sizeof(data)), std::reverse_iterator<const uint8_t*>(data));
+ return HexStr(std::reverse_iterator<const uint8_t*>(m_data + sizeof(m_data)), std::reverse_iterator<const uint8_t*>(m_data));
}
template <unsigned int BITS>
void base_blob<BITS>::SetHex(const char* psz)
{
- memset(data, 0, sizeof(data));
+ memset(m_data, 0, sizeof(m_data));
// skip leading spaces
while (IsSpace(*psz))
@@ -39,7 +39,7 @@ void base_blob<BITS>::SetHex(const char* psz)
size_t digits = 0;
while (::HexDigit(psz[digits]) != -1)
digits++;
- unsigned char* p1 = (unsigned char*)data;
+ unsigned char* p1 = (unsigned char*)m_data;
unsigned char* pend = p1 + WIDTH;
while (digits > 0 && p1 < pend) {
*p1 = ::HexDigit(psz[--digits]);
diff --git a/src/uint256.h b/src/uint256.h
index b36598f572..8ab747ef49 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -18,11 +18,11 @@ class base_blob
{
protected:
static constexpr int WIDTH = BITS / 8;
- uint8_t data[WIDTH];
+ uint8_t m_data[WIDTH];
public:
base_blob()
{
- memset(data, 0, sizeof(data));
+ memset(m_data, 0, sizeof(m_data));
}
explicit base_blob(const std::vector<unsigned char>& vch);
@@ -30,17 +30,17 @@ public:
bool IsNull() const
{
for (int i = 0; i < WIDTH; i++)
- if (data[i] != 0)
+ if (m_data[i] != 0)
return false;
return true;
}
void SetNull()
{
- memset(data, 0, sizeof(data));
+ memset(m_data, 0, sizeof(m_data));
}
- inline int Compare(const base_blob& other) const { return memcmp(data, other.data, sizeof(data)); }
+ inline int Compare(const base_blob& other) const { return memcmp(m_data, other.m_data, sizeof(m_data)); }
friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }
friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }
@@ -51,34 +51,37 @@ public:
void SetHex(const std::string& str);
std::string ToString() const;
+ const unsigned char* data() const { return m_data; }
+ unsigned char* data() { return m_data; }
+
unsigned char* begin()
{
- return &data[0];
+ return &m_data[0];
}
unsigned char* end()
{
- return &data[WIDTH];
+ return &m_data[WIDTH];
}
const unsigned char* begin() const
{
- return &data[0];
+ return &m_data[0];
}
const unsigned char* end() const
{
- return &data[WIDTH];
+ return &m_data[WIDTH];
}
unsigned int size() const
{
- return sizeof(data);
+ return sizeof(m_data);
}
uint64_t GetUint64(int pos) const
{
- const uint8_t* ptr = data + pos * 8;
+ const uint8_t* ptr = m_data + pos * 8;
return ((uint64_t)ptr[0]) | \
((uint64_t)ptr[1]) << 8 | \
((uint64_t)ptr[2]) << 16 | \
@@ -92,13 +95,13 @@ public:
template<typename Stream>
void Serialize(Stream& s) const
{
- s.write((char*)data, sizeof(data));
+ s.write((char*)m_data, sizeof(m_data));
}
template<typename Stream>
void Unserialize(Stream& s)
{
- s.read((char*)data, sizeof(data));
+ s.read((char*)m_data, sizeof(m_data));
}
};
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 8164e884b1..7b74789b32 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -6,6 +6,10 @@
#include <sync.h>
#include <util/system.h>
+#ifdef HAVE_BOOST_PROCESS
+#include <boost/process.hpp>
+#endif // HAVE_BOOST_PROCESS
+
#include <chainparamsbase.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -1021,7 +1025,7 @@ bool FileCommit(FILE *file)
return false;
}
#else
- #if defined(__linux__) || defined(__NetBSD__)
+ #if defined(HAVE_FDATASYNC)
if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
return false;
@@ -1161,6 +1165,43 @@ void runCommand(const std::string& strCommand)
}
#endif
+#ifdef HAVE_BOOST_PROCESS
+UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in)
+{
+ namespace bp = boost::process;
+
+ UniValue result_json;
+ bp::opstream stdin_stream;
+ bp::ipstream stdout_stream;
+ bp::ipstream stderr_stream;
+
+ if (str_command.empty()) return UniValue::VNULL;
+
+ bp::child c(
+ str_command,
+ bp::std_out > stdout_stream,
+ bp::std_err > stderr_stream,
+ bp::std_in < stdin_stream
+ );
+ if (!str_std_in.empty()) {
+ stdin_stream << str_std_in << std::endl;
+ }
+ stdin_stream.pipe().close();
+
+ std::string result;
+ std::string error;
+ std::getline(stdout_stream, result);
+ std::getline(stderr_stream, error);
+
+ c.wait();
+ const int n_error = c.exit_code();
+ if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error));
+ if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result);
+
+ return result_json;
+}
+#endif // HAVE_BOOST_PROCESS
+
void SetupEnvironment()
{
#ifdef HAVE_MALLOPT_ARENA_MAX
diff --git a/src/util/system.h b/src/util/system.h
index 0bd14cc9ea..1df194ca84 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -37,6 +37,8 @@
#include <boost/thread/condition_variable.hpp> // for boost::thread_interrupted
+class UniValue;
+
// Application startup time (used for uptime calculation)
int64_t GetStartupTime();
@@ -96,6 +98,16 @@ std::string ShellEscape(const std::string& arg);
#if HAVE_SYSTEM
void runCommand(const std::string& strCommand);
#endif
+#ifdef HAVE_BOOST_PROCESS
+/**
+ * Execute a command which returns JSON, and parse the result.
+ *
+ * @param str_command The command to execute, including any arguments
+ * @param str_std_in string to pass to stdin
+ * @return parsed JSON
+ */
+UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in="");
+#endif // HAVE_BOOST_PROCESS
/**
* Most paths passed as configuration arguments are treated as relative to
diff --git a/src/validation.cpp b/src/validation.cpp
index 3cebf1090e..84c106f064 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -688,8 +688,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
// Check for non-standard pay-to-script-hash in inputs
- if (fRequireStandard && !AreInputsStandard(tx, m_view))
- return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-nonstandard-inputs");
+ if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
+ return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
+ }
// Check for non-standard witness in P2WSH
if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, m_view))
@@ -3434,7 +3435,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
if (consensusParams.SegwitHeight != std::numeric_limits<int>::max()) {
if (commitpos == -1) {
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
- CHash256().Write(witnessroot.begin(), 32).Write(ret.data(), 32).Finalize(witnessroot.begin());
+ CHash256().Write(witnessroot).Write(ret).Finalize(witnessroot);
CTxOut out;
out.nValue = 0;
out.scriptPubKey.resize(MINIMUM_WITNESS_COMMITMENT);
@@ -3579,7 +3580,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
if (block.vtx[0]->vin[0].scriptWitness.stack.size() != 1 || block.vtx[0]->vin[0].scriptWitness.stack[0].size() != 32) {
return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "bad-witness-nonce-size", strprintf("%s : invalid witness reserved value size", __func__));
}
- CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->vin[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
+ CHash256().Write(hashWitness).Write(block.vtx[0]->vin[0].scriptWitness.stack[0]).Finalize(hashWitness);
if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) {
return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "bad-witness-merkle-match", strprintf("%s : witness merkle commitment mismatch", __func__));
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 9d334063c4..39d1f49e9e 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2338,7 +2338,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
{RPCResult::Type::NUM_TIME, "keypoololdest", "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only."},
{RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
{RPCResult::Type::NUM, "keypoolsize_hd_internal", "how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"},
- {RPCResult::Type::NUM_TIME, "unlocked_until", "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked"},
+ {RPCResult::Type::NUM_TIME, "unlocked_until", /* optional */ true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},
{RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB"},
{RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true, "the Hash160 of the HD seed (only present when HD is enabled)"},
{RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index d2770a46f7..7ef06663b5 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -630,13 +630,13 @@ static size_t CalculateNestedKeyhashInputSize(bool use_max_sig)
CPubKey pubkey = key.GetPubKey();
// Generate pubkey hash
- uint160 key_hash(Hash160(pubkey.begin(), pubkey.end()));
+ uint160 key_hash(Hash160(pubkey));
// Create inner-script to enter into keystore. Key hash can't be 0...
CScript inner_script = CScript() << OP_0 << std::vector<unsigned char>(key_hash.begin(), key_hash.end());
// Create outer P2SH script for the output
- uint160 script_id(Hash160(inner_script.begin(), inner_script.end()));
+ uint160 script_id(Hash160(inner_script));
CScript script_pubkey = CScript() << OP_HASH160 << std::vector<unsigned char>(script_id.begin(), script_id.end()) << OP_EQUAL;
// Add inner-script to key store and key to watchonly
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index a6d327994b..fa6814d0d3 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -103,7 +103,7 @@ bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey,
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
- return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
+ return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey)), false);
}
bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
@@ -115,7 +115,7 @@ bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
}
// Compute a checksum of the encrypted key
- uint256 checksum = Hash(vchCryptedSecret.begin(), vchCryptedSecret.end());
+ uint256 checksum = Hash(vchCryptedSecret);
const auto key = std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey);
if (!WriteIC(key, std::make_pair(vchCryptedSecret, checksum), false)) {
@@ -209,7 +209,7 @@ bool WalletBatch::WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubk
key.insert(key.end(), pubkey.begin(), pubkey.end());
key.insert(key.end(), privkey.begin(), privkey.end());
- return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(privkey, Hash(key.begin(), key.end())), false);
+ return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(privkey, Hash(key)), false);
}
bool WalletBatch::WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret)
@@ -365,7 +365,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
- if (Hash(vchKey.begin(), vchKey.end()) != hash)
+ if (Hash(vchKey) != hash)
{
strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
return false;
@@ -414,7 +414,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
if (!ssValue.eof()) {
uint256 checksum;
ssValue >> checksum;
- if ((checksum_valid = Hash(vchPrivKey.begin(), vchPrivKey.end()) != checksum)) {
+ if ((checksum_valid = Hash(vchPrivKey) != checksum)) {
strErr = "Error reading wallet database: Crypted key corrupt";
return false;
}
@@ -621,7 +621,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end());
to_hash.insert(to_hash.end(), pkey.begin(), pkey.end());
- if (Hash(to_hash.begin(), to_hash.end()) != hash)
+ if (Hash(to_hash) != hash)
{
strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
return false;
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index 741da3be31..c8e2616b79 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -218,7 +218,11 @@ class FilterTest(BitcoinTestFramework):
# Add peer but do not send version yet
filter_peer_without_nrelay = self.nodes[0].add_p2p_connection(P2PBloomFilter(), send_version=False, wait_for_verack=False)
# Send version with fRelay=False
- filter_peer_without_nrelay.wait_until(lambda: filter_peer_without_nrelay.is_connected, timeout=10)
+ filter_peer_without_nrelay.wait_until(
+ lambda: filter_peer_without_nrelay.is_connected,
+ timeout=10,
+ check_connected=False,
+ )
version_without_fRelay = msg_version()
version_without_fRelay.nRelay = 0
filter_peer_without_nrelay.send_message(version_without_fRelay)
diff --git a/test/functional/p2p_getaddr_caching.py b/test/functional/p2p_getaddr_caching.py
new file mode 100755
index 0000000000..c9278eab92
--- /dev/null
+++ b/test/functional/p2p_getaddr_caching.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test addr response caching"""
+
+import time
+from test_framework.messages import (
+ CAddress,
+ NODE_NETWORK,
+ NODE_WITNESS,
+ msg_addr,
+ msg_getaddr,
+)
+from test_framework.mininode import (
+ P2PInterface,
+ mininode_lock
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+)
+
+MAX_ADDR_TO_SEND = 1000
+
+def gen_addrs(n):
+ addrs = []
+ for i in range(n):
+ addr = CAddress()
+ addr.time = int(time.time())
+ addr.nServices = NODE_NETWORK | NODE_WITNESS
+ # Use first octets to occupy different AddrMan buckets
+ first_octet = i >> 8
+ second_octet = i % 256
+ addr.ip = "{}.{}.1.1".format(first_octet, second_octet)
+ addr.port = 8333
+ addrs.append(addr)
+ return addrs
+
+class AddrReceiver(P2PInterface):
+
+ def __init__(self):
+ super().__init__()
+ self.received_addrs = None
+
+ def get_received_addrs(self):
+ with mininode_lock:
+ return self.received_addrs
+
+ def on_addr(self, message):
+ self.received_addrs = []
+ for addr in message.addrs:
+ self.received_addrs.append(addr.ip)
+
+ def addr_received(self):
+ return self.received_addrs is not None
+
+
+class AddrTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+
+ def run_test(self):
+ self.log.info('Create connection that sends and requests addr messages')
+ addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
+
+ msg_send_addrs = msg_addr()
+ self.log.info('Fill peer AddrMan with a lot of records')
+ # Since these addrs are sent from the same source, not all of them will be stored,
+ # because we allocate a limited number of AddrMan buckets per addr source.
+ total_addrs = 10000
+ addrs = gen_addrs(total_addrs)
+ for i in range(int(total_addrs/MAX_ADDR_TO_SEND)):
+ msg_send_addrs.addrs = addrs[i * MAX_ADDR_TO_SEND:(i + 1) * MAX_ADDR_TO_SEND]
+ addr_source.send_and_ping(msg_send_addrs)
+
+ responses = []
+ self.log.info('Send many addr requests within short time to receive same response')
+ N = 5
+ cur_mock_time = int(time.time())
+ for i in range(N):
+ addr_receiver = self.nodes[0].add_p2p_connection(AddrReceiver())
+ addr_receiver.send_and_ping(msg_getaddr())
+ # Trigger response
+ cur_mock_time += 5 * 60
+ self.nodes[0].setmocktime(cur_mock_time)
+ addr_receiver.wait_until(addr_receiver.addr_received)
+ responses.append(addr_receiver.get_received_addrs())
+ for response in responses[1:]:
+ assert_equal(response, responses[0])
+ assert(len(response) < MAX_ADDR_TO_SEND)
+
+ cur_mock_time += 3 * 24 * 60 * 60
+ self.nodes[0].setmocktime(cur_mock_time)
+
+ self.log.info('After time passed, see a new response to addr request')
+ last_addr_receiver = self.nodes[0].add_p2p_connection(AddrReceiver())
+ last_addr_receiver.send_and_ping(msg_getaddr())
+ # Trigger response
+ cur_mock_time += 5 * 60
+ self.nodes[0].setmocktime(cur_mock_time)
+ last_addr_receiver.wait_until(last_addr_receiver.addr_received)
+ # new response is different
+ assert(set(responses[0]) != set(last_addr_receiver.get_received_addrs()))
+
+
+if __name__ == '__main__':
+ AddrTest().main()
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index 32a795e345..254352c816 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -96,7 +96,7 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.checkpermission(
# all permission added
["-whitelist=all@127.0.0.1"],
- ["forcerelay", "noban", "mempool", "bloomfilter", "relay", "download"],
+ ["forcerelay", "noban", "mempool", "bloomfilter", "relay", "download", "addr"],
False)
self.stop_node(1)
diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py
index e00af88cc4..5f5fd3e104 100755
--- a/test/functional/p2p_ping.py
+++ b/test/functional/p2p_ping.py
@@ -7,13 +7,8 @@
import time
-from test_framework.messages import (
- msg_pong,
-)
-from test_framework.mininode import (
- P2PInterface,
- wait_until,
-)
+from test_framework.messages import msg_pong
+from test_framework.mininode import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -78,7 +73,7 @@ class PingPongTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(['pong peer=0: Nonce mismatch']):
# mock time PING_INTERVAL ahead to trigger node into sending a ping
self.mock_forward(PING_INTERVAL + 1)
- wait_until(lambda: 'ping' in no_pong_node.last_message)
+ no_pong_node.wait_until(lambda: 'ping' in no_pong_node.last_message)
self.mock_forward(9)
# Send the wrong pong
no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce - 1))
@@ -93,27 +88,27 @@ class PingPongTest(BitcoinTestFramework):
assert 'ping' not in no_pong_node.last_message
# mock time PING_INTERVAL ahead to trigger node into sending a ping
self.mock_forward(PING_INTERVAL + 1)
- wait_until(lambda: 'ping' in no_pong_node.last_message)
+ no_pong_node.wait_until(lambda: 'ping' in no_pong_node.last_message)
ping_delay = 29
self.mock_forward(ping_delay)
- wait_until(lambda: 'ping' in no_pong_node.last_message)
+ no_pong_node.wait_until(lambda: 'ping' in no_pong_node.last_message)
no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce))
self.check_peer_info(pingtime=ping_delay, minping=ping_delay, pingwait=None)
self.log.info('Check that minping is decreased after a fast roundtrip')
# mock time PING_INTERVAL ahead to trigger node into sending a ping
self.mock_forward(PING_INTERVAL + 1)
- wait_until(lambda: 'ping' in no_pong_node.last_message)
+ no_pong_node.wait_until(lambda: 'ping' in no_pong_node.last_message)
ping_delay = 9
self.mock_forward(ping_delay)
- wait_until(lambda: 'ping' in no_pong_node.last_message)
+ no_pong_node.wait_until(lambda: 'ping' in no_pong_node.last_message)
no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce))
self.check_peer_info(pingtime=ping_delay, minping=ping_delay, pingwait=None)
self.log.info('Check that peer is disconnected after ping timeout')
assert 'ping' not in no_pong_node.last_message
self.nodes[0].ping()
- wait_until(lambda: 'ping' in no_pong_node.last_message)
+ no_pong_node.wait_until(lambda: 'ping' in no_pong_node.last_message)
with self.nodes[0].assert_debug_log(['ping timeout: 1201.000000s']):
self.mock_forward(20 * 60 + 1)
time.sleep(4) # peertimeout + 1
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 728212ca23..2233fa5998 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -1418,7 +1418,7 @@ class SegWitTest(BitcoinTestFramework):
temp_utxo.pop() # last entry in temp_utxo was the output we just spent
temp_utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
- # Spend everything in temp_utxo back to an OP_TRUE output.
+ # Spend everything in temp_utxo into an segwit v1 output.
tx3 = CTransaction()
total_value = 0
for i in temp_utxo:
@@ -1426,8 +1426,16 @@ class SegWitTest(BitcoinTestFramework):
tx3.wit.vtxinwit.append(CTxInWitness())
total_value += i.nValue
tx3.wit.vtxinwit[-1].scriptWitness.stack = [witness_program]
- tx3.vout.append(CTxOut(total_value - 1000, CScript([OP_TRUE])))
+ tx3.vout.append(CTxOut(total_value - 1000, script_pubkey))
tx3.rehash()
+
+ # First we test this transaction against fRequireStandard=true node
+ # making sure the txid is added to the reject filter
+ self.std_node.announce_tx_and_wait_for_getdata(tx3)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx3, with_witness=True, accepted=False, reason="bad-txns-nonstandard-inputs")
+ # Now the node will no longer ask for getdata of this transaction when advertised by same txid
+ self.std_node.announce_tx_and_wait_for_getdata(tx3, timeout=5, success=False)
+
# Spending a higher version witness output is not allowed by policy,
# even with fRequireStandard=false.
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False, reason="reserved for soft-fork upgrades")
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index 07811667a8..53d6e474d9 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -388,18 +388,22 @@ class P2PInterface(P2PConnection):
# Connection helper methods
- def wait_until(self, test_function, timeout=60):
+ def wait_until(self, test_function_in, *, timeout=60, check_connected=True):
+ def test_function():
+ if check_connected:
+ assert self.is_connected
+ return test_function_in()
+
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
- self.wait_until(test_function, timeout=timeout)
+ self.wait_until(test_function, timeout=timeout, check_connected=False)
# Message receiving helper methods
def wait_for_tx(self, txid, timeout=60):
def test_function():
- assert self.is_connected
if not self.last_message.get('tx'):
return False
return self.last_message['tx'].tx.rehash() == txid
@@ -408,14 +412,12 @@ class P2PInterface(P2PConnection):
def wait_for_block(self, blockhash, timeout=60):
def test_function():
- assert self.is_connected
return self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
self.wait_until(test_function, timeout=timeout)
def wait_for_header(self, blockhash, timeout=60):
def test_function():
- assert self.is_connected
last_headers = self.last_message.get('headers')
if not last_headers:
return False
@@ -425,7 +427,6 @@ class P2PInterface(P2PConnection):
def wait_for_merkleblock(self, blockhash, timeout=60):
def test_function():
- assert self.is_connected
last_filtered_block = self.last_message.get('merkleblock')
if not last_filtered_block:
return False
@@ -437,9 +438,7 @@ class P2PInterface(P2PConnection):
"""Waits for a getdata message.
The object hashes in the inventory vector must match the provided hash_list."""
-
def test_function():
- assert self.is_connected
last_data = self.last_message.get("getdata")
if not last_data:
return False
@@ -454,9 +453,7 @@ class P2PInterface(P2PConnection):
value must be explicitly cleared before calling this method, or this will return
immediately with success. TODO: change this method to take a hash value and only
return true if the correct block header has been requested."""
-
def test_function():
- assert self.is_connected
return self.last_message.get("getheaders")
self.wait_until(test_function, timeout=timeout)
@@ -467,7 +464,6 @@ class P2PInterface(P2PConnection):
raise NotImplementedError("wait_for_inv() will only verify the first inv object")
def test_function():
- assert self.is_connected
return self.last_message.get("inv") and \
self.last_message["inv"].inv[0].type == expected_inv[0].type and \
self.last_message["inv"].inv[0].hash == expected_inv[0].hash
@@ -478,7 +474,7 @@ class P2PInterface(P2PConnection):
def test_function():
return "verack" in self.last_message
- self.wait_until(test_function, timeout=timeout)
+ self.wait_until(test_function, timeout=timeout, check_connected=False)
# Message sending helper functions
@@ -491,7 +487,6 @@ class P2PInterface(P2PConnection):
self.send_message(msg_ping(nonce=self.ping_counter))
def test_function():
- assert self.is_connected
return self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter
self.wait_until(test_function, timeout=timeout)
@@ -609,7 +604,11 @@ class P2PDataStore(P2PInterface):
self.send_message(msg_block(block=b))
else:
self.send_message(msg_headers([CBlockHeader(block) for block in blocks]))
- self.wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout)
+ self.wait_until(
+ lambda: blocks[-1].sha256 in self.getdata_requests,
+ timeout=timeout,
+ check_connected=success,
+ )
if expect_disconnect:
self.wait_for_disconnect(timeout=timeout)
@@ -677,6 +676,6 @@ class P2PTxInvStore(P2PInterface):
The mempool should mark unbroadcast=False for these transactions.
"""
# Wait until invs have been received (and getdatas sent) for each txid.
- self.wait_until(lambda: set(self.tx_invs_received.keys()) == set([int(tx, 16) for tx in txns]), timeout)
+ self.wait_until(lambda: set(self.tx_invs_received.keys()) == set([int(tx, 16) for tx in txns]), timeout=timeout)
# Flush messages and wait for the getdatas to be processed
self.sync_with_ping()
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 66bb2c89b5..a5abe77870 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -637,7 +637,7 @@ class TestNodeCLI():
raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr)
try:
return json.loads(cli_stdout, parse_float=decimal.Decimal)
- except json.JSONDecodeError:
+ except (json.JSONDecodeError, decimal.InvalidOperation):
return cli_stdout.rstrip("\n")
class RPCOverloadWrapper():
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 95c2b7c5ec..b090e93394 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -159,6 +159,7 @@ BASE_SCRIPTS = [
'rpc_deprecated.py',
'wallet_disable.py',
'p2p_addr_relay.py',
+ 'p2p_getaddr_caching.py',
'p2p_getdata.py',
'rpc_net.py',
'wallet_keypool.py',
diff --git a/test/lint/lint-git-commit-check.sh b/test/lint/lint-git-commit-check.sh
index 7cffd267dd..8947f67bf6 100755
--- a/test/lint/lint-git-commit-check.sh
+++ b/test/lint/lint-git-commit-check.sh
@@ -14,21 +14,22 @@ while getopts "?" opt; do
case $opt in
?)
echo "Usage: $0 [N]"
- echo " TRAVIS_COMMIT_RANGE='<commit range>' $0"
+ echo " COMMIT_RANGE='<commit range>' $0"
echo " $0 -?"
echo "Checks unmerged commits, the previous N commits, or a commit range."
- echo "TRAVIS_COMMIT_RANGE='47ba2c3...ee50c9e' $0"
+ echo "COMMIT_RANGE='47ba2c3...ee50c9e' $0"
exit ${EXIT_CODE}
;;
esac
done
-if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then
- if [ -n "$1" ]; then
- TRAVIS_COMMIT_RANGE="HEAD~$1...HEAD"
- else
- TRAVIS_COMMIT_RANGE="origin/master..HEAD"
- fi
+if [ -z "${COMMIT_RANGE}" ]; then
+ if [ -n "$1" ]; then
+ COMMIT_RANGE="HEAD~$1...HEAD"
+ else
+ MERGE_BASE=$(git merge-base HEAD master)
+ COMMIT_RANGE="$MERGE_BASE..HEAD"
+ fi
fi
while IFS= read -r commit_hash || [[ -n "$commit_hash" ]]; do
@@ -41,6 +42,6 @@ while IFS= read -r commit_hash || [[ -n "$commit_hash" ]]; do
EXIT_CODE=1
fi
done < <(git log --format=%B -n 1 "$commit_hash")
-done < <(git log "${TRAVIS_COMMIT_RANGE}" --format=%H)
+done < <(git log "${COMMIT_RANGE}" --format=%H)
exit ${EXIT_CODE}
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index 611bd4a8c4..fde77aea2d 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -63,6 +63,7 @@ EXPECTED_BOOST_INCLUDES=(
boost/optional.hpp
boost/preprocessor/cat.hpp
boost/preprocessor/stringize.hpp
+ boost/process.hpp
boost/signals2/connection.hpp
boost/signals2/optional_last_value.hpp
boost/signals2/signal.hpp