aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml4
-rw-r--r--.editorconfig26
-rw-r--r--.fuzzbuzz.yml2
-rw-r--r--build-aux/m4/ax_boost_thread.m4187
-rw-r--r--build-aux/m4/ax_gcc_func_attribute.m4223
-rw-r--r--build_msvc/bitcoin_config.h3
-rw-r--r--build_msvc/vcpkg.json1
-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_fuzz_with_valgrind.sh2
-rw-r--r--ci/test/00_setup_env_native_valgrind.sh2
-rw-r--r--ci/test/00_setup_env_win64.sh3
-rwxr-xr-xci/test/wrap-wine.sh2
-rw-r--r--configure.ac42
-rwxr-xr-xcontrib/gitian-build.py2
-rw-r--r--depends/packages/boost.mk2
-rw-r--r--doc/bips.md4
-rw-r--r--doc/build-unix.md2
-rw-r--r--src/Makefile.am6
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/bench/block_assemble.cpp5
-rw-r--r--src/crypto/muhash.cpp42
-rw-r--r--src/crypto/muhash.h7
-rw-r--r--src/flatfile.cpp2
-rw-r--r--src/init.cpp3
-rw-r--r--src/net.cpp96
-rw-r--r--src/net.h2
-rw-r--r--src/net_processing.cpp19
-rw-r--r--src/netbase.cpp152
-rw-r--r--src/netbase.h27
-rw-r--r--src/node/coinstats.cpp63
-rw-r--r--src/node/coinstats.h1
-rw-r--r--src/node/transaction.cpp18
-rw-r--r--src/rpc/blockchain.cpp46
-rw-r--r--src/rpc/misc.cpp19
-rw-r--r--src/rpc/rawtransaction.cpp51
-rw-r--r--src/rpc/util.cpp17
-rw-r--r--src/rpc/util.h2
-rw-r--r--src/script/bitcoinconsensus.h12
-rw-r--r--src/script/sigcache.cpp12
-rw-r--r--src/script/sign.cpp9
-rw-r--r--src/script/standard.cpp31
-rw-r--r--src/test/cuckoocache_tests.cpp19
-rw-r--r--src/test/fs_tests.cpp18
-rw-r--r--src/test/fuzz/fuzz.cpp9
-rw-r--r--src/test/fuzz/fuzz.h28
-rw-r--r--src/test/fuzz/process_message.cpp79
-rw-r--r--src/test/fuzz/process_messages.cpp2
-rw-r--r--src/test/fuzz/script_assets_test_minimizer.cpp8
-rw-r--r--src/test/script_standard_tests.cpp16
-rw-r--r--src/test/sock_tests.cpp149
-rw-r--r--src/test/txvalidation_tests.cpp16
-rw-r--r--src/test/txvalidationcache_tests.cpp6
-rw-r--r--src/test/util_tests.cpp3
-rw-r--r--src/test/validation_block_tests.cpp10
-rw-r--r--src/torcontrol.cpp1
-rw-r--r--src/util/getuniquepath.cpp10
-rw-r--r--src/util/getuniquepath.h19
-rw-r--r--src/util/sock.cpp149
-rw-r--r--src/util/sock.h118
-rw-r--r--src/util/system.cpp3
-rw-r--r--src/util/time.cpp19
-rw-r--r--src/util/time.h13
-rw-r--r--src/validation.cpp99
-rw-r--r--src/validation.h49
-rw-r--r--src/wallet/rpcdump.cpp4
-rw-r--r--src/wallet/scriptpubkeyman.cpp5
-rw-r--r--src/wallet/test/db_tests.cpp8
-rw-r--r--src/wallet/test/init_tests.cpp8
-rwxr-xr-xtest/functional/feature_config_args.py58
-rwxr-xr-xtest/functional/feature_utxo_set_hash.py86
-rwxr-xr-xtest/functional/rpc_blockchain.py12
-rwxr-xr-xtest/functional/rpc_uptime.py5
-rw-r--r--test/functional/test_framework/bdb.py1
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/fuzz/test_runner.py2
-rwxr-xr-xtest/lint/lint-includes.sh2
77 files changed, 1254 insertions, 935 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 1eabca1b8b..691582239e 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -82,10 +82,10 @@ task:
FILE_ENV: "./ci/test/00_setup_env_arm.sh"
task:
- name: 'Win64 [unit tests, no gui tests, no boost::process, no functional tests] [bionic]'
+ name: 'Win64 [unit tests, no gui tests, no boost::process, no functional tests] [focal]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:bionic
+ image: ubuntu:focal
env:
FILE_ENV: "./ci/test/00_setup_env_win64.sh"
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..4967e675f6
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,26 @@
+# This is the top-most EditorConfig file.
+root = true
+
+# For all files.
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+# Source code files
+[*.{h,cpp,py,sh}]
+indent_size = 4
+
+# .cirrus.yml, .appveyor.yml, .fuzzbuzz.yml, etc.
+[*.yml]
+indent_size = 2
+
+# Makefiles
+[{*.am,Makefile.*.include}]
+indent_style = tab
+
+# Autoconf scripts
+[configure.ac]
+indent_size = 2
diff --git a/.fuzzbuzz.yml b/.fuzzbuzz.yml
index be9a1cd4e1..e40b4df165 100644
--- a/.fuzzbuzz.yml
+++ b/.fuzzbuzz.yml
@@ -5,7 +5,7 @@ environment:
- CXXFLAGS=-fcoverage-mapping -fno-omit-frame-pointer -fprofile-instr-generate -gline-tables-only -O1
setup:
- sudo apt-get update
- - sudo apt-get install -y autoconf bsdmainutils clang git libboost-all-dev libc++1 libc++abi1 libc++abi-dev libc++-dev libclang1 libclang-dev libdb5.3++ libevent-dev libllvm-ocaml-dev libomp5 libomp-dev libqt5core5a libqt5dbus5 libqt5gui5 libtool llvm llvm-dev llvm-runtime pkg-config qttools5-dev qttools5-dev-tools software-properties-common
+ - sudo apt-get install -y autoconf bsdmainutils clang git libboost-system-dev libboost-filesystem-dev libboost-test-dev libc++1 libc++abi1 libc++abi-dev libc++-dev libclang1 libclang-dev libdb5.3++ libevent-dev libllvm-ocaml-dev libomp5 libomp-dev libqt5core5a libqt5dbus5 libqt5gui5 libtool llvm llvm-dev llvm-runtime pkg-config qttools5-dev qttools5-dev-tools software-properties-common
- ./autogen.sh
- CC=clang CXX=clang++ ./configure --enable-fuzz --with-sanitizers=address,fuzzer,undefined --enable-danger-fuzz-link-all
- make
diff --git a/build-aux/m4/ax_boost_thread.m4 b/build-aux/m4/ax_boost_thread.m4
deleted file mode 100644
index 75e80e6e75..0000000000
--- a/build-aux/m4/ax_boost_thread.m4
+++ /dev/null
@@ -1,187 +0,0 @@
-# ===========================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_boost_thread.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_BOOST_THREAD
-#
-# DESCRIPTION
-#
-# Test for Thread 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_THREAD_LIB)
-#
-# And sets:
-#
-# HAVE_BOOST_THREAD
-#
-# LICENSE
-#
-# Copyright (c) 2009 Thomas Porschberg <thomas@randspringer.de>
-# Copyright (c) 2009 Michael Tindal
-#
-# 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 33
-
-AC_DEFUN([AX_BOOST_THREAD],
-[
- AC_ARG_WITH([boost-thread],
- AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@],
- [use the Thread library from boost -
- it is possible to specify a certain library for the linker
- e.g. --with-boost-thread=boost_thread-gcc-mt ]),
- [
- if test "$withval" = "yes"; then
- want_boost="yes"
- ax_boost_user_thread_lib=""
- else
- want_boost="yes"
- ax_boost_user_thread_lib="$withval"
- fi
- ],
- [want_boost="yes"]
- )
-
- if test "x$want_boost" = "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::Thread library is available,
- ax_cv_boost_thread,
- [AC_LANG_PUSH([C++])
- CXXFLAGS_SAVE=$CXXFLAGS
-
- case "x$host_os" in
- xsolaris )
- CXXFLAGS="-pthreads $CXXFLAGS"
- break;
- ;;
- xmingw32 )
- CXXFLAGS="-mthreads $CXXFLAGS"
- break;
- ;;
- *android* )
- break;
- ;;
- * )
- CXXFLAGS="-pthread $CXXFLAGS"
- break;
- ;;
- esac
-
- AC_COMPILE_IFELSE([
- AC_LANG_PROGRAM(
- [[@%:@include <boost/thread/thread.hpp>]],
- [[boost::thread_group thrds;
- return 0;]])],
- ax_cv_boost_thread=yes, ax_cv_boost_thread=no)
- CXXFLAGS=$CXXFLAGS_SAVE
- AC_LANG_POP([C++])
- ])
- if test "x$ax_cv_boost_thread" = "xyes"; then
- case "x$host_os" in
- xsolaris )
- BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS"
- break;
- ;;
- xmingw32 )
- BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS"
- break;
- ;;
- *android* )
- break;
- ;;
- * )
- BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS"
- break;
- ;;
- esac
-
- AC_SUBST(BOOST_CPPFLAGS)
-
- AC_DEFINE(HAVE_BOOST_THREAD,,
- [define if the Boost::Thread library is available])
- BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
-
- LDFLAGS_SAVE=$LDFLAGS
- case "x$host_os" in
- *bsd* )
- LDFLAGS="-pthread $LDFLAGS"
- break;
- ;;
- esac
- if test "x$ax_boost_user_thread_lib" = "x"; then
- for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do
- ax_lib=${libextension}
- AC_CHECK_LIB($ax_lib, exit,
- [link_thread="yes"; break],
- [link_thread="no"])
- done
- if test "x$link_thread" != "xyes"; then
- for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do
- ax_lib=${libextension}
- AC_CHECK_LIB($ax_lib, exit,
- [link_thread="yes"; break],
- [link_thread="no"])
- done
- fi
-
- else
- for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do
- AC_CHECK_LIB($ax_lib, exit,
- [link_thread="yes"; break],
- [link_thread="no"])
- done
-
- fi
- if test "x$ax_lib" = "x"; then
- AC_MSG_ERROR(Could not find a version of the Boost::Thread library!)
- fi
- if test "x$link_thread" = "xno"; then
- AC_MSG_ERROR(Could not link against $ax_lib !)
- else
- BOOST_THREAD_LIB="-l$ax_lib"
- case "x$host_os" in
- *bsd* )
- BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS"
- break;
- ;;
- xsolaris )
- BOOST_THREAD_LIB="$BOOST_THREAD_LIB -lpthread"
- break;
- ;;
- xmingw32 )
- break;
- ;;
- *android* )
- break;
- ;;
- * )
- BOOST_THREAD_LIB="$BOOST_THREAD_LIB -lpthread"
- break;
- ;;
- esac
- AC_SUBST(BOOST_THREAD_LIB)
- fi
- fi
-
- CPPFLAGS="$CPPFLAGS_SAVED"
- LDFLAGS="$LDFLAGS_SAVED"
- fi
-])
diff --git a/build-aux/m4/ax_gcc_func_attribute.m4 b/build-aux/m4/ax_gcc_func_attribute.m4
deleted file mode 100644
index c788ca9bd4..0000000000
--- a/build-aux/m4/ax_gcc_func_attribute.m4
+++ /dev/null
@@ -1,223 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE)
-#
-# DESCRIPTION
-#
-# This macro checks if the compiler supports one of GCC's function
-# attributes; many other compilers also provide function attributes with
-# the same syntax. Compiler warnings are used to detect supported
-# attributes as unsupported ones are ignored by default so quieting
-# warnings when using this macro will yield false positives.
-#
-# The ATTRIBUTE parameter holds the name of the attribute to be checked.
-#
-# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_<ATTRIBUTE>.
-#
-# The macro caches its result in the ax_cv_have_func_attribute_<attribute>
-# variable.
-#
-# The macro currently supports the following function attributes:
-#
-# alias
-# aligned
-# alloc_size
-# always_inline
-# artificial
-# cold
-# const
-# constructor
-# constructor_priority for constructor attribute with priority
-# deprecated
-# destructor
-# dllexport
-# dllimport
-# error
-# externally_visible
-# flatten
-# format
-# format_arg
-# gnu_inline
-# hot
-# ifunc
-# leaf
-# malloc
-# noclone
-# noinline
-# nonnull
-# noreturn
-# nothrow
-# optimize
-# pure
-# unused
-# used
-# visibility
-# warning
-# warn_unused_result
-# weak
-# weakref
-#
-# Unsuppored function attributes will be tested with a prototype returning
-# an int and not accepting any arguments and the result of the check might
-# be wrong or meaningless so use with care.
-#
-# LICENSE
-#
-# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@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 3
-
-AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [
- AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1])
-
- AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [
- AC_LINK_IFELSE([AC_LANG_PROGRAM([
- m4_case([$1],
- [alias], [
- int foo( void ) { return 0; }
- int bar( void ) __attribute__(($1("foo")));
- ],
- [aligned], [
- int foo( void ) __attribute__(($1(32)));
- ],
- [alloc_size], [
- void *foo(int a) __attribute__(($1(1)));
- ],
- [always_inline], [
- inline __attribute__(($1)) int foo( void ) { return 0; }
- ],
- [artificial], [
- inline __attribute__(($1)) int foo( void ) { return 0; }
- ],
- [cold], [
- int foo( void ) __attribute__(($1));
- ],
- [const], [
- int foo( void ) __attribute__(($1));
- ],
- [constructor_priority], [
- int foo( void ) __attribute__((__constructor__(65535/2)));
- ],
- [constructor], [
- int foo( void ) __attribute__(($1));
- ],
- [deprecated], [
- int foo( void ) __attribute__(($1("")));
- ],
- [destructor], [
- int foo( void ) __attribute__(($1));
- ],
- [dllexport], [
- __attribute__(($1)) int foo( void ) { return 0; }
- ],
- [dllimport], [
- int foo( void ) __attribute__(($1));
- ],
- [error], [
- int foo( void ) __attribute__(($1("")));
- ],
- [externally_visible], [
- int foo( void ) __attribute__(($1));
- ],
- [flatten], [
- int foo( void ) __attribute__(($1));
- ],
- [format], [
- int foo(const char *p, ...) __attribute__(($1(printf, 1, 2)));
- ],
- [format_arg], [
- char *foo(const char *p) __attribute__(($1(1)));
- ],
- [gnu_inline], [
- inline __attribute__(($1)) int foo( void ) { return 0; }
- ],
- [hot], [
- int foo( void ) __attribute__(($1));
- ],
- [ifunc], [
- int my_foo( void ) { return 0; }
- static int (*resolve_foo(void))(void) { return my_foo; }
- int foo( void ) __attribute__(($1("resolve_foo")));
- ],
- [leaf], [
- __attribute__(($1)) int foo( void ) { return 0; }
- ],
- [malloc], [
- void *foo( void ) __attribute__(($1));
- ],
- [noclone], [
- int foo( void ) __attribute__(($1));
- ],
- [noinline], [
- __attribute__(($1)) int foo( void ) { return 0; }
- ],
- [nonnull], [
- int foo(char *p) __attribute__(($1(1)));
- ],
- [noreturn], [
- void foo( void ) __attribute__(($1));
- ],
- [nothrow], [
- int foo( void ) __attribute__(($1));
- ],
- [optimize], [
- __attribute__(($1(3))) int foo( void ) { return 0; }
- ],
- [pure], [
- int foo( void ) __attribute__(($1));
- ],
- [unused], [
- int foo( void ) __attribute__(($1));
- ],
- [used], [
- int foo( void ) __attribute__(($1));
- ],
- [visibility], [
- int foo_def( void ) __attribute__(($1("default")));
- int foo_hid( void ) __attribute__(($1("hidden")));
- int foo_int( void ) __attribute__(($1("internal")));
- int foo_pro( void ) __attribute__(($1("protected")));
- ],
- [warning], [
- int foo( void ) __attribute__(($1("")));
- ],
- [warn_unused_result], [
- int foo( void ) __attribute__(($1));
- ],
- [weak], [
- int foo( void ) __attribute__(($1));
- ],
- [weakref], [
- static int foo( void ) { return 0; }
- static int bar( void ) __attribute__(($1("foo")));
- ],
- [
- m4_warn([syntax], [Unsupported attribute $1, the test may fail])
- int foo( void ) __attribute__(($1));
- ]
- )], [])
- ],
- dnl GCC doesn't exit with an error if an unknown attribute is
- dnl provided but only outputs a warning, so accept the attribute
- dnl only if no warning were issued.
- [AS_IF([test -s conftest.err],
- [AS_VAR_SET([ac_var], [no])],
- [AS_VAR_SET([ac_var], [yes])])],
- [AS_VAR_SET([ac_var], [no])])
- ])
-
- AS_IF([test yes = AS_VAR_GET([ac_var])],
- [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1,
- [Define to 1 if the system has the `$1' function attribute])], [])
-
- AS_VAR_POPDEF([ac_var])
-])
diff --git a/build_msvc/bitcoin_config.h b/build_msvc/bitcoin_config.h
index 53aead38b5..23c554e396 100644
--- a/build_msvc/bitcoin_config.h
+++ b/build_msvc/bitcoin_config.h
@@ -56,9 +56,6 @@
/* define if the Boost::System library is available */
#define HAVE_BOOST_SYSTEM /**/
-/* define if the Boost::Thread library is available */
-#define HAVE_BOOST_THREAD /**/
-
/* define if the Boost::Unit_Test_Framework library is available */
#define HAVE_BOOST_UNIT_TEST_FRAMEWORK /**/
diff --git a/build_msvc/vcpkg.json b/build_msvc/vcpkg.json
index dfd3929c44..42b9a5d16f 100644
--- a/build_msvc/vcpkg.json
+++ b/build_msvc/vcpkg.json
@@ -8,7 +8,6 @@
"boost-process",
"boost-signals2",
"boost-test",
- "boost-thread",
"sqlite3",
"double-conversion",
{
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index f682486088..f6cd9736c7 100644
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_asan
-export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
+export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
export DOCKER_NAME_TAG=ubuntu:20.04
export NO_DEPENDS=1
export GOAL="install"
diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh
index b7157c608d..c69009100d 100644
--- a/ci/test/00_setup_env_native_fuzz.sh
+++ b/ci/test/00_setup_env_native_fuzz.sh
@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
export DOCKER_NAME_TAG="ubuntu:20.04"
export CONTAINER_NAME=ci_native_fuzz
-export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev"
+export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev"
export NO_DEPENDS=1
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
index e06a40eb23..771ed21c6d 100644
--- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
+++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
export DOCKER_NAME_TAG="ubuntu:20.04"
export CONTAINER_NAME=ci_native_fuzz_valgrind
-export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev valgrind"
+export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev valgrind"
export NO_DEPENDS=1
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh
index f0c153158b..46690a8e69 100644
--- a/ci/test/00_setup_env_native_valgrind.sh
+++ b/ci/test/00_setup_env_native_valgrind.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_valgrind
-export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev"
+export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev"
export USE_VALGRIND=1
export NO_DEPENDS=1
export TEST_RUNNER_EXTRA="--exclude rpc_bind" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh
index 73bcffa0eb..3eea0a4565 100644
--- a/ci/test/00_setup_env_win64.sh
+++ b/ci/test/00_setup_env_win64.sh
@@ -9,7 +9,8 @@ export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_win64
export DOCKER_NAME_TAG=ubuntu:20.04 # Check that Focal can cross-compile to win64 (Focal is used in the gitian build as well)
export HOST=x86_64-w64-mingw32
-export PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 file"
+export DPKG_ADD_ARCH="i386"
+export PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 wine32 file"
export RUN_FUNCTIONAL_TESTS=false
export GOAL="deploy"
export BITCOIN_CONFIG="--enable-reduce-exports --disable-fuzz-binary --disable-gui-tests --without-boost-process"
diff --git a/ci/test/wrap-wine.sh b/ci/test/wrap-wine.sh
index 58a8983e6e..82964897e1 100755
--- a/ci/test/wrap-wine.sh
+++ b/ci/test/wrap-wine.sh
@@ -13,7 +13,7 @@ for b_name in {"${BASE_OUTDIR}/bin"/*,src/secp256k1/*tests,src/univalue/{no_nul,
echo "Wrap $b ..."
mv "$b" "${b}_orig"
echo '#!/usr/bin/env bash' > "$b"
- echo "wine64 \"${b}_orig\" \"\$@\"" >> "$b"
+ echo "( wine \"${b}_orig\" \"\$@\" ) || ( sleep 1 && wine \"${b}_orig\" \"\$@\" )" >> "$b"
chmod +x "$b"
fi
done
diff --git a/configure.ac b/configure.ac
index 4ac985abdc..62f1c308b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -657,7 +657,7 @@ case $host in
AC_MSG_ERROR("windres not found")
fi
- CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -D_WIN32_WINNT=0x0601 -D_WIN32_IE=0x0501 -DWIN32_LEAN_AND_MEAN"
+ CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -D_WIN32_WINNT=0x0601 -D_WIN32_IE=0x0501 -DWIN32_LEAN_AND_MEAN"
dnl libtool insists upon adding -nostdlib and a list of objects/libs to link against.
dnl That breaks our ability to build dll's with static libgcc/libstdc++/libssp. Override
@@ -813,10 +813,6 @@ if test x$ac_cv_sys_large_files != x &&
CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=$ac_cv_sys_large_files"
fi
-AX_GCC_FUNC_ATTRIBUTE([visibility])
-AX_GCC_FUNC_ATTRIBUTE([dllexport])
-AX_GCC_FUNC_ATTRIBUTE([dllimport])
-
if test x$use_glibc_compat != xno; then
AX_CHECK_LINK_FLAG([[-Wl,--wrap=__divmoddi4]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=__divmoddi4"])
AX_CHECK_LINK_FLAG([[-Wl,--wrap=log2f]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=log2f"])
@@ -984,13 +980,13 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
[ AC_MSG_RESULT(no)]
)
-AC_MSG_CHECKING([for visibility attribute])
-AC_LINK_IFELSE([AC_LANG_SOURCE([
- int foo_def( void ) __attribute__((visibility("default")));
+AC_MSG_CHECKING([for default visibility attribute])
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ int foo(void) __attribute__((visibility("default")));
int main(){}
])],
[
- AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE,1,[Define if the visibility attribute is supported.])
+ AC_DEFINE(HAVE_DEFAULT_VISIBILITY_ATTRIBUTE,1,[Define if the visibility attribute is supported.])
AC_MSG_RESULT(yes)
],
[
@@ -1001,6 +997,18 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
]
)
+AC_MSG_CHECKING([for dllexport attribute])
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ __declspec(dllexport) int foo(void);
+ int main(){}
+ ])],
+ [
+ AC_DEFINE(HAVE_DLLEXPORT_ATTRIBUTE,1,[Define if the dllexport attribute is supported.])
+ AC_MSG_RESULT(yes)
+ ],
+ [AC_MSG_RESULT(no)]
+)
+
dnl thread_local is currently disabled when building with glibc back compat.
dnl Our minimum supported glibc is 2.17, however support for thread_local
dnl did not arrive in glibc until 2.18.
@@ -1183,12 +1191,6 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
[ AC_MSG_RESULT(no); HAVE_WEAK_GETAUXVAL=0 ]
)
-dnl Check for reduced exports
-if test x$use_reduce_exports = xyes; then
- AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"],
- [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])])
-fi
-
AC_MSG_CHECKING([for std::system])
AC_LINK_IFELSE(
[ AC_LANG_PROGRAM(
@@ -1385,7 +1387,6 @@ if test x$want_boost = xno; then
fi
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 ] )
@@ -1399,12 +1400,14 @@ dnl counter implementations. In 1.63 and later the std::atomic approach is defau
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"
-BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_THREAD_LIB"
+BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB"
fi
+dnl Check for reduced exports
if test x$use_reduce_exports = xyes; then
- CXXFLAGS="$CXXFLAGS $RE_CXXFLAGS"
- AX_CHECK_LINK_FLAG([[-Wl,--exclude-libs,ALL]], [RELDFLAGS="-Wl,--exclude-libs,ALL"],, [[$LDFLAG_WERROR]])
+ AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[CXXFLAGS="$CXXFLAGS -fvisibility=hidden"],
+ [AC_MSG_ERROR([Cannot set hidden symbol visibility. Use --disable-reduce-exports.])],[[$CXXFLAG_WERROR]])
+ AX_CHECK_LINK_FLAG([[-Wl,--exclude-libs,ALL]],[RELDFLAGS="-Wl,--exclude-libs,ALL"],,[[$LDFLAG_WERROR]])
fi
if test x$use_tests = xyes; then
@@ -1875,6 +1878,7 @@ echo
echo "Options used to compile and link:"
echo " boost process = $ax_cv_boost_process"
echo " multiprocess = $build_multiprocess"
+echo " with libs = $build_bitcoin_libs"
echo " with wallet = $enable_wallet"
if test "x$enable_wallet" != "xno"; then
echo " with sqlite = $use_sqlite"
diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py
index 0facf07948..60acb0d593 100755
--- a/contrib/gitian-build.py
+++ b/contrib/gitian-build.py
@@ -39,7 +39,7 @@ def setup():
if args.docker:
make_image_prog += ['--docker']
elif not args.kvm:
- make_image_prog += ['--lxc']
+ make_image_prog += ['--lxc', '--disksize', '13000']
subprocess.check_call(make_image_prog)
os.chdir(workdir)
if args.is_focal and not args.kvm and not args.docker:
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index ff8a252db9..29a3efdfe6 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -22,7 +22,7 @@ $(package)_toolset_$(host_os)=clang
else
$(package)_toolset_$(host_os)=gcc
endif
-$(package)_config_libraries=filesystem,system,thread,test
+$(package)_config_libraries=filesystem,system,test
$(package)_cxxflags=-std=c++17 -fvisibility=hidden
$(package)_cxxflags_linux=-fPIC
$(package)_cxxflags_android=-fPIC
diff --git a/doc/bips.md b/doc/bips.md
index 8c20533c9b..a5e9a6c020 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -15,6 +15,9 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.21.0**):
* [`BIP 35`](https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki): The 'mempool' protocol message (and the protocol version bump to 60002) has been implemented since **v0.7.0** ([PR #1641](https://github.com/bitcoin/bitcoin/pull/1641)). As of **v0.13.0**, this is only available for `NODE_BLOOM` (BIP 111) peers.
* [`BIP 37`](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki): The bloom filtering for transaction relaying, partial Merkle trees for blocks, and the protocol version bump to 70001 (enabling low-bandwidth SPV clients) has been implemented since **v0.8.0** ([PR #1795](https://github.com/bitcoin/bitcoin/pull/1795)). Disabled by default since **v0.19.0**, can be enabled by the `-peerbloomfilters` option.
* [`BIP 42`](https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki): The bug that would have caused the subsidy schedule to resume after block 13440000 was fixed in **v0.9.2** ([PR #3842](https://github.com/bitcoin/bitcoin/pull/3842)).
+* [`BIP 43`](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki): The experimental descriptor wallets introduced in **v0.21.0** by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 43. ([PR #16528](https://github.com/bitcoin/bitcoin/pull/16528))
+* [`BIP 44`](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki): The experimental descriptor wallets introduced in **v0.21.0** by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 44. ([PR #16528](https://github.com/bitcoin/bitcoin/pull/16528))
+* [`BIP 49`](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki): The experimental descriptor wallets introduced in **v0.21.0** by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 49. ([PR #16528](https://github.com/bitcoin/bitcoin/pull/16528))
* [`BIP 61`](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki): The 'reject' protocol message (and the protocol version bump to 70002) was added in **v0.9.0** ([PR #3185](https://github.com/bitcoin/bitcoin/pull/3185)). Starting **v0.17.0**, whether to send reject messages can be configured with the `-enablebip61` option, and support is deprecated (disabled by default) as of **v0.18.0**. Support was removed in **v0.20.0** ([PR #15437](https://github.com/bitcoin/bitcoin/pull/15437)).
* [`BIP 65`](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki): The CHECKLOCKTIMEVERIFY softfork was merged in **v0.12.0** ([PR #6351](https://github.com/bitcoin/bitcoin/pull/6351)), and backported to **v0.11.2** and **v0.10.4**. Mempool-only CLTV was added in [PR #6124](https://github.com/bitcoin/bitcoin/pull/6124).
* [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)).
@@ -24,6 +27,7 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.21.0**):
Support can be optionally disabled at build time since **v0.18.0** ([PR 14451](https://github.com/bitcoin/bitcoin/pull/14451)),
and it is disabled by default at build time since **v0.19.0** ([PR #15584](https://github.com/bitcoin/bitcoin/pull/15584)).
It has been removed as of **v0.20.0** ([PR 17165](https://github.com/bitcoin/bitcoin/pull/17165)).
+* [`BIP 84`](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki): The experimental descriptor wallets introduced in **v0.21.0** by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 84. ([PR #16528](https://github.com/bitcoin/bitcoin/pull/16528))
* [`BIP 90`](https://github.com/bitcoin/bips/blob/master/bip-0090.mediawiki): Trigger mechanism for activation of BIPs 34, 65, and 66 has been simplified to block height checks since **v0.14.0** ([PR #8391](https://github.com/bitcoin/bitcoin/pull/8391)).
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
* [`BIP 112`](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki): The CHECKSEQUENCEVERIFY opcode has been implemented since **v0.12.1** ([PR #7524](https://github.com/bitcoin/bitcoin/pull/7524)), and has been *buried* since **v0.19.0** ([PR #16060](https://github.com/bitcoin/bitcoin/pull/16060)).
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 4051440886..150b447e68 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -82,7 +82,7 @@ Build requirements:
Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies:
- sudo apt-get install libevent-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev
+ sudo apt-get install libevent-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev
BerkeleyDB is required for the wallet.
diff --git a/src/Makefile.am b/src/Makefile.am
index 2616eb8638..869270d1fc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -233,6 +233,7 @@ BITCOIN_CORE_H = \
util/check.h \
util/error.h \
util/fees.h \
+ util/getuniquepath.h \
util/golombrice.h \
util/hasher.h \
util/macros.h \
@@ -242,6 +243,7 @@ BITCOIN_CORE_H = \
util/rbf.h \
util/ref.h \
util/settings.h \
+ util/sock.h \
util/spanparsing.h \
util/string.h \
util/system.h \
@@ -556,7 +558,9 @@ libbitcoin_util_a_SOURCES = \
util/bytevectorhash.cpp \
util/error.cpp \
util/fees.cpp \
+ util/getuniquepath.cpp \
util/hasher.cpp \
+ util/sock.cpp \
util/system.cpp \
util/message.cpp \
util/moneystr.cpp \
@@ -683,7 +687,7 @@ endif
bitcoin_util_SOURCES = bitcoin-util.cpp
bitcoin_util_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
bitcoin_util_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-bitcoin_util_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+bitcoin_util_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
if TARGET_WINDOWS
bitcoin_util_SOURCES += bitcoin-util-res.rc
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 77cba466ba..e817bb2ee2 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -124,6 +124,7 @@ BITCOIN_TESTS =\
test/sighash_tests.cpp \
test/sigopcount_tests.cpp \
test/skiplist_tests.cpp \
+ test/sock_tests.cpp \
test/streams_tests.cpp \
test/sync_tests.cpp \
test/system_tests.cpp \
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index af5a82f69f..9f7d582e8a 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -48,9 +48,8 @@ static void AssembleBlock(benchmark::Bench& bench)
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
for (const auto& txr : txs) {
- TxValidationState state;
- bool ret{::AcceptToMemoryPool(*test_setup.m_node.mempool, state, txr, nullptr /* plTxnReplaced */, false /* bypass_limits */)};
- assert(ret);
+ const MempoolAcceptResult res = ::AcceptToMemoryPool(*test_setup.m_node.mempool, txr, false /* bypass_limits */);
+ assert(res.m_result_type == MempoolAcceptResult::ResultType::VALID);
}
}
diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp
index fbd14f9325..e5a0d4cb9c 100644
--- a/src/crypto/muhash.cpp
+++ b/src/crypto/muhash.cpp
@@ -17,7 +17,6 @@ namespace {
using limb_t = Num3072::limb_t;
using double_limb_t = Num3072::double_limb_t;
constexpr int LIMB_SIZE = Num3072::LIMB_SIZE;
-constexpr int LIMBS = Num3072::LIMBS;
/** 2^3072 - 1103717, the largest 3072-bit safe prime number, is used as the modulus. */
constexpr limb_t MAX_PRIME_DIFF = 1103717;
@@ -123,7 +122,7 @@ inline void square_n_mul(Num3072& in_out, const int sq, const Num3072& mul)
} // namespace
-/** Indicates wether d is larger than the modulus. */
+/** Indicates whether d is larger than the modulus. */
bool Num3072::IsOverflow() const
{
if (this->limbs[0] <= std::numeric_limits<limb_t>::max() - MAX_PRIME_DIFF) return false;
@@ -276,18 +275,33 @@ void Num3072::Divide(const Num3072& a)
if (this->IsOverflow()) this->FullReduce();
}
-Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
- Num3072 out{};
- uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256();
- unsigned char tmp[BYTE_SIZE];
- ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, BYTE_SIZE);
+Num3072::Num3072(const unsigned char (&data)[BYTE_SIZE]) {
+ for (int i = 0; i < LIMBS; ++i) {
+ if (sizeof(limb_t) == 4) {
+ this->limbs[i] = ReadLE32(data + 4 * i);
+ } else if (sizeof(limb_t) == 8) {
+ this->limbs[i] = ReadLE64(data + 8 * i);
+ }
+ }
+}
+
+void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) {
for (int i = 0; i < LIMBS; ++i) {
if (sizeof(limb_t) == 4) {
- out.limbs[i] = ReadLE32(tmp + 4 * i);
+ WriteLE32(out + i * 4, this->limbs[i]);
} else if (sizeof(limb_t) == 8) {
- out.limbs[i] = ReadLE64(tmp + 8 * i);
+ WriteLE64(out + i * 8, this->limbs[i]);
}
}
+}
+
+Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
+ unsigned char tmp[Num3072::BYTE_SIZE];
+
+ uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256();
+ ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, Num3072::BYTE_SIZE);
+ Num3072 out{tmp};
+
return out;
}
@@ -301,14 +315,8 @@ void MuHash3072::Finalize(uint256& out) noexcept
m_numerator.Divide(m_denominator);
m_denominator.SetToOne(); // Needed to keep the MuHash object valid
- unsigned char data[384];
- for (int i = 0; i < LIMBS; ++i) {
- if (sizeof(limb_t) == 4) {
- WriteLE32(data + i * 4, m_numerator.limbs[i]);
- } else if (sizeof(limb_t) == 8) {
- WriteLE64(data + i * 8, m_numerator.limbs[i]);
- }
- }
+ unsigned char data[Num3072::BYTE_SIZE];
+ m_numerator.ToBytes(data);
out = (CHashWriter(SER_DISK, 0) << data).GetSHA256();
}
diff --git a/src/crypto/muhash.h b/src/crypto/muhash.h
index 0c710007c4..c023a8b9d3 100644
--- a/src/crypto/muhash.h
+++ b/src/crypto/muhash.h
@@ -22,6 +22,7 @@ private:
Num3072 GetInverse() const;
public:
+ static constexpr size_t BYTE_SIZE = 384;
#ifdef HAVE___INT128
typedef unsigned __int128 double_limb_t;
@@ -48,8 +49,10 @@ public:
void Divide(const Num3072& a);
void SetToOne();
void Square();
+ void ToBytes(unsigned char (&out)[BYTE_SIZE]);
Num3072() { this->SetToOne(); };
+ Num3072(const unsigned char (&data)[BYTE_SIZE]);
SERIALIZE_METHODS(Num3072, obj)
{
@@ -78,7 +81,7 @@ public:
* arbitrary subset of the update operations, allowing them to be
* efficiently combined later.
*
- * Muhash does not support checking if an element is already part of the
+ * MuHash does not support checking if an element is already part of the
* set. That is why this class does not enforce the use of a set as the
* data it represents because there is no efficient way to do so.
* It is possible to add elements more than once and also to remove
@@ -91,8 +94,6 @@ public:
class MuHash3072
{
private:
- static constexpr size_t BYTE_SIZE = 384;
-
Num3072 m_numerator;
Num3072 m_denominator;
diff --git a/src/flatfile.cpp b/src/flatfile.cpp
index 11cf357f3d..151f1a38f1 100644
--- a/src/flatfile.cpp
+++ b/src/flatfile.cpp
@@ -66,7 +66,7 @@ size_t FlatFileSeq::Allocate(const FlatFilePos& pos, size_t add_size, bool& out_
if (CheckDiskSpace(m_dir, inc_size)) {
FILE *file = Open(pos);
if (file) {
- LogPrintf("Pre-allocating up to position 0x%x in %s%05u.dat\n", new_size, m_prefix, pos.nFile);
+ LogPrint(BCLog::VALIDATION, "Pre-allocating up to position 0x%x in %s%05u.dat\n", new_size, m_prefix, pos.nFile);
AllocateFileRange(file, pos.nPos, inc_size);
fclose(file);
return inc_size;
diff --git a/src/init.cpp b/src/init.cpp
index a77e2cf1cb..f71fae41e7 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -434,8 +434,9 @@ void SetupServerArgs(NodeContext& node)
argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
- argsman.AddArg("-dnsseed", "Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-dnsseed", strprintf("Query for peer addresses via DNS lookup, if low on addresses (default: %u unless -connect used)", DEFAULT_DNSSEED), ArgsManager::ALLOW_BOOL, OptionsCategory::CONNECTION);
argsman.AddArg("-externalip=<ip>", "Specify your own public address", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-fixedseeds", strprintf("Allow fixed seeds if DNS seeds don't provide peers (default: %u)", DEFAULT_FIXEDSEEDS), ArgsManager::ALLOW_BOOL, OptionsCategory::CONNECTION);
argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-listen", "Accept connections from outside (default: 1 if no -proxy or -connect)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-listenonion", strprintf("Automatically create Tor onion service (default: %d)", DEFAULT_LISTEN_ONION), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
diff --git a/src/net.cpp b/src/net.cpp
index d004aace88..c2e7ca0301 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -20,6 +20,7 @@
#include <protocol.h>
#include <random.h>
#include <scheduler.h>
+#include <util/sock.h>
#include <util/strencodings.h>
#include <util/translation.h>
@@ -429,24 +430,26 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
// Connect
bool connected = false;
- SOCKET hSocket = INVALID_SOCKET;
+ std::unique_ptr<Sock> sock;
proxyType proxy;
if (addrConnect.IsValid()) {
bool proxyConnectionFailed = false;
if (GetProxy(addrConnect.GetNetwork(), proxy)) {
- hSocket = CreateSocket(proxy.proxy);
- if (hSocket == INVALID_SOCKET) {
+ sock = CreateSock(proxy.proxy);
+ if (!sock) {
return nullptr;
}
- connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, proxyConnectionFailed);
+ connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(),
+ *sock, nConnectTimeout, proxyConnectionFailed);
} else {
// no proxy needed (none set for target network)
- hSocket = CreateSocket(addrConnect);
- if (hSocket == INVALID_SOCKET) {
+ sock = CreateSock(addrConnect);
+ if (!sock) {
return nullptr;
}
- connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout, conn_type == ConnectionType::MANUAL);
+ connected = ConnectSocketDirectly(addrConnect, sock->Get(), nConnectTimeout,
+ conn_type == ConnectionType::MANUAL);
}
if (!proxyConnectionFailed) {
// If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
@@ -454,26 +457,26 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
addrman.Attempt(addrConnect, fCountFailure);
}
} else if (pszDest && GetNameProxy(proxy)) {
- hSocket = CreateSocket(proxy.proxy);
- if (hSocket == INVALID_SOCKET) {
+ sock = CreateSock(proxy.proxy);
+ if (!sock) {
return nullptr;
}
std::string host;
int port = default_port;
SplitHostPort(std::string(pszDest), port, host);
bool proxyConnectionFailed;
- connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, proxyConnectionFailed);
+ connected = ConnectThroughProxy(proxy, host, port, *sock, nConnectTimeout,
+ proxyConnectionFailed);
}
if (!connected) {
- CloseSocket(hSocket);
return nullptr;
}
// Add node
NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
- CAddress addr_bind = GetBindAddress(hSocket);
- CNode* pnode = new CNode(id, nLocalServices, hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", conn_type);
+ CAddress addr_bind = GetBindAddress(sock->Get());
+ CNode* pnode = new CNode(id, nLocalServices, sock->Release(), addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", conn_type);
pnode->AddRef();
// We're making a new connection, harvest entropy from the time (and our peer count)
@@ -1769,11 +1772,19 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
// Initiate network connections
- int64_t nStart = GetTime();
+ auto start = GetTime<std::chrono::seconds>();
// Minimum time before next feeler connection (in microseconds).
- int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
- int64_t nNextExtraBlockRelay = PoissonNextSend(nStart*1000*1000, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
+
+ int64_t nNextFeeler = PoissonNextSend(count_microseconds(start), FEELER_INTERVAL);
+ int64_t nNextExtraBlockRelay = PoissonNextSend(count_microseconds(start), EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
+ const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);
+ bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);
+
+ if (!add_fixed_seeds) {
+ LogPrintf("Fixed seeds are disabled\n");
+ }
+
while (!interruptNet)
{
ProcessAddrFetch();
@@ -1785,18 +1796,32 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
if (interruptNet)
return;
- // Add seed nodes if DNS seeds are all down (an infrastructure attack?).
- // Note that we only do this if we started with an empty peers.dat,
- // (in which case we will query DNS seeds immediately) *and* the DNS
- // seeds have not returned any results.
- if (addrman.size() == 0 && (GetTime() - nStart > 60)) {
- static bool done = false;
- if (!done) {
- LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n");
+ if (add_fixed_seeds && addrman.size() == 0) {
+ // When the node starts with an empty peers.dat, there are a few other sources of peers before
+ // we fallback on to fixed seeds: -dnsseed, -seednode, -addnode
+ // If none of those are available, we fallback on to fixed seeds immediately, else we allow
+ // 60 seconds for any of those sources to populate addrman.
+ bool add_fixed_seeds_now = false;
+ // It is cheapest to check if enough time has passed first.
+ if (GetTime<std::chrono::seconds>() > start + std::chrono::minutes{1}) {
+ add_fixed_seeds_now = true;
+ LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty\n");
+ }
+
+ // Checking !dnsseed is cheaper before locking 2 mutexes.
+ if (!add_fixed_seeds_now && !dnsseed) {
+ LOCK2(m_addr_fetches_mutex, cs_vAddedNodes);
+ if (m_addr_fetches.empty() && vAddedNodes.empty()) {
+ add_fixed_seeds_now = true;
+ LogPrintf("Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n");
+ }
+ }
+
+ if (add_fixed_seeds_now) {
CNetAddr local;
local.SetInternal("fixedseeds");
addrman.Add(convertSeed6(Params().FixedSeeds()), local);
- done = true;
+ add_fixed_seeds = false;
}
}
@@ -2188,9 +2213,8 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
return false;
}
- SOCKET hListenSocket = CreateSocket(addrBind);
- if (hListenSocket == INVALID_SOCKET)
- {
+ std::unique_ptr<Sock> sock = CreateSock(addrBind);
+ if (!sock) {
strError = strprintf(Untranslated("Error: Couldn't open socket for incoming connections (socket returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError.original);
return false;
@@ -2198,21 +2222,21 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
- setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int));
+ setsockopt(sock->Get(), SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int));
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if (addrBind.IsIPv6()) {
#ifdef IPV6_V6ONLY
- setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int));
+ setsockopt(sock->Get(), IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int));
#endif
#ifdef WIN32
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
- setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
+ setsockopt(sock->Get(), IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
#endif
}
- if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
+ if (::bind(sock->Get(), (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
@@ -2220,21 +2244,19 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError.original);
- CloseSocket(hListenSocket);
return false;
}
LogPrintf("Bound to %s\n", addrBind.ToString());
// Listen for incoming connections
- if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
+ if (listen(sock->Get(), SOMAXCONN) == SOCKET_ERROR)
{
strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError.original);
- CloseSocket(hListenSocket);
return false;
}
- vhListenSocket.push_back(ListenSocket(hListenSocket, permissions));
+ vhListenSocket.push_back(ListenSocket(sock->Release(), permissions));
return true;
}
@@ -2434,7 +2456,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
// Send and receive from sockets, accept connections
threadSocketHandler = std::thread(&TraceThread<std::function<void()> >, "net", std::function<void()>(std::bind(&CConnman::ThreadSocketHandler, this)));
- if (!gArgs.GetBoolArg("-dnsseed", true))
+ if (!gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED))
LogPrintf("DNS seeding disabled\n");
else
threadDNSAddressSeed = std::thread(&TraceThread<std::function<void()> >, "dnsseed", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this)));
diff --git a/src/net.h b/src/net.h
index a0aa157058..1678eda8e7 100644
--- a/src/net.h
+++ b/src/net.h
@@ -80,6 +80,8 @@ static const int64_t DEFAULT_PEER_CONNECT_TIMEOUT = 60;
static const int NUM_FDS_MESSAGE_CAPTURE = 1;
static const bool DEFAULT_FORCEDNSSEED = false;
+static const bool DEFAULT_DNSSEED = true;
+static const bool DEFAULT_FIXEDSEEDS = true;
static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index a246c8fa1c..4340eb120c 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2178,10 +2178,10 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
if (orphan_it == mapOrphanTransactions.end()) continue;
const CTransactionRef porphanTx = orphan_it->second.tx;
- TxValidationState state;
- std::list<CTransactionRef> removed_txn;
+ const MempoolAcceptResult result = AcceptToMemoryPool(m_mempool, porphanTx, false /* bypass_limits */);
+ const TxValidationState& state = result.m_state;
- if (AcceptToMemoryPool(m_mempool, state, porphanTx, &removed_txn, false /* bypass_limits */)) {
+ if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanHash, porphanTx->GetWitnessHash(), m_connman);
for (unsigned int i = 0; i < porphanTx->vout.size(); i++) {
@@ -2193,7 +2193,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
}
}
EraseOrphanTx(orphanHash);
- for (const CTransactionRef& removedTx : removed_txn) {
+ for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
AddToCompactExtraTransactions(removedTx);
}
break;
@@ -2489,6 +2489,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
bool fRelay = true;
vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
+ if (nTime < 0) {
+ nTime = 0;
+ }
nServices = ServiceFlags(nServiceInt);
if (!pfrom.IsInboundConn())
{
@@ -3197,10 +3200,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
- TxValidationState state;
- std::list<CTransactionRef> lRemovedTxn;
+ const MempoolAcceptResult result = AcceptToMemoryPool(m_mempool, ptx, false /* bypass_limits */);
+ const TxValidationState& state = result.m_state;
- if (AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */)) {
+ if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
m_mempool.check(&::ChainstateActive().CoinsTip());
// As this version of the transaction was acceptable, we can forget about any
// requests for it.
@@ -3223,7 +3226,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
tx.GetHash().ToString(),
m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);
- for (const CTransactionRef& removedTx : lRemovedTxn) {
+ for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
AddToCompactExtraTransactions(removedTx);
}
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 264029d8a2..24188f83c6 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -7,13 +7,17 @@
#include <sync.h>
#include <tinyformat.h>
+#include <util/sock.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/system.h>
+#include <util/time.h>
#include <atomic>
#include <cstdint>
+#include <functional>
#include <limits>
+#include <memory>
#ifndef WIN32
#include <fcntl.h>
@@ -271,14 +275,6 @@ CService LookupNumeric(const std::string& name, int portDefault)
return addr;
}
-struct timeval MillisToTimeval(int64_t nTimeout)
-{
- struct timeval timeout;
- timeout.tv_sec = nTimeout / 1000;
- timeout.tv_usec = (nTimeout % 1000) * 1000;
- return timeout;
-}
-
/** SOCKS version */
enum SOCKSVersion: uint8_t {
SOCKS4 = 0x04,
@@ -336,8 +332,7 @@ enum class IntrRecvError {
* @param data The buffer where the read bytes should be stored.
* @param len The number of bytes to read into the specified buffer.
* @param timeout The total timeout in milliseconds for this read.
- * @param hSocket The socket (has to be in non-blocking mode) from which to read
- * bytes.
+ * @param sock The socket (has to be in non-blocking mode) from which to read bytes.
*
* @returns An IntrRecvError indicating the resulting status of this read.
* IntrRecvError::OK only if all of the specified number of bytes were
@@ -347,7 +342,7 @@ enum class IntrRecvError {
* Sockets can be made non-blocking with SetSocketNonBlocking(const
* SOCKET&, bool).
*/
-static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
+static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock)
{
int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout;
@@ -355,7 +350,7 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
// (in millis) to break off in case of an interruption.
const int64_t maxWait = 1000;
while (len > 0 && curTime < endTime) {
- ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
+ ssize_t ret = sock.Recv(data, len, 0); // Optimistically try the recv first
if (ret > 0) {
len -= ret;
data += ret;
@@ -364,25 +359,10 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
} else { // Other error or blocking
int nErr = WSAGetLastError();
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
- if (!IsSelectableSocket(hSocket)) {
- return IntrRecvError::NetworkError;
- }
// Only wait at most maxWait milliseconds at a time, unless
// we're approaching the end of the specified total timeout
int timeout_ms = std::min(endTime - curTime, maxWait);
-#ifdef USE_POLL
- struct pollfd pollfd = {};
- pollfd.fd = hSocket;
- pollfd.events = POLLIN;
- int nRet = poll(&pollfd, 1, timeout_ms);
-#else
- struct timeval tval = MillisToTimeval(timeout_ms);
- fd_set fdset;
- FD_ZERO(&fdset);
- FD_SET(hSocket, &fdset);
- int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
-#endif
- if (nRet == SOCKET_ERROR) {
+ if (!sock.Wait(std::chrono::milliseconds{timeout_ms}, Sock::RECV)) {
return IntrRecvError::NetworkError;
}
} else {
@@ -436,7 +416,7 @@ static std::string Socks5ErrorString(uint8_t err)
* @param port The destination port.
* @param auth The credentials with which to authenticate with the specified
* SOCKS5 proxy.
- * @param hSocket The SOCKS5 proxy socket.
+ * @param sock The SOCKS5 proxy socket.
*
* @returns Whether or not the operation succeeded.
*
@@ -446,7 +426,7 @@ static std::string Socks5ErrorString(uint8_t err)
* @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
* Version 5</a>
*/
-static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket)
+static bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, const Sock& sock)
{
IntrRecvError recvr;
LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
@@ -464,12 +444,12 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vSocks5Init.push_back(0x01); // 1 method identifier follows...
vSocks5Init.push_back(SOCKS5Method::NOAUTH);
}
- ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
+ ssize_t ret = sock.Send(vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5Init.size()) {
return error("Error sending to proxy");
}
uint8_t pchRet1[2];
- if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
+ if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) {
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
return false;
}
@@ -486,13 +466,13 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
vAuth.push_back(auth->password.size());
vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
- ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
+ ret = sock.Send(vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vAuth.size()) {
return error("Error sending authentication to proxy");
}
LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
uint8_t pchRetA[2];
- if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
+ if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) {
return error("Error reading proxy authentication response");
}
if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
@@ -512,12 +492,12 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
vSocks5.push_back((port >> 8) & 0xFF);
vSocks5.push_back((port >> 0) & 0xFF);
- ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
+ ret = sock.Send(vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5.size()) {
return error("Error sending to proxy");
}
uint8_t pchRet2[4];
- if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
+ if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) {
if (recvr == IntrRecvError::Timeout) {
/* If a timeout happens here, this effectively means we timed out while connecting
* to the remote node. This is very common for Tor, so do not print an
@@ -541,16 +521,16 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
uint8_t pchRet3[256];
switch (pchRet2[3])
{
- case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
- case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
+ case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, sock); break;
+ case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, sock); break;
case SOCKS5Atyp::DOMAINNAME:
{
- recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
+ recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, sock);
if (recvr != IntrRecvError::OK) {
return error("Error reading from proxy");
}
int nRecv = pchRet3[0];
- recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
+ recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, sock);
break;
}
default: return error("Error: malformed proxy response");
@@ -558,41 +538,35 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
if (recvr != IntrRecvError::OK) {
return error("Error reading from proxy");
}
- if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
+ if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) {
return error("Error reading from proxy");
}
LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
return true;
}
-/**
- * Try to create a socket file descriptor with specific properties in the
- * communications domain (address family) of the specified service.
- *
- * For details on the desired properties, see the inline comments in the source
- * code.
- */
-SOCKET CreateSocket(const CService &addrConnect)
+std::unique_ptr<Sock> CreateSockTCP(const CService& address_family)
{
// Create a sockaddr from the specified service.
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
- if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
- LogPrintf("Cannot create socket for %s: unsupported network\n", addrConnect.ToString());
- return INVALID_SOCKET;
+ if (!address_family.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
+ LogPrintf("Cannot create socket for %s: unsupported network\n", address_family.ToString());
+ return nullptr;
}
// Create a TCP socket in the address family of the specified service.
SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
- if (hSocket == INVALID_SOCKET)
- return INVALID_SOCKET;
+ if (hSocket == INVALID_SOCKET) {
+ return nullptr;
+ }
// Ensure that waiting for I/O on this socket won't result in undefined
// behavior.
if (!IsSelectableSocket(hSocket)) {
CloseSocket(hSocket);
LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
- return INVALID_SOCKET;
+ return nullptr;
}
#ifdef SO_NOSIGPIPE
@@ -608,11 +582,14 @@ SOCKET CreateSocket(const CService &addrConnect)
// Set the non-blocking option on the socket.
if (!SetSocketNonBlocking(hSocket, true)) {
CloseSocket(hSocket);
- LogPrintf("CreateSocket: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
+ LogPrintf("Error setting socket to non-blocking: %s\n", NetworkErrorString(WSAGetLastError()));
+ return nullptr;
}
- return hSocket;
+ return std::make_unique<Sock>(hSocket);
}
+std::function<std::unique_ptr<Sock>(const CService&)> CreateSock = CreateSockTCP;
+
template<typename... Args>
static void LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args) {
std::string error_message = tfm::format(fmt, args...);
@@ -786,7 +763,7 @@ bool IsProxy(const CNetAddr &addr) {
* @param proxy The SOCKS5 proxy.
* @param strDest The destination service to which to connect.
* @param port The destination port.
- * @param hSocket The socket on which to connect to the SOCKS5 proxy.
+ * @param sock The socket on which to connect to the SOCKS5 proxy.
* @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
* proxy to be established.
* @param[out] outProxyConnectionFailed Whether or not the connection to the
@@ -794,10 +771,10 @@ bool IsProxy(const CNetAddr &addr) {
*
* @returns Whether or not the operation succeeded.
*/
-bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool& outProxyConnectionFailed)
+bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
{
// first connect to proxy server
- if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) {
+ if (!ConnectSocketDirectly(proxy.proxy, sock.Get(), nTimeout, true)) {
outProxyConnectionFailed = true;
return false;
}
@@ -806,11 +783,11 @@ bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int
ProxyCredentials random_auth;
static std::atomic_int counter(0);
random_auth.username = random_auth.password = strprintf("%i", counter++);
- if (!Socks5(strDest, (uint16_t)port, &random_auth, hSocket)) {
+ if (!Socks5(strDest, (uint16_t)port, &random_auth, sock)) {
return false;
}
} else {
- if (!Socks5(strDest, (uint16_t)port, 0, hSocket)) {
+ if (!Socks5(strDest, (uint16_t)port, 0, sock)) {
return false;
}
}
@@ -869,57 +846,6 @@ bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
return false;
}
-#ifdef WIN32
-std::string NetworkErrorString(int err)
-{
- wchar_t buf[256];
- buf[0] = 0;
- if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
- nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- buf, ARRAYSIZE(buf), nullptr))
- {
- return strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);
- }
- else
- {
- return strprintf("Unknown error (%d)", err);
- }
-}
-#else
-std::string NetworkErrorString(int err)
-{
- char buf[256];
- buf[0] = 0;
- /* Too bad there are two incompatible implementations of the
- * thread-safe strerror. */
- const char *s;
-#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
- s = strerror_r(err, buf, sizeof(buf));
-#else /* POSIX variant always returns message in buffer */
- s = buf;
- if (strerror_r(err, buf, sizeof(buf)))
- buf[0] = 0;
-#endif
- return strprintf("%s (%d)", s, err);
-}
-#endif
-
-bool CloseSocket(SOCKET& hSocket)
-{
- if (hSocket == INVALID_SOCKET)
- return false;
-#ifdef WIN32
- int ret = closesocket(hSocket);
-#else
- int ret = close(hSocket);
-#endif
- if (ret) {
- LogPrintf("Socket close failed: %d. Error: %s\n", hSocket, NetworkErrorString(WSAGetLastError()));
- }
- hSocket = INVALID_SOCKET;
- return ret != SOCKET_ERROR;
-}
-
bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking)
{
if (fNonBlocking) {
diff --git a/src/netbase.h b/src/netbase.h
index ac4cd97673..afc373ef49 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -12,7 +12,10 @@
#include <compat.h>
#include <netaddress.h>
#include <serialize.h>
+#include <util/sock.h>
+#include <functional>
+#include <memory>
#include <stdint.h>
#include <string>
#include <vector>
@@ -51,21 +54,25 @@ bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllo
bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions);
CService LookupNumeric(const std::string& name, int portDefault = 0);
bool LookupSubNet(const std::string& strSubnet, CSubNet& subnet);
-SOCKET CreateSocket(const CService &addrConnect);
+
+/**
+ * Create a TCP socket in the given address family.
+ * @param[in] address_family The socket is created in the same address family as this address.
+ * @return pointer to the created Sock object or unique_ptr that owns nothing in case of failure
+ */
+std::unique_ptr<Sock> CreateSockTCP(const CService& address_family);
+
+/**
+ * Socket factory. Defaults to `CreateSockTCP()`, but can be overridden by unit tests.
+ */
+extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
+
bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout, bool manual_connection);
-bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocketRet, int nTimeout, bool& outProxyConnectionFailed);
-/** Return readable error string for a network error code */
-std::string NetworkErrorString(int err);
-/** Close socket and set hSocket to INVALID_SOCKET */
-bool CloseSocket(SOCKET& hSocket);
+bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
/** Disable or enable blocking-mode for a socket */
bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking);
/** Set the TCP_NODELAY flag on a socket */
bool SetSocketNoDelay(const SOCKET& hSocket);
-/**
- * Convert milliseconds to a struct timeval for e.g. select.
- */
-struct timeval MillisToTimeval(int64_t nTimeout);
void InterruptSocks5(bool interrupt);
#endif // BITCOIN_NETBASE_H
diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp
index 56113cb731..b994e79391 100644
--- a/src/node/coinstats.cpp
+++ b/src/node/coinstats.cpp
@@ -6,6 +6,7 @@
#include <node/coinstats.h>
#include <coins.h>
+#include <crypto/muhash.h>
#include <hash.h>
#include <serialize.h>
#include <uint256.h>
@@ -24,31 +25,47 @@ static uint64_t GetBogoSize(const CScript& scriptPubKey)
scriptPubKey.size() /* scriptPubKey */;
}
-static void ApplyStats(CCoinsStats& stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
+static void ApplyHash(CCoinsStats& stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs, std::map<uint32_t, Coin>::const_iterator it)
{
- assert(!outputs.empty());
- ss << hash;
- ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase ? 1u : 0u);
- stats.nTransactions++;
- for (const auto& output : outputs) {
- ss << VARINT(output.first + 1);
- ss << output.second.out.scriptPubKey;
- ss << VARINT_MODE(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
- stats.nTransactionOutputs++;
- stats.nTotalAmount += output.second.out.nValue;
- stats.nBogoSize += GetBogoSize(output.second.out.scriptPubKey);
+ if (it == outputs.begin()) {
+ ss << hash;
+ ss << VARINT(it->second.nHeight * 2 + it->second.fCoinBase ? 1u : 0u);
+ }
+
+ ss << VARINT(it->first + 1);
+ ss << it->second.out.scriptPubKey;
+ ss << VARINT_MODE(it->second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
+
+ if (it == std::prev(outputs.end())) {
+ ss << VARINT(0u);
}
- ss << VARINT(0u);
}
-static void ApplyStats(CCoinsStats& stats, std::nullptr_t, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
+static void ApplyHash(CCoinsStats& stats, std::nullptr_t, const uint256& hash, const std::map<uint32_t, Coin>& outputs, std::map<uint32_t, Coin>::const_iterator it) {}
+
+static void ApplyHash(CCoinsStats& stats, MuHash3072& muhash, const uint256& hash, const std::map<uint32_t, Coin>& outputs, std::map<uint32_t, Coin>::const_iterator it)
+{
+ COutPoint outpoint = COutPoint(hash, it->first);
+ Coin coin = it->second;
+
+ CDataStream ss(SER_DISK, PROTOCOL_VERSION);
+ ss << outpoint;
+ ss << static_cast<uint32_t>(coin.nHeight * 2 + coin.fCoinBase);
+ ss << coin.out;
+ muhash.Insert(MakeUCharSpan(ss));
+}
+
+template <typename T>
+static void ApplyStats(CCoinsStats& stats, T& hash_obj, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
{
assert(!outputs.empty());
stats.nTransactions++;
- for (const auto& output : outputs) {
+ for (auto it = outputs.begin(); it != outputs.end(); ++it) {
+ ApplyHash(stats, hash_obj, hash, outputs, it);
+
stats.nTransactionOutputs++;
- stats.nTotalAmount += output.second.out.nValue;
- stats.nBogoSize += GetBogoSize(output.second.out.scriptPubKey);
+ stats.nTotalAmount += it->second.out.nValue;
+ stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
}
}
@@ -104,6 +121,10 @@ bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, CoinStatsHashType hash_t
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
return GetUTXOStats(view, stats, ss, interruption_point);
}
+ case(CoinStatsHashType::MUHASH): {
+ MuHash3072 muhash;
+ return GetUTXOStats(view, stats, muhash, interruption_point);
+ }
case(CoinStatsHashType::NONE): {
return GetUTXOStats(view, stats, nullptr, interruption_point);
}
@@ -116,10 +137,18 @@ static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
{
ss << stats.hashBlock;
}
+// MuHash does not need the prepare step
+static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {}
static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}
static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats)
{
stats.hashSerialized = ss.GetHash();
}
+static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
+{
+ uint256 out;
+ muhash.Finalize(out);
+ stats.hashSerialized = out;
+}
static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
diff --git a/src/node/coinstats.h b/src/node/coinstats.h
index 7c56bfc2ad..f02b95235f 100644
--- a/src/node/coinstats.h
+++ b/src/node/coinstats.h
@@ -16,6 +16,7 @@ class CCoinsView;
enum class CoinStatsHashType {
HASH_SERIALIZED,
+ MUHASH,
NONE,
};
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index d3bb9687a8..6f5acf41e3 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -50,22 +50,22 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
}
if (!node.mempool->exists(hashTx)) {
// Transaction is not already in the mempool.
- TxValidationState state;
if (max_tx_fee > 0) {
// First, call ATMP with test_accept and check the fee. If ATMP
// fails here, return error immediately.
- CAmount fee{0};
- if (!AcceptToMemoryPool(*node.mempool, state, tx,
- nullptr /* plTxnReplaced */, false /* bypass_limits */, /* test_accept */ true, &fee)) {
- return HandleATMPError(state, err_string);
- } else if (fee > max_tx_fee) {
+ const MempoolAcceptResult result = AcceptToMemoryPool(*node.mempool, tx, false /* bypass_limits */,
+ true /* test_accept */);
+ if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
+ return HandleATMPError(result.m_state, err_string);
+ } else if (result.m_base_fees.value() > max_tx_fee) {
return TransactionError::MAX_FEE_EXCEEDED;
}
}
// Try to submit the transaction to the mempool.
- if (!AcceptToMemoryPool(*node.mempool, state, tx,
- nullptr /* plTxnReplaced */, false /* bypass_limits */)) {
- return HandleATMPError(state, err_string);
+ const MempoolAcceptResult result = AcceptToMemoryPool(*node.mempool, tx, false /* bypass_limits */,
+ false /* test_accept */);
+ if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
+ return HandleATMPError(result.m_state, err_string);
}
// Transaction was accepted to the mempool.
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index ea92dc11a4..5be02b1e4e 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -156,21 +156,11 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails)
{
- // Serialize passed information without accessing chain state of the active chain!
- AssertLockNotHeld(cs_main); // For performance reasons
+ UniValue result = blockheaderToJSON(tip, blockindex);
- UniValue result(UniValue::VOBJ);
- result.pushKV("hash", blockindex->GetBlockHash().GetHex());
- const CBlockIndex* pnext;
- int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
- result.pushKV("confirmations", confirmations);
result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS));
result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
result.pushKV("weight", (int)::GetBlockWeight(block));
- result.pushKV("height", blockindex->nHeight);
- result.pushKV("version", block.nVersion);
- result.pushKV("versionHex", strprintf("%08x", block.nVersion));
- result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
UniValue txs(UniValue::VARR);
if (txDetails) {
CBlockUndo blockUndo;
@@ -189,18 +179,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
}
}
result.pushKV("tx", txs);
- result.pushKV("time", block.GetBlockTime());
- result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
- result.pushKV("nonce", (uint64_t)block.nNonce);
- result.pushKV("bits", strprintf("%08x", block.nBits));
- result.pushKV("difficulty", GetDifficulty(blockindex));
- result.pushKV("chainwork", blockindex->nChainWork.GetHex());
- result.pushKV("nTx", (uint64_t)blockindex->nTx);
- if (blockindex->pprev)
- result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
- if (pnext)
- result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
return result;
}
@@ -1047,13 +1026,26 @@ static RPCHelpMan pruneblockchain()
};
}
+CoinStatsHashType ParseHashType(const std::string& hash_type_input)
+{
+ if (hash_type_input == "hash_serialized_2") {
+ return CoinStatsHashType::HASH_SERIALIZED;
+ } else if (hash_type_input == "muhash") {
+ return CoinStatsHashType::MUHASH;
+ } else if (hash_type_input == "none") {
+ return CoinStatsHashType::NONE;
+ } else {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s is not a valid hash_type", hash_type_input));
+ }
+}
+
static RPCHelpMan gettxoutsetinfo()
{
return RPCHelpMan{"gettxoutsetinfo",
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n",
{
- {"hash_type", RPCArg::Type::STR, /* default */ "hash_serialized_2", "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'none'."},
+ {"hash_type", RPCArg::Type::STR, /* default */ "hash_serialized_2", "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -1063,7 +1055,8 @@ static RPCHelpMan gettxoutsetinfo()
{RPCResult::Type::NUM, "transactions", "The number of transactions with unspent outputs"},
{RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
{RPCResult::Type::NUM, "bogosize", "A meaningless metric for UTXO set size"},
- {RPCResult::Type::STR_HEX, "hash_serialized_2", "The serialized hash (only present if 'hash_serialized_2' hash_type is chosen)"},
+ {RPCResult::Type::STR_HEX, "hash_serialized_2", /* optional */ true, "The serialized hash (only present if 'hash_serialized_2' hash_type is chosen)"},
+ {RPCResult::Type::STR_HEX, "muhash", /* optional */ true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
{RPCResult::Type::NUM, "disk_size", "The estimated size of the chainstate on disk"},
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount"},
}},
@@ -1078,7 +1071,7 @@ static RPCHelpMan gettxoutsetinfo()
CCoinsStats stats;
::ChainstateActive().ForceFlushStateToDisk();
- const CoinStatsHashType hash_type = ParseHashType(request.params[0], CoinStatsHashType::HASH_SERIALIZED);
+ const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
CCoinsView* coins_view = WITH_LOCK(cs_main, return &ChainstateActive().CoinsDB());
NodeContext& node = EnsureNodeContext(request.context);
@@ -1091,6 +1084,9 @@ static RPCHelpMan gettxoutsetinfo()
if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
ret.pushKV("hash_serialized_2", stats.hashSerialized.GetHex());
}
+ if (hash_type == CoinStatsHashType::MUHASH) {
+ ret.pushKV("muhash", stats.hashSerialized.GetHex());
+ }
ret.pushKV("disk_size", stats.nDiskSize);
ret.pushKV("total_amount", ValueFromAmount(stats.nTotalAmount));
} else {
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index b75a7b8d26..38a0bddddb 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -365,13 +365,13 @@ static RPCHelpMan signmessagewithprivkey()
static RPCHelpMan setmocktime()
{
return RPCHelpMan{"setmocktime",
- "\nSet the local time to given timestamp (-regtest only)\n",
- {
- {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, UNIX_EPOCH_TIME + "\n"
- " Pass 0 to go back to using the system time."},
- },
- RPCResult{RPCResult::Type::NONE, "", ""},
- RPCExamples{""},
+ "\nSet the local time to given timestamp (-regtest only)\n",
+ {
+ {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, UNIX_EPOCH_TIME + "\n"
+ "Pass 0 to go back to using the system time."},
+ },
+ RPCResult{RPCResult::Type::NONE, "", ""},
+ RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
if (!Params().IsMockableChain()) {
@@ -386,7 +386,10 @@ static RPCHelpMan setmocktime()
LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VNUM});
- int64_t time = request.params[0].get_int64();
+ const int64_t time{request.params[0].get_int64()};
+ if (time < 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime can not be negative: %s.", time));
+ }
SetMockTime(time);
if (request.context.Has<NodeContext>()) {
for (const auto& chain_client : request.context.Get<NodeContext>().chain_clients) {
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index ac42404470..784a53e060 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -946,44 +946,35 @@ static RPCHelpMan testmempoolaccept()
result_0.pushKV("txid", tx->GetHash().GetHex());
result_0.pushKV("wtxid", tx->GetWitnessHash().GetHex());
- TxValidationState state;
- bool test_accept_res;
- CAmount fee{0};
- {
- LOCK(cs_main);
- test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx),
- nullptr /* plTxnReplaced */, false /* bypass_limits */, /* test_accept */ true, &fee);
- }
-
- // Check that fee does not exceed maximum fee
- if (test_accept_res && max_raw_tx_fee && fee > max_raw_tx_fee) {
- result_0.pushKV("allowed", false);
- result_0.pushKV("reject-reason", "max-fee-exceeded");
- result.push_back(std::move(result_0));
- return result;
- }
- result_0.pushKV("allowed", test_accept_res);
+ const MempoolAcceptResult accept_result = WITH_LOCK(cs_main, return AcceptToMemoryPool(mempool, std::move(tx),
+ false /* bypass_limits */, /* test_accept */ true));
// Only return the fee and vsize if the transaction would pass ATMP.
// These can be used to calculate the feerate.
- if (test_accept_res) {
- result_0.pushKV("vsize", virtual_size);
- UniValue fees(UniValue::VOBJ);
- fees.pushKV("base", ValueFromAmount(fee));
- result_0.pushKV("fees", fees);
+ if (accept_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
+ const CAmount fee = accept_result.m_base_fees.value();
+ // Check that fee does not exceed maximum fee
+ if (max_raw_tx_fee && fee > max_raw_tx_fee) {
+ result_0.pushKV("allowed", false);
+ result_0.pushKV("reject-reason", "max-fee-exceeded");
+ } else {
+ result_0.pushKV("allowed", true);
+ result_0.pushKV("vsize", virtual_size);
+ UniValue fees(UniValue::VOBJ);
+ fees.pushKV("base", ValueFromAmount(fee));
+ result_0.pushKV("fees", fees);
+ }
+ result.push_back(std::move(result_0));
} else {
- if (state.IsInvalid()) {
- if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
- result_0.pushKV("reject-reason", "missing-inputs");
- } else {
- result_0.pushKV("reject-reason", strprintf("%s", state.GetRejectReason()));
- }
+ result_0.pushKV("allowed", false);
+ const TxValidationState state = accept_result.m_state;
+ if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
+ result_0.pushKV("reject-reason", "missing-inputs");
} else {
result_0.pushKV("reject-reason", state.GetRejectReason());
}
+ result.push_back(std::move(result_0));
}
-
- result.push_back(std::move(result_0));
return result;
},
};
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index bfdba5253c..e890c0108a 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -113,23 +113,6 @@ std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
return ParseHexV(find_value(o, strKey), strKey);
}
-CoinStatsHashType ParseHashType(const UniValue& param, const CoinStatsHashType default_type)
-{
- if (param.isNull()) {
- return default_type;
- } else {
- std::string hash_type_input = param.get_str();
-
- if (hash_type_input == "hash_serialized_2") {
- return CoinStatsHashType::HASH_SERIALIZED;
- } else if (hash_type_input == "none") {
- return CoinStatsHashType::NONE;
- } else {
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%d is not a valid hash_type", hash_type_input));
- }
- }
-}
-
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
{
return "> bitcoin-cli " + methodname + " " + args + "\n";
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 444a013ca1..c54ce85f60 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -77,8 +77,6 @@ extern uint256 ParseHashO(const UniValue& o, std::string strKey);
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
-CoinStatsHashType ParseHashType(const UniValue& param, const CoinStatsHashType default_type);
-
extern CAmount AmountFromValue(const UniValue& value);
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index c5dceac848..b6939127e1 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -11,14 +11,12 @@
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#if defined(_WIN32)
- #if defined(DLL_EXPORT)
- #if defined(HAVE_FUNC_ATTRIBUTE_DLLEXPORT)
- #define EXPORT_SYMBOL __declspec(dllexport)
- #else
- #define EXPORT_SYMBOL
- #endif
+ #if defined(HAVE_DLLEXPORT_ATTRIBUTE)
+ #define EXPORT_SYMBOL __declspec(dllexport)
+ #else
+ #define EXPORT_SYMBOL
#endif
- #elif defined(HAVE_FUNC_ATTRIBUTE_VISIBILITY)
+ #elif defined(HAVE_DEFAULT_VISIBILITY_ATTRIBUTE)
#define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
#endif
#elif defined(MSC_VER) && !defined(STATIC_LIBBITCOINCONSENSUS)
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index cf47d37e70..c6d898a25a 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -12,8 +12,10 @@
#include <cuckoocache.h>
-#include <boost/thread/lock_types.hpp>
-#include <boost/thread/shared_mutex.hpp>
+#include <algorithm>
+#include <mutex>
+#include <shared_mutex>
+#include <vector>
namespace {
/**
@@ -29,7 +31,7 @@ private:
CSHA256 m_salted_hasher_schnorr;
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
map_type setValid;
- boost::shared_mutex cs_sigcache;
+ std::shared_mutex cs_sigcache;
public:
CSignatureCache()
@@ -64,13 +66,13 @@ public:
bool
Get(const uint256& entry, const bool erase)
{
- boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
+ std::shared_lock<std::shared_mutex> lock(cs_sigcache);
return setValid.contains(entry, erase);
}
void Set(const uint256& entry)
{
- boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
+ std::unique_lock<std::shared_mutex> lock(cs_sigcache);
setValid.insert(entry);
}
uint32_t setup_bytes(size_t n)
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 8afbe9ebed..dba5ce621a 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -106,8 +106,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
std::vector<valtype> vSolutions;
whichTypeRet = Solver(scriptPubKey, vSolutions);
- switch (whichTypeRet)
- {
+ switch (whichTypeRet) {
case TxoutType::NONSTANDARD:
case TxoutType::NULL_DATA:
case TxoutType::WITNESS_UNKNOWN:
@@ -173,10 +172,8 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
// Could not find witnessScript, add to missing
sigdata.missing_witness_script = uint256(vSolutions[0]);
return false;
-
- default:
- return false;
- }
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
static CScript PushAll(const std::vector<valtype>& values)
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 7967c01858..4d882cd1f1 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -45,8 +45,7 @@ WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
std::string GetTxnOutputType(TxoutType t)
{
- switch (t)
- {
+ switch (t) {
case TxoutType::NONSTANDARD: return "nonstandard";
case TxoutType::PUBKEY: return "pubkey";
case TxoutType::PUBKEYHASH: return "pubkeyhash";
@@ -182,7 +181,8 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
std::vector<valtype> vSolutions;
TxoutType whichType = Solver(scriptPubKey, vSolutions);
- if (whichType == TxoutType::PUBKEY) {
+ switch (whichType) {
+ case TxoutType::PUBKEY: {
CPubKey pubKey(vSolutions[0]);
if (!pubKey.IsValid())
return false;
@@ -190,26 +190,28 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
addressRet = PKHash(pubKey);
return true;
}
- else if (whichType == TxoutType::PUBKEYHASH)
- {
+ case TxoutType::PUBKEYHASH: {
addressRet = PKHash(uint160(vSolutions[0]));
return true;
}
- else if (whichType == TxoutType::SCRIPTHASH)
- {
+ case TxoutType::SCRIPTHASH: {
addressRet = ScriptHash(uint160(vSolutions[0]));
return true;
- } else if (whichType == TxoutType::WITNESS_V0_KEYHASH) {
+ }
+ case TxoutType::WITNESS_V0_KEYHASH: {
WitnessV0KeyHash hash;
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
addressRet = hash;
return true;
- } else if (whichType == TxoutType::WITNESS_V0_SCRIPTHASH) {
+ }
+ case TxoutType::WITNESS_V0_SCRIPTHASH: {
WitnessV0ScriptHash hash;
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
addressRet = hash;
return true;
- } else if (whichType == TxoutType::WITNESS_UNKNOWN || whichType == TxoutType::WITNESS_V1_TAPROOT) {
+ }
+ case TxoutType::WITNESS_UNKNOWN:
+ case TxoutType::WITNESS_V1_TAPROOT: {
WitnessUnknown unk;
unk.version = vSolutions[0][0];
std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
@@ -217,8 +219,13 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
addressRet = unk;
return true;
}
- // Multisig txns have more than one address...
- return false;
+ case TxoutType::MULTISIG:
+ // Multisig txns have more than one address...
+ case TxoutType::NULL_DATA:
+ case TxoutType::NONSTANDARD:
+ return false;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp
index 75c7e47e64..35b66cfc53 100644
--- a/src/test/cuckoocache_tests.cpp
+++ b/src/test/cuckoocache_tests.cpp
@@ -1,15 +1,18 @@
// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <boost/test/unit_test.hpp>
-#include <boost/thread/lock_types.hpp>
-#include <boost/thread/shared_mutex.hpp>
#include <cuckoocache.h>
-#include <deque>
#include <random.h>
#include <script/sigcache.h>
#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <deque>
+#include <mutex>
+#include <shared_mutex>
#include <thread>
+#include <vector>
/** Test Suite for CuckooCache
*
@@ -201,11 +204,11 @@ static void test_cache_erase_parallel(size_t megabytes)
* "future proofed".
*/
std::vector<uint256> hashes_insert_copy = hashes;
- boost::shared_mutex mtx;
+ std::shared_mutex mtx;
{
/** Grab lock to make sure we release inserts */
- boost::unique_lock<boost::shared_mutex> l(mtx);
+ std::unique_lock<std::shared_mutex> l(mtx);
/** Insert the first half */
for (uint32_t i = 0; i < (n_insert / 2); ++i)
set.insert(hashes_insert_copy[i]);
@@ -219,7 +222,7 @@ static void test_cache_erase_parallel(size_t megabytes)
/** Each thread is emplaced with x copy-by-value
*/
threads.emplace_back([&, x] {
- boost::shared_lock<boost::shared_mutex> l(mtx);
+ std::shared_lock<std::shared_mutex> l(mtx);
size_t ntodo = (n_insert/4)/3;
size_t start = ntodo*x;
size_t end = ntodo*(x+1);
@@ -234,7 +237,7 @@ static void test_cache_erase_parallel(size_t megabytes)
for (std::thread& t : threads)
t.join();
/** Grab lock to make sure we observe erases */
- boost::unique_lock<boost::shared_mutex> l(mtx);
+ std::unique_lock<std::shared_mutex> l(mtx);
/** Insert the second half */
for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
set.insert(hashes_insert_copy[i]);
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index ec487aa3ff..e52cd5230c 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -5,6 +5,7 @@
#include <fs.h>
#include <test/util/setup_common.h>
#include <util/system.h>
+#include <util/getuniquepath.h>
#include <boost/test/unit_test.hpp>
@@ -69,6 +70,21 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream)
BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, ""));
BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, {}));
}
+ {
+ fs::path p1 = GetUniquePath(tmpfolder);
+ fs::path p2 = GetUniquePath(tmpfolder);
+ fs::path p3 = GetUniquePath(tmpfolder);
+
+ // Ensure that the parent path is always the same.
+ BOOST_CHECK_EQUAL(tmpfolder, p1.parent_path());
+ BOOST_CHECK_EQUAL(tmpfolder, p2.parent_path());
+ BOOST_CHECK_EQUAL(tmpfolder, p3.parent_path());
+
+ // Ensure that generated paths are actually different.
+ BOOST_CHECK(p1 != p2);
+ BOOST_CHECK(p2 != p3);
+ BOOST_CHECK(p1 != p3);
+ }
}
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
index e5df672163..45151258b3 100644
--- a/src/test/fuzz/fuzz.cpp
+++ b/src/test/fuzz/fuzz.cpp
@@ -13,15 +13,15 @@
const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
-std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize>>& FuzzTargets()
+std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets()
{
- static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize>> g_fuzz_targets;
+ static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets;
return g_fuzz_targets;
}
-void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init)
+void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init, TypeHidden hidden)
{
- const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init));
+ const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init), hidden);
Assert(it_ins.second);
}
@@ -31,6 +31,7 @@ void initialize()
{
if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) {
for (const auto& t : FuzzTargets()) {
+ if (std::get<2>(t.second)) continue;
std::cout << t.first << std::endl;
}
Assert(false);
diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h
index 19386a5059..4abc52c15a 100644
--- a/src/test/fuzz/fuzz.h
+++ b/src/test/fuzz/fuzz.h
@@ -15,22 +15,26 @@ using FuzzBufferType = Span<const uint8_t>;
using TypeTestOneInput = std::function<void(FuzzBufferType)>;
using TypeInitialize = std::function<void()>;
+using TypeHidden = bool;
-void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init);
+void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init, TypeHidden hidden);
-inline void FuzzFrameworkEmptyFun() {}
+inline void FuzzFrameworkEmptyInitFun() {}
#define FUZZ_TARGET(name) \
- FUZZ_TARGET_INIT(name, FuzzFrameworkEmptyFun)
-
-#define FUZZ_TARGET_INIT(name, init_fun) \
- void name##_fuzz_target(FuzzBufferType); \
- struct name##_Before_Main { \
- name##_Before_Main() \
- { \
- FuzzFrameworkRegisterTarget(#name, name##_fuzz_target, init_fun); \
- } \
- } const static g_##name##_before_main; \
+ FUZZ_TARGET_INIT(name, FuzzFrameworkEmptyInitFun)
+
+#define FUZZ_TARGET_INIT(name, init_fun) \
+ FUZZ_TARGET_INIT_HIDDEN(name, init_fun, false)
+
+#define FUZZ_TARGET_INIT_HIDDEN(name, init_fun, hidden) \
+ void name##_fuzz_target(FuzzBufferType); \
+ struct name##_Before_Main { \
+ name##_Before_Main() \
+ { \
+ FuzzFrameworkRegisterTarget(#name, name##_fuzz_target, init_fun, hidden); \
+ } \
+ } const static g_##name##_before_main; \
void name##_fuzz_target(FuzzBufferType buffer)
#endif // BITCOIN_TEST_FUZZ_FUZZ_H
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index a3e46ca2a2..442e32d4ca 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -35,8 +35,27 @@ namespace {
const TestingSetup* g_setup;
} // namespace
+size_t& GetNumMsgTypes()
+{
+ static size_t g_num_msg_types{0};
+ return g_num_msg_types;
+}
+#define FUZZ_TARGET_MSG(msg_type) \
+ struct msg_type##_Count_Before_Main { \
+ msg_type##_Count_Before_Main() \
+ { \
+ ++GetNumMsgTypes(); \
+ } \
+ } const static g_##msg_type##_count_before_main; \
+ FUZZ_TARGET_INIT(process_message_##msg_type, initialize_process_message) \
+ { \
+ fuzz_target(buffer, #msg_type); \
+ }
+
void initialize_process_message()
{
+ Assert(GetNumMsgTypes() == getAllNetMessageTypes().size()); // If this fails, add or remove the message type below
+
static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
@@ -60,7 +79,7 @@ void fuzz_target(FuzzBufferType buffer, const std::string& LIMIT_TO_MESSAGE_TYPE
}
CNode& p2p_node = *ConsumeNodeAsUniquePtr(fuzzed_data_provider).release();
- const bool successfully_connected{true};
+ const bool successfully_connected{fuzzed_data_provider.ConsumeBool()};
p2p_node.fSuccessfullyConnected = successfully_connected;
connman.AddTestNode(p2p_node);
g_setup->m_node.peerman->InitializeNode(&p2p_node);
@@ -86,27 +105,37 @@ void fuzz_target(FuzzBufferType buffer, const std::string& LIMIT_TO_MESSAGE_TYPE
}
FUZZ_TARGET_INIT(process_message, initialize_process_message) { fuzz_target(buffer, ""); }
-FUZZ_TARGET_INIT(process_message_addr, initialize_process_message) { fuzz_target(buffer, "addr"); }
-FUZZ_TARGET_INIT(process_message_block, initialize_process_message) { fuzz_target(buffer, "block"); }
-FUZZ_TARGET_INIT(process_message_blocktxn, initialize_process_message) { fuzz_target(buffer, "blocktxn"); }
-FUZZ_TARGET_INIT(process_message_cmpctblock, initialize_process_message) { fuzz_target(buffer, "cmpctblock"); }
-FUZZ_TARGET_INIT(process_message_feefilter, initialize_process_message) { fuzz_target(buffer, "feefilter"); }
-FUZZ_TARGET_INIT(process_message_filteradd, initialize_process_message) { fuzz_target(buffer, "filteradd"); }
-FUZZ_TARGET_INIT(process_message_filterclear, initialize_process_message) { fuzz_target(buffer, "filterclear"); }
-FUZZ_TARGET_INIT(process_message_filterload, initialize_process_message) { fuzz_target(buffer, "filterload"); }
-FUZZ_TARGET_INIT(process_message_getaddr, initialize_process_message) { fuzz_target(buffer, "getaddr"); }
-FUZZ_TARGET_INIT(process_message_getblocks, initialize_process_message) { fuzz_target(buffer, "getblocks"); }
-FUZZ_TARGET_INIT(process_message_getblocktxn, initialize_process_message) { fuzz_target(buffer, "getblocktxn"); }
-FUZZ_TARGET_INIT(process_message_getdata, initialize_process_message) { fuzz_target(buffer, "getdata"); }
-FUZZ_TARGET_INIT(process_message_getheaders, initialize_process_message) { fuzz_target(buffer, "getheaders"); }
-FUZZ_TARGET_INIT(process_message_headers, initialize_process_message) { fuzz_target(buffer, "headers"); }
-FUZZ_TARGET_INIT(process_message_inv, initialize_process_message) { fuzz_target(buffer, "inv"); }
-FUZZ_TARGET_INIT(process_message_mempool, initialize_process_message) { fuzz_target(buffer, "mempool"); }
-FUZZ_TARGET_INIT(process_message_notfound, initialize_process_message) { fuzz_target(buffer, "notfound"); }
-FUZZ_TARGET_INIT(process_message_ping, initialize_process_message) { fuzz_target(buffer, "ping"); }
-FUZZ_TARGET_INIT(process_message_pong, initialize_process_message) { fuzz_target(buffer, "pong"); }
-FUZZ_TARGET_INIT(process_message_sendcmpct, initialize_process_message) { fuzz_target(buffer, "sendcmpct"); }
-FUZZ_TARGET_INIT(process_message_sendheaders, initialize_process_message) { fuzz_target(buffer, "sendheaders"); }
-FUZZ_TARGET_INIT(process_message_tx, initialize_process_message) { fuzz_target(buffer, "tx"); }
-FUZZ_TARGET_INIT(process_message_verack, initialize_process_message) { fuzz_target(buffer, "verack"); }
-FUZZ_TARGET_INIT(process_message_version, initialize_process_message) { fuzz_target(buffer, "version"); }
+FUZZ_TARGET_MSG(addr);
+FUZZ_TARGET_MSG(addrv2);
+FUZZ_TARGET_MSG(block);
+FUZZ_TARGET_MSG(blocktxn);
+FUZZ_TARGET_MSG(cfcheckpt);
+FUZZ_TARGET_MSG(cfheaders);
+FUZZ_TARGET_MSG(cfilter);
+FUZZ_TARGET_MSG(cmpctblock);
+FUZZ_TARGET_MSG(feefilter);
+FUZZ_TARGET_MSG(filteradd);
+FUZZ_TARGET_MSG(filterclear);
+FUZZ_TARGET_MSG(filterload);
+FUZZ_TARGET_MSG(getaddr);
+FUZZ_TARGET_MSG(getblocks);
+FUZZ_TARGET_MSG(getblocktxn);
+FUZZ_TARGET_MSG(getcfcheckpt);
+FUZZ_TARGET_MSG(getcfheaders);
+FUZZ_TARGET_MSG(getcfilters);
+FUZZ_TARGET_MSG(getdata);
+FUZZ_TARGET_MSG(getheaders);
+FUZZ_TARGET_MSG(headers);
+FUZZ_TARGET_MSG(inv);
+FUZZ_TARGET_MSG(mempool);
+FUZZ_TARGET_MSG(merkleblock);
+FUZZ_TARGET_MSG(notfound);
+FUZZ_TARGET_MSG(ping);
+FUZZ_TARGET_MSG(pong);
+FUZZ_TARGET_MSG(sendaddrv2);
+FUZZ_TARGET_MSG(sendcmpct);
+FUZZ_TARGET_MSG(sendheaders);
+FUZZ_TARGET_MSG(tx);
+FUZZ_TARGET_MSG(verack);
+FUZZ_TARGET_MSG(version);
+FUZZ_TARGET_MSG(wtxidrelay);
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index 810f0aac92..ef45196671 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -46,7 +46,7 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages)
peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release());
CNode& p2p_node = *peers.back();
- const bool successfully_connected{true};
+ const bool successfully_connected{fuzzed_data_provider.ConsumeBool()};
p2p_node.fSuccessfullyConnected = successfully_connected;
p2p_node.fPauseSend = false;
g_setup->m_node.peerman->InitializeNode(&p2p_node);
diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp
index 2091ad5d91..8d9a939dab 100644
--- a/src/test/fuzz/script_assets_test_minimizer.cpp
+++ b/src/test/fuzz/script_assets_test_minimizer.cpp
@@ -28,12 +28,12 @@
//
// (normal build)
// $ mkdir dump
-// $ for N in $(seq 1 10); do TEST_DUMP_DIR=dump test/functional/feature_taproot --dumptests; done
+// $ for N in $(seq 1 10); do TEST_DUMP_DIR=dump test/functional/feature_taproot.py --dumptests; done
// $ ...
//
-// (fuzz test build)
+// (libFuzzer build)
// $ mkdir dump-min
-// $ ./src/test/fuzz/script_assets_test_minimizer -merge=1 dump-min/ dump/
+// $ FUZZ=script_assets_test_minimizer ./src/test/fuzz/fuzz -merge=1 -use_value_profile=1 dump-min/ dump/
// $ (echo -en '[\n'; cat dump-min/* | head -c -2; echo -en '\n]') >script_assets_test.json
namespace {
@@ -190,7 +190,7 @@ ECCVerifyHandle handle;
} // namespace
-FUZZ_TARGET(script_assets_test_minimizer)
+FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, FuzzFrameworkEmptyInitFun, /* hidden */ true)
{
if (buffer.size() < 2 || buffer.back() != '\n' || buffer[buffer.size() - 2] != ',') return;
const std::string str((const char*)buffer.data(), buffer.size() - 2);
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 366385b619..4dc0dd5f51 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -107,6 +107,22 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(scriptHash));
+ // TxoutType::WITNESS_V1_TAPROOT
+ s.clear();
+ s << OP_1 << ToByteVector(uint256::ZERO);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_V1_TAPROOT);
+ BOOST_CHECK_EQUAL(solutions.size(), 2U);
+ BOOST_CHECK(solutions[0] == std::vector<unsigned char>{1});
+ BOOST_CHECK(solutions[1] == ToByteVector(uint256::ZERO));
+
+ // TxoutType::WITNESS_UNKNOWN
+ s.clear();
+ s << OP_16 << ToByteVector(uint256::ONE);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_UNKNOWN);
+ BOOST_CHECK_EQUAL(solutions.size(), 2U);
+ BOOST_CHECK(solutions[0] == std::vector<unsigned char>{16});
+ BOOST_CHECK(solutions[1] == ToByteVector(uint256::ONE));
+
// TxoutType::NONSTANDARD
s.clear();
s << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
diff --git a/src/test/sock_tests.cpp b/src/test/sock_tests.cpp
new file mode 100644
index 0000000000..cc0e6e7057
--- /dev/null
+++ b/src/test/sock_tests.cpp
@@ -0,0 +1,149 @@
+// Copyright (c) 2021-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <compat.h>
+#include <test/util/setup_common.h>
+#include <util/sock.h>
+#include <util/system.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <thread>
+
+using namespace std::chrono_literals;
+
+BOOST_FIXTURE_TEST_SUITE(sock_tests, BasicTestingSetup)
+
+static bool SocketIsClosed(const SOCKET& s)
+{
+ // Notice that if another thread is running and creates its own socket after `s` has been
+ // closed, it may be assigned the same file descriptor number. In this case, our test will
+ // wrongly pretend that the socket is not closed.
+ int type;
+ socklen_t len = sizeof(type);
+ return getsockopt(s, SOL_SOCKET, SO_TYPE, (sockopt_arg_type)&type, &len) == SOCKET_ERROR;
+}
+
+static SOCKET CreateSocket()
+{
+ const SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ BOOST_REQUIRE(s != static_cast<SOCKET>(SOCKET_ERROR));
+ return s;
+}
+
+BOOST_AUTO_TEST_CASE(constructor_and_destructor)
+{
+ const SOCKET s = CreateSocket();
+ Sock* sock = new Sock(s);
+ BOOST_CHECK_EQUAL(sock->Get(), s);
+ BOOST_CHECK(!SocketIsClosed(s));
+ delete sock;
+ BOOST_CHECK(SocketIsClosed(s));
+}
+
+BOOST_AUTO_TEST_CASE(move_constructor)
+{
+ const SOCKET s = CreateSocket();
+ Sock* sock1 = new Sock(s);
+ Sock* sock2 = new Sock(std::move(*sock1));
+ delete sock1;
+ BOOST_CHECK(!SocketIsClosed(s));
+ BOOST_CHECK_EQUAL(sock2->Get(), s);
+ delete sock2;
+ BOOST_CHECK(SocketIsClosed(s));
+}
+
+BOOST_AUTO_TEST_CASE(move_assignment)
+{
+ const SOCKET s = CreateSocket();
+ Sock* sock1 = new Sock(s);
+ Sock* sock2 = new Sock();
+ *sock2 = std::move(*sock1);
+ delete sock1;
+ BOOST_CHECK(!SocketIsClosed(s));
+ BOOST_CHECK_EQUAL(sock2->Get(), s);
+ delete sock2;
+ BOOST_CHECK(SocketIsClosed(s));
+}
+
+BOOST_AUTO_TEST_CASE(release)
+{
+ SOCKET s = CreateSocket();
+ Sock* sock = new Sock(s);
+ BOOST_CHECK_EQUAL(sock->Release(), s);
+ delete sock;
+ BOOST_CHECK(!SocketIsClosed(s));
+ BOOST_REQUIRE(CloseSocket(s));
+}
+
+BOOST_AUTO_TEST_CASE(reset)
+{
+ const SOCKET s = CreateSocket();
+ Sock sock(s);
+ sock.Reset();
+ BOOST_CHECK(SocketIsClosed(s));
+}
+
+#ifndef WIN32 // Windows does not have socketpair(2).
+
+static void CreateSocketPair(int s[2])
+{
+ BOOST_REQUIRE_EQUAL(socketpair(AF_UNIX, SOCK_STREAM, 0, s), 0);
+}
+
+static void SendAndRecvMessage(const Sock& sender, const Sock& receiver)
+{
+ const char* msg = "abcd";
+ constexpr size_t msg_len = 4;
+ char recv_buf[10];
+
+ BOOST_CHECK_EQUAL(sender.Send(msg, msg_len, 0), msg_len);
+ BOOST_CHECK_EQUAL(receiver.Recv(recv_buf, sizeof(recv_buf), 0), msg_len);
+ BOOST_CHECK_EQUAL(strncmp(msg, recv_buf, msg_len), 0);
+}
+
+BOOST_AUTO_TEST_CASE(send_and_receive)
+{
+ int s[2];
+ CreateSocketPair(s);
+
+ Sock* sock0 = new Sock(s[0]);
+ Sock* sock1 = new Sock(s[1]);
+
+ SendAndRecvMessage(*sock0, *sock1);
+
+ Sock* sock0moved = new Sock(std::move(*sock0));
+ Sock* sock1moved = new Sock();
+ *sock1moved = std::move(*sock1);
+
+ delete sock0;
+ delete sock1;
+
+ SendAndRecvMessage(*sock1moved, *sock0moved);
+
+ delete sock0moved;
+ delete sock1moved;
+
+ BOOST_CHECK(SocketIsClosed(s[0]));
+ BOOST_CHECK(SocketIsClosed(s[1]));
+}
+
+BOOST_AUTO_TEST_CASE(wait)
+{
+ int s[2];
+ CreateSocketPair(s);
+
+ Sock sock0(s[0]);
+ Sock sock1(s[1]);
+
+ std::thread waiter([&sock0]() { sock0.Wait(24h, Sock::RECV); });
+
+ BOOST_REQUIRE_EQUAL(sock1.Send("a", 1, 0), 1);
+
+ waiter.join();
+}
+
+#endif /* WIN32 */
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp
index 7e6246d68f..9b0d2e3135 100644
--- a/src/test/txvalidation_tests.cpp
+++ b/src/test/txvalidation_tests.cpp
@@ -30,25 +30,21 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
- TxValidationState state;
-
LOCK(cs_main);
unsigned int initialPoolSize = m_node.mempool->size();
+ const MempoolAcceptResult result = AcceptToMemoryPool(*m_node.mempool, MakeTransactionRef(coinbaseTx),
+ true /* bypass_limits */);
- BOOST_CHECK_EQUAL(
- false,
- AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(coinbaseTx),
- nullptr /* plTxnReplaced */,
- true /* bypass_limits */));
+ BOOST_CHECK(result.m_result_type == MempoolAcceptResult::ResultType::INVALID);
// Check that the transaction hasn't been added to mempool.
BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
// Check that the validation state reflects the unsuccessful attempt.
- BOOST_CHECK(state.IsInvalid());
- BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
- BOOST_CHECK(state.GetResult() == TxValidationResult::TX_CONSENSUS);
+ BOOST_CHECK(result.m_state.IsInvalid());
+ BOOST_CHECK_EQUAL(result.m_state.GetRejectReason(), "coinbase");
+ BOOST_CHECK(result.m_state.GetResult() == TxValidationResult::TX_CONSENSUS);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index bed2ba3608..af0090cc10 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -28,9 +28,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
const auto ToMemPool = [this](const CMutableTransaction& tx) {
LOCK(cs_main);
- TxValidationState state;
- return AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(tx),
- nullptr /* plTxnReplaced */, true /* bypass_limits */);
+ const MempoolAcceptResult result = AcceptToMemoryPool(*m_node.mempool, MakeTransactionRef(tx),
+ true /* bypass_limits */);
+ return result.m_result_type == MempoolAcceptResult::ResultType::VALID;
};
// Create a double-spend of mature coinbase txn:
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 4133f2623b..dccbf00d6f 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -13,6 +13,7 @@
#include <test/util/setup_common.h>
#include <test/util/str.h>
#include <uint256.h>
+#include <util/getuniquepath.h>
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
#include <util/moneystr.h>
#include <util/spanparsing.h>
@@ -1816,7 +1817,7 @@ BOOST_AUTO_TEST_CASE(test_DirIsWritable)
BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
// Should not be able to write to a non-existent dir.
- tmpdirname = tmpdirname / fs::unique_path();
+ tmpdirname = GetUniquePath(tmpdirname);
BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), false);
fs::create_directory(tmpdirname);
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index ec45d9a434..6c18a9e1bb 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -283,15 +283,9 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
// Add the txs to the tx pool
{
LOCK(cs_main);
- TxValidationState state;
- std::list<CTransactionRef> plTxnReplaced;
for (const auto& tx : txs) {
- BOOST_REQUIRE(AcceptToMemoryPool(
- *m_node.mempool,
- state,
- tx,
- &plTxnReplaced,
- /* bypass_limits */ false));
+ const MempoolAcceptResult result = AcceptToMemoryPool(*m_node.mempool, tx, false /* bypass_limits */);
+ BOOST_REQUIRE(result.m_result_type == MempoolAcceptResult::ResultType::VALID);
}
}
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 908ad35e1b..605c77fc3a 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -14,6 +14,7 @@
#include <netbase.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/time.h>
#include <deque>
#include <functional>
diff --git a/src/util/getuniquepath.cpp b/src/util/getuniquepath.cpp
new file mode 100644
index 0000000000..9839d2f624
--- /dev/null
+++ b/src/util/getuniquepath.cpp
@@ -0,0 +1,10 @@
+#include <random.h>
+#include <fs.h>
+#include <util/strencodings.h>
+
+fs::path GetUniquePath(const fs::path& base)
+{
+ FastRandomContext rnd;
+ fs::path tmpFile = base / HexStr(rnd.randbytes(8));
+ return tmpFile;
+} \ No newline at end of file
diff --git a/src/util/getuniquepath.h b/src/util/getuniquepath.h
new file mode 100644
index 0000000000..e0c6147876
--- /dev/null
+++ b/src/util/getuniquepath.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_GETUNIQUEPATH_H
+#define BITCOIN_UTIL_GETUNIQUEPATH_H
+
+#include <fs.h>
+
+/**
+ * Helper function for getting a unique path
+ *
+ * @param[in] base Base path
+ * @returns base joined with a random 8-character long string.
+ * @post Returned path is unique with high probability.
+ */
+fs::path GetUniquePath(const fs::path& base);
+
+#endif // BITCOIN_UTIL_GETUNIQUEPATH_H \ No newline at end of file
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
new file mode 100644
index 0000000000..4c65b5b680
--- /dev/null
+++ b/src/util/sock.cpp
@@ -0,0 +1,149 @@
+// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <compat.h>
+#include <logging.h>
+#include <tinyformat.h>
+#include <util/sock.h>
+#include <util/system.h>
+#include <util/time.h>
+
+#include <codecvt>
+#include <cwchar>
+#include <locale>
+#include <string>
+
+#ifdef USE_POLL
+#include <poll.h>
+#endif
+
+Sock::Sock() : m_socket(INVALID_SOCKET) {}
+
+Sock::Sock(SOCKET s) : m_socket(s) {}
+
+Sock::Sock(Sock&& other)
+{
+ m_socket = other.m_socket;
+ other.m_socket = INVALID_SOCKET;
+}
+
+Sock::~Sock() { Reset(); }
+
+Sock& Sock::operator=(Sock&& other)
+{
+ Reset();
+ m_socket = other.m_socket;
+ other.m_socket = INVALID_SOCKET;
+ return *this;
+}
+
+SOCKET Sock::Get() const { return m_socket; }
+
+SOCKET Sock::Release()
+{
+ const SOCKET s = m_socket;
+ m_socket = INVALID_SOCKET;
+ return s;
+}
+
+void Sock::Reset() { CloseSocket(m_socket); }
+
+ssize_t Sock::Send(const void* data, size_t len, int flags) const
+{
+ return send(m_socket, static_cast<const char*>(data), len, flags);
+}
+
+ssize_t Sock::Recv(void* buf, size_t len, int flags) const
+{
+ return recv(m_socket, static_cast<char*>(buf), len, flags);
+}
+
+bool Sock::Wait(std::chrono::milliseconds timeout, Event requested) const
+{
+#ifdef USE_POLL
+ pollfd fd;
+ fd.fd = m_socket;
+ fd.events = 0;
+ if (requested & RECV) {
+ fd.events |= POLLIN;
+ }
+ if (requested & SEND) {
+ fd.events |= POLLOUT;
+ }
+
+ return poll(&fd, 1, count_milliseconds(timeout)) != SOCKET_ERROR;
+#else
+ if (!IsSelectableSocket(m_socket)) {
+ return false;
+ }
+
+ fd_set fdset_recv;
+ fd_set fdset_send;
+ FD_ZERO(&fdset_recv);
+ FD_ZERO(&fdset_send);
+
+ if (requested & RECV) {
+ FD_SET(m_socket, &fdset_recv);
+ }
+
+ if (requested & SEND) {
+ FD_SET(m_socket, &fdset_send);
+ }
+
+ timeval timeout_struct = MillisToTimeval(timeout);
+
+ return select(m_socket + 1, &fdset_recv, &fdset_send, nullptr, &timeout_struct) != SOCKET_ERROR;
+#endif /* USE_POLL */
+}
+
+#ifdef WIN32
+std::string NetworkErrorString(int err)
+{
+ wchar_t buf[256];
+ buf[0] = 0;
+ if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buf, ARRAYSIZE(buf), nullptr))
+ {
+ return strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);
+ }
+ else
+ {
+ return strprintf("Unknown error (%d)", err);
+ }
+}
+#else
+std::string NetworkErrorString(int err)
+{
+ char buf[256];
+ buf[0] = 0;
+ /* Too bad there are two incompatible implementations of the
+ * thread-safe strerror. */
+ const char *s;
+#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
+ s = strerror_r(err, buf, sizeof(buf));
+#else /* POSIX variant always returns message in buffer */
+ s = buf;
+ if (strerror_r(err, buf, sizeof(buf)))
+ buf[0] = 0;
+#endif
+ return strprintf("%s (%d)", s, err);
+}
+#endif
+
+bool CloseSocket(SOCKET& hSocket)
+{
+ if (hSocket == INVALID_SOCKET)
+ return false;
+#ifdef WIN32
+ int ret = closesocket(hSocket);
+#else
+ int ret = close(hSocket);
+#endif
+ if (ret) {
+ LogPrintf("Socket close failed: %d. Error: %s\n", hSocket, NetworkErrorString(WSAGetLastError()));
+ }
+ hSocket = INVALID_SOCKET;
+ return ret != SOCKET_ERROR;
+}
diff --git a/src/util/sock.h b/src/util/sock.h
new file mode 100644
index 0000000000..26fe60f18f
--- /dev/null
+++ b/src/util/sock.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_SOCK_H
+#define BITCOIN_UTIL_SOCK_H
+
+#include <compat.h>
+
+#include <chrono>
+#include <string>
+
+/**
+ * RAII helper class that manages a socket. Mimics `std::unique_ptr`, but instead of a pointer it
+ * contains a socket and closes it automatically when it goes out of scope.
+ */
+class Sock
+{
+public:
+ /**
+ * Default constructor, creates an empty object that does nothing when destroyed.
+ */
+ Sock();
+
+ /**
+ * Take ownership of an existent socket.
+ */
+ explicit Sock(SOCKET s);
+
+ /**
+ * Copy constructor, disabled because closing the same socket twice is undesirable.
+ */
+ Sock(const Sock&) = delete;
+
+ /**
+ * Move constructor, grab the socket from another object and close ours (if set).
+ */
+ Sock(Sock&& other);
+
+ /**
+ * Destructor, close the socket or do nothing if empty.
+ */
+ virtual ~Sock();
+
+ /**
+ * Copy assignment operator, disabled because closing the same socket twice is undesirable.
+ */
+ Sock& operator=(const Sock&) = delete;
+
+ /**
+ * Move assignment operator, grab the socket from another object and close ours (if set).
+ */
+ virtual Sock& operator=(Sock&& other);
+
+ /**
+ * Get the value of the contained socket.
+ * @return socket or INVALID_SOCKET if empty
+ */
+ virtual SOCKET Get() const;
+
+ /**
+ * Get the value of the contained socket and drop ownership. It will not be closed by the
+ * destructor after this call.
+ * @return socket or INVALID_SOCKET if empty
+ */
+ virtual SOCKET Release();
+
+ /**
+ * Close if non-empty.
+ */
+ virtual void Reset();
+
+ /**
+ * send(2) wrapper. Equivalent to `send(this->Get(), data, len, flags);`. Code that uses this
+ * wrapper can be unit-tested if this method is overridden by a mock Sock implementation.
+ */
+ virtual ssize_t Send(const void* data, size_t len, int flags) const;
+
+ /**
+ * recv(2) wrapper. Equivalent to `recv(this->Get(), buf, len, flags);`. Code that uses this
+ * wrapper can be unit-tested if this method is overridden by a mock Sock implementation.
+ */
+ virtual ssize_t Recv(void* buf, size_t len, int flags) const;
+
+ using Event = uint8_t;
+
+ /**
+ * If passed to `Wait()`, then it will wait for readiness to read from the socket.
+ */
+ static constexpr Event RECV = 0b01;
+
+ /**
+ * If passed to `Wait()`, then it will wait for readiness to send to the socket.
+ */
+ static constexpr Event SEND = 0b10;
+
+ /**
+ * Wait for readiness for input (recv) or output (send).
+ * @param[in] timeout Wait this much for at least one of the requested events to occur.
+ * @param[in] requested Wait for those events, bitwise-or of `RECV` and `SEND`.
+ * @return true on success and false otherwise
+ */
+ virtual bool Wait(std::chrono::milliseconds timeout, Event requested) const;
+
+private:
+ /**
+ * Contained socket. `INVALID_SOCKET` designates the object is empty.
+ */
+ SOCKET m_socket;
+};
+
+/** Return readable error string for a network error code */
+std::string NetworkErrorString(int err);
+
+/** Close socket and set hSocket to INVALID_SOCKET */
+bool CloseSocket(SOCKET& hSocket);
+
+#endif // BITCOIN_UTIL_SOCK_H
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 9fe9d67411..9a2e719bbc 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -12,6 +12,7 @@
#include <chainparamsbase.h>
#include <sync.h>
#include <util/check.h>
+#include <util/getuniquepath.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/translation.h>
@@ -124,7 +125,7 @@ void ReleaseDirectoryLocks()
bool DirIsWritable(const fs::path& directory)
{
- fs::path tmpFile = directory / fs::unique_path();
+ fs::path tmpFile = GetUniquePath(directory);
FILE* file = fsbridge::fopen(tmpFile, "a");
if (!file) return false;
diff --git a/src/util/time.cpp b/src/util/time.cpp
index e96972fe12..295806c54a 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -7,8 +7,11 @@
#include <config/bitcoin-config.h>
#endif
+#include <compat.h>
#include <util/time.h>
+#include <util/check.h>
+
#include <atomic>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <ctime>
@@ -18,7 +21,7 @@
void UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread::sleep_for(n); }
-static std::atomic<int64_t> nMockTime(0); //!< For unit testing
+static std::atomic<int64_t> nMockTime(0); //!< For testing
int64_t GetTime()
{
@@ -46,6 +49,7 @@ template std::chrono::microseconds GetTime();
void SetMockTime(int64_t nMockTimeIn)
{
+ Assert(nMockTimeIn >= 0);
nMockTime.store(nMockTimeIn, std::memory_order_relaxed);
}
@@ -114,3 +118,16 @@ int64_t ParseISO8601DateTime(const std::string& str)
return 0;
return (ptime - epoch).total_seconds();
}
+
+struct timeval MillisToTimeval(int64_t nTimeout)
+{
+ struct timeval timeout;
+ timeout.tv_sec = nTimeout / 1000;
+ timeout.tv_usec = (nTimeout % 1000) * 1000;
+ return timeout;
+}
+
+struct timeval MillisToTimeval(std::chrono::milliseconds ms)
+{
+ return MillisToTimeval(count_milliseconds(ms));
+}
diff --git a/src/util/time.h b/src/util/time.h
index c69f604dc6..03b75b5be5 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -6,6 +6,8 @@
#ifndef BITCOIN_UTIL_TIME_H
#define BITCOIN_UTIL_TIME_H
+#include <compat.h>
+
#include <chrono>
#include <stdint.h>
#include <string>
@@ -25,6 +27,7 @@ void UninterruptibleSleep(const std::chrono::microseconds& n);
* interface that doesn't support std::chrono (e.g. RPC, debug log, or the GUI)
*/
inline int64_t count_seconds(std::chrono::seconds t) { return t.count(); }
+inline int64_t count_milliseconds(std::chrono::milliseconds t) { return t.count(); }
inline int64_t count_microseconds(std::chrono::microseconds t) { return t.count(); }
/**
@@ -57,4 +60,14 @@ std::string FormatISO8601DateTime(int64_t nTime);
std::string FormatISO8601Date(int64_t nTime);
int64_t ParseISO8601DateTime(const std::string& str);
+/**
+ * Convert milliseconds to a struct timeval for e.g. select.
+ */
+struct timeval MillisToTimeval(int64_t nTimeout);
+
+/**
+ * Convert milliseconds to a struct timeval for e.g. select.
+ */
+struct timeval MillisToTimeval(std::chrono::milliseconds ms);
+
#endif // BITCOIN_UTIL_TIME_H
diff --git a/src/validation.cpp b/src/validation.cpp
index 8f7d36bfd3..778d75ce18 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -380,10 +380,8 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact
auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin();
while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
// ignore validation errors in resurrected transactions
- TxValidationState stateDummy;
if (!fAddToMempool || (*it)->IsCoinBase() ||
- !AcceptToMemoryPool(mempool, stateDummy, *it,
- nullptr /* plTxnReplaced */, true /* bypass_limits */)) {
+ AcceptToMemoryPool(mempool, *it, true /* bypass_limits */).m_result_type != MempoolAcceptResult::ResultType::VALID) {
// If the transaction doesn't make it in to the mempool, remove any
// transactions that depend on it (which would now be orphans).
mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
@@ -463,9 +461,7 @@ public:
// around easier.
struct ATMPArgs {
const CChainParams& m_chainparams;
- TxValidationState &m_state;
const int64_t m_accept_time;
- std::list<CTransactionRef>* m_replaced_transactions;
const bool m_bypass_limits;
/*
* Return any outpoints which were not previously present in the coins
@@ -476,11 +472,10 @@ public:
*/
std::vector<COutPoint>& m_coins_to_uncache;
const bool m_test_accept;
- CAmount* m_fee_out;
};
// Single transaction acceptance
- bool AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ MempoolAcceptResult AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
private:
// All the intermediate state that gets passed between the various levels
@@ -491,14 +486,17 @@ private:
CTxMemPool::setEntries m_all_conflicting;
CTxMemPool::setEntries m_ancestors;
std::unique_ptr<CTxMemPoolEntry> m_entry;
+ std::list<CTransactionRef> m_replaced_transactions;
bool m_replacement_transaction;
+ CAmount m_base_fees;
CAmount m_modified_fees;
CAmount m_conflicting_fees;
size_t m_conflicting_size;
const CTransactionRef& m_ptx;
const uint256& m_hash;
+ TxValidationState m_state;
};
// Run the policy checks on a given transaction, excluding any script checks.
@@ -509,18 +507,18 @@ private:
// Run the script checks using our policy flags. As this can be slow, we should
// only invoke this on transactions that have otherwise passed policy checks.
- bool PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
+ bool PolicyScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Re-run the script checks, using consensus flags, and try to cache the
// result in the scriptcache. This should be done after
// PolicyScriptChecks(). This requires that all inputs either be in our
// utxo set or in the mempool.
- bool ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
+ bool ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Try to add the transaction to the mempool, removing any conflicts first.
// Returns true if the transaction is in the mempool after any size
// limiting is performed, false otherwise.
- bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
+ bool Finalize(const ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Compare a package's feerate against minimum allowed.
bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs)
@@ -558,12 +556,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
const uint256& hash = ws.m_hash;
// Copy/alias what we need out of args
- TxValidationState &state = args.m_state;
const int64_t nAcceptTime = args.m_accept_time;
const bool bypass_limits = args.m_bypass_limits;
std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache;
// Alias what we need out of ws
+ TxValidationState& state = ws.m_state;
std::set<uint256>& setConflicts = ws.m_conflicts;
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting;
CTxMemPool::setEntries& setAncestors = ws.m_ancestors;
@@ -683,16 +681,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
if (!CheckSequenceLocks(m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
- CAmount nFees = 0;
- if (!Consensus::CheckTxInputs(tx, state, m_view, g_chainman.m_blockman.GetSpendHeight(m_view), nFees)) {
+ if (!Consensus::CheckTxInputs(tx, state, m_view, g_chainman.m_blockman.GetSpendHeight(m_view), ws.m_base_fees)) {
return false; // state filled in by CheckTxInputs
}
- // If fee_out is passed, return the fee to the caller
- if (args.m_fee_out) {
- *args.m_fee_out = nFees;
- }
-
// Check for non-standard pay-to-script-hash in inputs
const auto& params = args.m_chainparams.GetConsensus();
auto taproot_state = VersionBitsState(::ChainActive().Tip(), params, Consensus::DEPLOYMENT_TAPROOT, versionbitscache);
@@ -707,7 +699,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
// nModifiedFees includes any fee deltas from PrioritiseTransaction
- nModifiedFees = nFees;
+ nModifiedFees = ws.m_base_fees;
m_pool.ApplyDelta(hash, nModifiedFees);
// Keep track of transactions that spend a coinbase, which we re-scan
@@ -721,7 +713,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
}
- entry.reset(new CTxMemPoolEntry(ptx, nFees, nAcceptTime, ::ChainActive().Height(),
+ entry.reset(new CTxMemPoolEntry(ptx, ws.m_base_fees, nAcceptTime, ::ChainActive().Height(),
fSpendsCoinbase, nSigOpsCost, lp));
unsigned int nSize = entry->GetTxSize();
@@ -925,11 +917,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return true;
}
-bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata)
+bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata)
{
const CTransaction& tx = *ws.m_ptx;
-
- TxValidationState &state = args.m_state;
+ TxValidationState& state = ws.m_state;
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
@@ -952,12 +943,11 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, Prec
return true;
}
-bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata)
+bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata)
{
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
-
- TxValidationState &state = args.m_state;
+ TxValidationState& state = ws.m_state;
const CChainParams& chainparams = args.m_chainparams;
// Check again against the current block tip's script verification
@@ -984,11 +974,11 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, P
return true;
}
-bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
+bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
{
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
- TxValidationState &state = args.m_state;
+ TxValidationState& state = ws.m_state;
const bool bypass_limits = args.m_bypass_limits;
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting;
@@ -1007,8 +997,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
hash.ToString(),
FormatMoney(nModifiedFees - nConflictingFees),
(int)entry->GetTxSize() - (int)nConflictingSize);
- if (args.m_replaced_transactions)
- args.m_replaced_transactions->push_back(it->GetSharedTx());
+ ws.m_replaced_transactions.push_back(it->GetSharedTx());
}
m_pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED);
@@ -1031,14 +1020,14 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
return true;
}
-bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args)
+MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args)
{
AssertLockHeld(cs_main);
LOCK(m_pool.cs); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool())
- Workspace workspace(ptx);
+ Workspace ws(ptx);
- if (!PreChecks(args, workspace)) return false;
+ if (!PreChecks(args, ws)) return MempoolAcceptResult(ws.m_state);
// Only compute the precomputed transaction data if we need to verify
// scripts (ie, other policy checks pass). We perform the inexpensive
@@ -1046,31 +1035,35 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
// checks pass, to mitigate CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata;
- if (!PolicyScriptChecks(args, workspace, txdata)) return false;
+ if (!PolicyScriptChecks(args, ws, txdata)) return MempoolAcceptResult(ws.m_state);
- if (!ConsensusScriptChecks(args, workspace, txdata)) return false;
+ if (!ConsensusScriptChecks(args, ws, txdata)) return MempoolAcceptResult(ws.m_state);
// Tx was accepted, but not added
- if (args.m_test_accept) return true;
+ if (args.m_test_accept) {
+ return MempoolAcceptResult(std::move(ws.m_replaced_transactions), ws.m_base_fees);
+ }
- if (!Finalize(args, workspace)) return false;
+ if (!Finalize(args, ws)) return MempoolAcceptResult(ws.m_state);
GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence());
- return true;
+ return MempoolAcceptResult(std::move(ws.m_replaced_transactions), ws.m_base_fees);
}
} // anon namespace
/** (try to) add transaction to memory pool with a specified acceptance time **/
-static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
- int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, bool test_accept, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool,
+ const CTransactionRef &tx, int64_t nAcceptTime,
+ bool bypass_limits, bool test_accept)
+ EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
std::vector<COutPoint> coins_to_uncache;
- MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, coins_to_uncache, test_accept, fee_out };
- bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args);
- if (!res) {
+ MemPoolAccept::ATMPArgs args { chainparams, nAcceptTime, bypass_limits, coins_to_uncache, test_accept };
+
+ const MempoolAcceptResult result = MemPoolAccept(pool).AcceptSingleTransaction(tx, args);
+ if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
// Remove coins that were not present in the coins cache before calling ATMPW;
// this is to prevent memory DoS in case we receive a large number of
// invalid transactions that attempt to overrun the in-memory coins cache
@@ -1082,15 +1075,12 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
BlockValidationState state_dummy;
::ChainstateActive().FlushStateToDisk(chainparams, state_dummy, FlushStateMode::PERIODIC);
- return res;
+ return result;
}
-bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
- std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, bool test_accept, CAmount* fee_out)
+MempoolAcceptResult AcceptToMemoryPool(CTxMemPool& pool, const CTransactionRef &tx, bool bypass_limits, bool test_accept)
{
- const CChainParams& chainparams = Params();
- return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, test_accept, fee_out);
+ return AcceptToMemoryPoolWithTime(Params(), pool, tx, GetTime(), bypass_limits, test_accept);
}
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
@@ -3219,7 +3209,7 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n
if ((int)nFile != nLastBlockFile) {
if (!fKnown) {
- LogPrintf("Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());
+ LogPrint(BCLog::VALIDATION, "Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());
}
FlushBlockFile(!fKnown, finalize_undo);
nLastBlockFile = nFile;
@@ -5029,13 +5019,10 @@ bool LoadMempool(CTxMemPool& pool)
if (amountdelta) {
pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
}
- TxValidationState state;
if (nTime > nNow - nExpiryTimeout) {
LOCK(cs_main);
- AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nTime,
- nullptr /* plTxnReplaced */, false /* bypass_limits */,
- false /* test_accept */);
- if (state.IsValid()) {
+ if (AcceptToMemoryPoolWithTime(chainparams, pool, tx, nTime, false /* bypass_limits */,
+ false /* test_accept */).m_result_type == MempoolAcceptResult::ResultType::VALID) {
++count;
} else {
// mempool may contain the transaction already, e.g. from
diff --git a/src/validation.h b/src/validation.h
index e85c7bbf1a..238d6009b4 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -12,6 +12,7 @@
#include <amount.h>
#include <coins.h>
+#include <consensus/validation.h>
#include <crypto/common.h> // for ReadLE64
#include <fs.h>
#include <optional.h>
@@ -23,6 +24,7 @@
#include <txdb.h>
#include <versionbits.h>
#include <serialize.h>
+#include <util/check.h>
#include <util/hasher.h>
#include <atomic>
@@ -46,7 +48,6 @@ class CConnman;
class CScriptCheck;
class CTxMemPool;
class ChainstateManager;
-class TxValidationState;
struct ChainTxData;
struct DisconnectedBlockTransactions;
@@ -181,12 +182,46 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
/** Prune block files up to a given height */
void PruneBlockFilesManual(int nManualPruneHeight);
-/** (try to) add transaction to memory pool
- * plTxnReplaced will be appended to with all transactions replaced from mempool
- * @param[out] fee_out optional argument to return tx fee to the caller **/
-bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
- std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, bool test_accept=false, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+/**
+* Validation result for a single transaction mempool acceptance.
+*/
+struct MempoolAcceptResult {
+ /** Used to indicate the results of mempool validation,
+ * including the possibility of unfinished validation.
+ */
+ enum class ResultType {
+ VALID, //!> Fully validated, valid.
+ INVALID, //!> Invalid.
+ };
+ ResultType m_result_type;
+ TxValidationState m_state;
+
+ // The following fields are only present when m_result_type = ResultType::VALID
+ /** Mempool transactions replaced by the tx per BIP 125 rules. */
+ std::optional<std::list<CTransactionRef>> m_replaced_transactions;
+ /** Raw base fees. */
+ std::optional<CAmount> m_base_fees;
+
+ /** Constructor for failure case */
+ explicit MempoolAcceptResult(TxValidationState state)
+ : m_result_type(ResultType::INVALID),
+ m_state(state), m_replaced_transactions(nullopt), m_base_fees(nullopt) {
+ Assume(!state.IsValid()); // Can be invalid or error
+ }
+
+ /** Constructor for success case */
+ explicit MempoolAcceptResult(std::list<CTransactionRef>&& replaced_txns, CAmount fees)
+ : m_result_type(ResultType::VALID), m_state(TxValidationState{}),
+ m_replaced_transactions(std::move(replaced_txns)), m_base_fees(fees) {}
+};
+
+/**
+ * (Try to) add a transaction to the memory pool.
+ * @param[in] bypass_limits When true, don't enforce mempool fee limits.
+ * @param[in] test_accept When true, run validation checks but don't submit to mempool.
+ */
+MempoolAcceptResult AcceptToMemoryPool(CTxMemPool& pool, const CTransactionRef& tx,
+ bool bypass_limits, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 8505ddc309..99803a91d2 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -934,9 +934,9 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
case TxoutType::NONSTANDARD:
case TxoutType::WITNESS_UNKNOWN:
case TxoutType::WITNESS_V1_TAPROOT:
- default:
return "unrecognized script";
- }
+ } // no default case, so the compiler can warn about missing cases
+ CHECK_NONFATAL(false);
}
static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys)
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 15972fe7bb..55110f30d9 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -94,8 +94,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
TxoutType whichType = Solver(scriptPubKey, vSolutions);
CKeyID keyID;
- switch (whichType)
- {
+ switch (whichType) {
case TxoutType::NONSTANDARD:
case TxoutType::NULL_DATA:
case TxoutType::WITNESS_UNKNOWN:
@@ -194,7 +193,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
}
break;
}
- }
+ } // no default case, so the compiler can warn about missing cases
if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
ret = std::max(ret, IsMineResult::WATCH_ONLY);
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index 27179839b7..b2eb8e4bca 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -30,8 +30,8 @@ BOOST_AUTO_TEST_CASE(getwalletenv_file)
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename);
- BOOST_CHECK(filename == test_name);
- BOOST_CHECK(env->Directory() == datadir);
+ BOOST_CHECK_EQUAL(filename, test_name);
+ BOOST_CHECK_EQUAL(env->Directory(), datadir);
}
BOOST_AUTO_TEST_CASE(getwalletenv_directory)
@@ -41,8 +41,8 @@ BOOST_AUTO_TEST_CASE(getwalletenv_directory)
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(datadir, filename);
- BOOST_CHECK(filename == expected_name);
- BOOST_CHECK(env->Directory() == datadir);
+ BOOST_CHECK_EQUAL(filename, expected_name);
+ BOOST_CHECK_EQUAL(env->Directory(), datadir);
}
BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple)
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index e70b56c529..45e1b8c4b8 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default)
BOOST_CHECK(result == true);
fs::path walletdir = gArgs.GetArg("-walletdir", "");
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
- BOOST_CHECK(walletdir == expected_path);
+ BOOST_CHECK_EQUAL(walletdir, expected_path);
}
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom)
@@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom)
BOOST_CHECK(result == true);
fs::path walletdir = gArgs.GetArg("-walletdir", "");
fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]);
- BOOST_CHECK(walletdir == expected_path);
+ BOOST_CHECK_EQUAL(walletdir, expected_path);
}
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_does_not_exist)
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing)
BOOST_CHECK(result == true);
fs::path walletdir = gArgs.GetArg("-walletdir", "");
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
- BOOST_CHECK(walletdir == expected_path);
+ BOOST_CHECK_EQUAL(walletdir, expected_path);
}
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2)
@@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2)
BOOST_CHECK(result == true);
fs::path walletdir = gArgs.GetArg("-walletdir", "");
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
- BOOST_CHECK(walletdir == expected_path);
+ BOOST_CHECK_EQUAL(walletdir, expected_path);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index 2445b6d977..573760a8cb 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -5,6 +5,7 @@
"""Test various command line arguments and configuration file parameters."""
import os
+import time
from test_framework.test_framework import BitcoinTestFramework
from test_framework import util
@@ -147,11 +148,68 @@ class ConfArgsTest(BitcoinTestFramework):
self.start_node(0, extra_args=['-nonetworkactive=1'])
self.stop_node(0)
+ def test_seed_peers(self):
+ self.log.info('Test seed peers')
+ default_data_dir = self.nodes[0].datadir
+
+ # No peers.dat exists and -dnsseed=1
+ # We expect the node will use DNS Seeds, but Regtest mode has 0 DNS seeds
+ # So after 60 seconds, the node should fallback to fixed seeds (this is a slow test)
+ assert not os.path.exists(os.path.join(default_data_dir, "peers.dat"))
+ start = int(time.time())
+ with self.nodes[0].assert_debug_log(expected_msgs=[
+ "Loaded 0 addresses from peers.dat",
+ "0 addresses found from DNS seeds"]):
+ self.start_node(0, extra_args=['-dnsseed=1 -mocktime={}'.format(start)])
+ with self.nodes[0].assert_debug_log(expected_msgs=[
+ "Adding fixed seeds as 60 seconds have passed and addrman is empty"]):
+ self.nodes[0].setmocktime(start + 65)
+ self.stop_node(0)
+
+ # No peers.dat exists and -dnsseed=0
+ # We expect the node will fallback immediately to fixed seeds
+ assert not os.path.exists(os.path.join(default_data_dir, "peers.dat"))
+ start = time.time()
+ with self.nodes[0].assert_debug_log(expected_msgs=[
+ "Loaded 0 addresses from peers.dat",
+ "DNS seeding disabled",
+ "Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n"]):
+ self.start_node(0, extra_args=['-dnsseed=0'])
+ assert time.time() - start < 60
+ self.stop_node(0)
+
+ # No peers.dat exists and dns seeds are disabled.
+ # We expect the node will not add fixed seeds when explicitly disabled.
+ assert not os.path.exists(os.path.join(default_data_dir, "peers.dat"))
+ start = time.time()
+ with self.nodes[0].assert_debug_log(expected_msgs=[
+ "Loaded 0 addresses from peers.dat",
+ "DNS seeding disabled",
+ "Fixed seeds are disabled"]):
+ self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=0'])
+ assert time.time() - start < 60
+ self.stop_node(0)
+
+ # No peers.dat exists and -dnsseed=0, but a -addnode is provided
+ # We expect the node will allow 60 seconds prior to using fixed seeds
+ assert not os.path.exists(os.path.join(default_data_dir, "peers.dat"))
+ start = int(time.time())
+ with self.nodes[0].assert_debug_log(expected_msgs=[
+ "Loaded 0 addresses from peers.dat",
+ "DNS seeding disabled"]):
+ self.start_node(0, extra_args=['-dnsseed=0', '-addnode=fakenodeaddr -mocktime={}'.format(start)])
+ with self.nodes[0].assert_debug_log(expected_msgs=[
+ "Adding fixed seeds as 60 seconds have passed and addrman is empty"]):
+ self.nodes[0].setmocktime(start + 65)
+ self.stop_node(0)
+
+
def run_test(self):
self.stop_node(0)
self.test_log_buffer()
self.test_args_log()
+ self.test_seed_peers()
self.test_networkactive()
self.test_config_file_parser()
diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py
new file mode 100755
index 0000000000..6e6046d84d
--- /dev/null
+++ b/test/functional/feature_utxo_set_hash.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test UTXO set hash value calculation in gettxoutsetinfo."""
+
+import struct
+
+from test_framework.blocktools import create_transaction
+from test_framework.messages import (
+ CBlock,
+ COutPoint,
+ FromHex,
+)
+from test_framework.muhash import MuHash3072
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class UTXOSetHashTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def test_deterministic_hash_results(self):
+ self.log.info("Test deterministic UTXO set hash results")
+
+ # These depend on the setup_clean_chain option, the chain loaded from the cache
+ assert_equal(self.nodes[0].gettxoutsetinfo()['hash_serialized_2'], "b32ec1dda5a53cd025b95387aad344a801825fe46a60ff952ce26528f01d3be8")
+ assert_equal(self.nodes[0].gettxoutsetinfo("muhash")['muhash'], "dd5ad2a105c2d29495f577245c357409002329b9f4d6182c0af3dc2f462555c8")
+
+ def test_muhash_implementation(self):
+ self.log.info("Test MuHash implementation consistency")
+
+ node = self.nodes[0]
+
+ # Generate 100 blocks and remove the first since we plan to spend its
+ # coinbase
+ block_hashes = node.generate(100)
+ blocks = list(map(lambda block: FromHex(CBlock(), node.getblock(block, False)), block_hashes))
+ spending = blocks.pop(0)
+
+ # Create a spending transaction and mine a block which includes it
+ tx = create_transaction(node, spending.vtx[0].rehash(), node.getnewaddress(), amount=49)
+ txid = node.sendrawtransaction(hexstring=tx.serialize_with_witness().hex(), maxfeerate=0)
+
+ tx_block = node.generateblock(output=node.getnewaddress(), transactions=[txid])
+ blocks.append(FromHex(CBlock(), node.getblock(tx_block['hash'], False)))
+
+ # Serialize the outputs that should be in the UTXO set and add them to
+ # a MuHash object
+ muhash = MuHash3072()
+
+ for height, block in enumerate(blocks):
+ # The Genesis block coinbase is not part of the UTXO set and we
+ # spent the first mined block
+ height += 2
+
+ for tx in block.vtx:
+ for n, tx_out in enumerate(tx.vout):
+ coinbase = 1 if not tx.vin[0].prevout.hash else 0
+
+ # Skip witness commitment
+ if (coinbase and n > 0):
+ continue
+
+ data = COutPoint(int(tx.rehash(), 16), n).serialize()
+ data += struct.pack("<i", height * 2 + coinbase)
+ data += tx_out.serialize()
+
+ muhash.insert(data)
+
+ finalized = muhash.digest()
+ node_muhash = node.gettxoutsetinfo("muhash")['muhash']
+
+ assert_equal(finalized[::-1].hex(), node_muhash)
+
+ def run_test(self):
+ self.test_deterministic_hash_results()
+ self.test_muhash_implementation()
+
+
+if __name__ == '__main__':
+ UTXOSetHashTest().main()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 99be6b7b8e..84ca1b99c2 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -268,6 +268,18 @@ class BlockchainTest(BitcoinTestFramework):
res5 = node.gettxoutsetinfo(hash_type='none')
assert 'hash_serialized_2' not in res5
+ # hash_type muhash should return a different UTXO set hash.
+ res6 = node.gettxoutsetinfo(hash_type='muhash')
+ assert 'muhash' in res6
+ assert(res['hash_serialized_2'] != res6['muhash'])
+
+ # muhash should not be included in gettxoutset unless requested.
+ for r in [res, res2, res3, res4, res5]:
+ assert 'muhash' not in r
+
+ # Unknown hash_type raises an error
+ assert_raises_rpc_error(-8, "foohash is not a valid hash_type", node.gettxoutsetinfo, "foohash")
+
def _test_getblockheader(self):
node = self.nodes[0]
diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py
index e86f91b1d0..6177970872 100755
--- a/test/functional/rpc_uptime.py
+++ b/test/functional/rpc_uptime.py
@@ -10,6 +10,7 @@ Test corresponds to code in rpc/server.cpp.
import time
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_raises_rpc_error
class UptimeTest(BitcoinTestFramework):
@@ -18,8 +19,12 @@ class UptimeTest(BitcoinTestFramework):
self.setup_clean_chain = True
def run_test(self):
+ self._test_negative_time()
self._test_uptime()
+ def _test_negative_time(self):
+ assert_raises_rpc_error(-8, "Mocktime can not be negative: -1.", self.nodes[0].setmocktime, -1)
+
def _test_uptime(self):
wait_time = 10
self.nodes[0].setmocktime(int(time.time() + wait_time))
diff --git a/test/functional/test_framework/bdb.py b/test/functional/test_framework/bdb.py
index 9de358aa0a..97b9c1d6d0 100644
--- a/test/functional/test_framework/bdb.py
+++ b/test/functional/test_framework/bdb.py
@@ -51,7 +51,6 @@ def dump_leaf_page(data):
page_info['pgno'] = pgno
page_info['prev_pgno'] = prev_pgno
page_info['next_pgno'] = next_pgno
- page_info['entries'] = entries
page_info['hf_offset'] = hf_offset
page_info['level'] = level
page_info['pg_type'] = pg_type
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 1e7d9e4b0d..354cacf95a 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -203,6 +203,7 @@ BASE_SCRIPTS = [
'feature_notifications.py',
'rpc_getblockfilter.py',
'rpc_invalidateblock.py',
+ 'feature_utxo_set_hash.py',
'feature_rbf.py',
'mempool_packages.py',
'mempool_package_onemore.py',
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index aa0aa11d15..611061072f 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -225,6 +225,8 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir)
args = [
os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
'-merge=1',
+ '-shuffle=0',
+ '-prefer_small=1',
'-use_value_profile=1', # Also done by oss-fuzz https://github.com/google/oss-fuzz/issues/1406#issuecomment-387790487
os.path.join(corpus, t),
os.path.join(merge_dir, t),
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index fc0b86a297..bf7aeb5b4f 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -65,8 +65,6 @@ EXPECTED_BOOST_INCLUDES=(
boost/signals2/optional_last_value.hpp
boost/signals2/signal.hpp
boost/test/unit_test.hpp
- boost/thread/lock_types.hpp
- boost/thread/shared_mutex.hpp
)
for BOOST_INCLUDE in $(git grep '^#include <boost/' -- "*.cpp" "*.h" | cut -f2 -d: | cut -f2 -d'<' | cut -f1 -d'>' | sort -u); do