aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--ci/test/00_setup_env_native_asan.sh2
-rw-r--r--ci/test/00_setup_env_native_qt5.sh2
-rw-r--r--ci/test/00_setup_env_native_valgrind.sh2
-rw-r--r--configure.ac47
-rw-r--r--depends/Makefile50
-rw-r--r--depends/README.md1
-rw-r--r--depends/config.site.in74
-rw-r--r--depends/funcs.mk30
-rw-r--r--depends/hosts/darwin.mk97
-rw-r--r--depends/packages/libnatpmp.mk19
-rw-r--r--depends/packages/packages.mk1
-rw-r--r--doc/JSON-RPC-interface.md15
-rw-r--r--doc/build-osx.md7
-rw-r--r--doc/build-unix.md24
-rw-r--r--doc/dependencies.md4
-rw-r--r--doc/productivity.md1
-rw-r--r--doc/release-notes-18077.md10
-rw-r--r--doc/tor.md2
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/Makefile.qttest.include2
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/flatfile.cpp1
-rw-r--r--src/init.cpp20
-rw-r--r--src/interfaces/node.h2
-rw-r--r--src/key_io.cpp12
-rw-r--r--src/mapport.cpp336
-rw-r--r--src/mapport.h30
-rw-r--r--src/net.cpp131
-rw-r--r--src/net.h109
-rw-r--r--src/net_processing.cpp13
-rw-r--r--src/netaddress.cpp81
-rw-r--r--src/netaddress.h24
-rw-r--r--src/node/interfaces.cpp11
-rw-r--r--src/outputtype.cpp2
-rw-r--r--src/outputtype.h6
-rw-r--r--src/policy/fees.h13
-rw-r--r--src/qt/addresstablemodel.cpp6
-rw-r--r--src/qt/coincontroldialog.cpp2
-rw-r--r--src/qt/forms/debugwindow.ui9
-rw-r--r--src/qt/forms/optionsdialog.ui10
-rw-r--r--src/qt/guiutil.cpp13
-rw-r--r--src/qt/guiutil.h6
-rw-r--r--src/qt/optionsdialog.cpp9
-rw-r--r--src/qt/optionsmodel.cpp24
-rw-r--r--src/qt/optionsmodel.h1
-rw-r--r--src/qt/peertablemodel.cpp10
-rw-r--r--src/qt/peertablemodel.h6
-rw-r--r--src/qt/rpcconsole.cpp31
-rw-r--r--src/qt/signverifymessagedialog.cpp2
-rw-r--r--src/qt/transactionrecord.cpp2
-rw-r--r--src/rpc/mining.cpp2
-rw-r--r--src/rpc/net.cpp8
-rw-r--r--src/rpc/util.cpp4
-rw-r--r--src/script/descriptor.cpp4
-rw-r--r--src/script/signingprovider.cpp8
-rw-r--r--src/script/standard.cpp9
-rw-r--r--src/script/standard.h6
-rw-r--r--src/test/fuzz/kitchen_sink.cpp8
-rw-r--r--src/test/fuzz/muhash.cpp2
-rw-r--r--src/test/fuzz/policy_estimator.cpp4
-rw-r--r--src/test/fuzz/process_message.cpp3
-rw-r--r--src/test/fuzz/process_messages.cpp3
-rw-r--r--src/test/fuzz/util.h19
-rw-r--r--src/test/netbase_tests.cpp21
-rw-r--r--src/test/script_standard_tests.cpp38
-rw-r--r--src/util/message.cpp2
-rw-r--r--src/util/system.cpp27
-rw-r--r--src/util/system.h12
-rw-r--r--src/wallet/rpcwallet.cpp14
-rw-r--r--src/wallet/test/wallet_tests.cpp6
-rw-r--r--src/wallet/wallet.cpp4
-rwxr-xr-xtest/functional/mempool_compatibility.py17
-rwxr-xr-xtest/functional/rpc_setban.py16
-rw-r--r--test/functional/test_framework/util.py1
-rw-r--r--test/functional/test_framework/wallet.py10
-rwxr-xr-xtest/lint/lint-includes.sh3
79 files changed, 1096 insertions, 479 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index e7a50d931a..b915cfabc7 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -170,7 +170,7 @@ task:
task:
name: 'macOS 10.15 native [gui] [no depends]'
macos_brew_addon_script:
- - brew install boost libevent berkeley-db4 qt miniupnpc ccache zeromq qrencode sqlite libtool automake pkg-config gnu-getopt
+ - brew install boost libevent berkeley-db4 qt miniupnpc libnatpmp ccache zeromq qrencode sqlite libtool automake pkg-config gnu-getopt
<< : *GLOBAL_TASK_TEMPLATE
osx_instance:
# Use latest image, but hardcode version to avoid silent upgrades (and breaks)
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index 191b8049b0..f682486088 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 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 libboost-thread-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_qt5.sh b/ci/test/00_setup_env_native_qt5.sh
index dc6b2aecb5..567145fe47 100644
--- a/ci/test/00_setup_env_native_qt5.sh
+++ b/ci/test/00_setup_env_native_qt5.sh
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_qt5
export DOCKER_NAME_TAG=ubuntu:18.04 # Check that bionic gcc-7 can compile our c++17 and run our functional tests in python3, see doc/dependencies.md
export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
-export DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
+export DEP_OPTS="NO_QT=1 NO_UPNP=1 NO_NATPMP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
export RUN_SECURITY_TESTS="true"
export RUN_UNIT_TESTS_SEQUENTIAL="true"
diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh
index bfaea13a25..f0c153158b 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 libzmq3-dev libsqlite3-dev"
+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 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/configure.ac b/configure.ac
index 0a8d5ef8f8..0fa99cfc47 100644
--- a/configure.ac
+++ b/configure.ac
@@ -143,6 +143,18 @@ AC_ARG_ENABLE([upnp-default],
[use_upnp_default=$enableval],
[use_upnp_default=no])
+AC_ARG_WITH([natpmp],
+ [AS_HELP_STRING([--with-natpmp],
+ [enable NAT-PMP (default is yes if libnatpmp is found)])],
+ [use_natpmp=$withval],
+ [use_natpmp=auto])
+
+AC_ARG_ENABLE([natpmp-default],
+ [AS_HELP_STRING([--enable-natpmp-default],
+ [if NAT-PMP is enabled, turn it on at startup (default is no)])],
+ [use_natpmp_default=$enableval],
+ [use_natpmp_default=no])
+
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--disable-tests],[do not compile tests (default is to compile)]),
[use_tests=$enableval],
@@ -1206,6 +1218,7 @@ if test "x$enable_fuzz" = "xyes"; then
enable_wallet=no
use_bench=no
use_upnp=no
+ use_natpmp=no
use_zmq=no
AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"]],,[[$CXXFLAG_WERROR]])
@@ -1303,6 +1316,13 @@ if test x$have_miniupnpc != xno; then
fi
fi
+dnl Check for libnatpmp (optional).
+if test "x$use_natpmp" != xno; then
+ AC_CHECK_HEADERS([natpmp.h],
+ [AC_CHECK_LIB([natpmp], [initnatpmp], [NATPMP_LIBS=-lnatpmp], [have_natpmp=no])],
+ [have_natpmp=no])
+fi
+
if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
use_boost=no
else
@@ -1561,6 +1581,31 @@ else
fi
fi
+dnl Enable NAT-PMP support.
+AC_MSG_CHECKING([whether to build with support for NAT-PMP])
+if test "x$have_natpmp" = xno; then
+ if test "x$use_natpmp" = xyes; then
+ AC_MSG_ERROR([NAT-PMP requested but cannot be built. Use --without-natpmp])
+ fi
+ AC_MSG_RESULT([no])
+ use_natpmp=no
+else
+ if test "x$use_natpmp" != xno; then
+ AC_MSG_RESULT([yes])
+ AC_MSG_CHECKING([whether to build with NAT-PMP enabled by default])
+ use_natpmp=yes
+ natpmp_setting=0
+ if test "x$use_natpmp_default" != xno; then
+ use_natpmp_default=yes
+ natpmp_setting=1
+ fi
+ AC_MSG_RESULT($use_natpmp_default)
+ AC_DEFINE_UNQUOTED([USE_NATPMP], [$natpmp_setting], [NAT-PMP support not compiled if undefined, otherwise value (0 or 1) determines default state])
+ else
+ AC_MSG_RESULT([no])
+ fi
+fi
+
dnl these are only used when qt is enabled
BUILD_TEST_QT=""
if test x$bitcoin_enable_qt != xno; then
@@ -1707,6 +1752,7 @@ AC_SUBST(SQLITE_LIBS)
AC_SUBST(TESTDEFS)
AC_SUBST(MINIUPNPC_CPPFLAGS)
AC_SUBST(MINIUPNPC_LIBS)
+AC_SUBST(NATPMP_LIBS)
AC_SUBST(EVENT_LIBS)
AC_SUBST(EVENT_PTHREADS_LIBS)
AC_SUBST(ZMQ_LIBS)
@@ -1794,6 +1840,7 @@ else
fi
echo " with bench = $use_bench"
echo " with upnp = $use_upnp"
+echo " with natpmp = $use_natpmp"
echo " use asm = $use_asm"
echo " sanitizers = $use_sanitizers"
echo " debug enabled = $enable_debug"
diff --git a/depends/Makefile b/depends/Makefile
index 1ad21f6821..596a46d4a2 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -37,6 +37,7 @@ NO_QR ?=
NO_WALLET ?=
NO_ZMQ ?=
NO_UPNP ?=
+NO_NATPMP ?=
MULTIPROCESS ?=
FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources
@@ -126,6 +127,8 @@ $(host_arch)_$(host_os)_id_string+=$(shell $(host_RANLIB) --version 2>/dev/null)
$(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null)
ifneq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
+# Make sure that cache is invalidated when switching between system and
+# depends-managed, pinned clang
build_id_string+=system_clang
$(host_arch)_$(host_os)_id_string+=system_clang
endif
@@ -139,10 +142,12 @@ sqlite_packages_$(NO_SQLITE) = $(sqlite_packages)
wallet_packages_$(NO_WALLET) = $(bdb_packages_) $(sqlite_packages_)
upnp_packages_$(NO_UPNP) = $(upnp_packages)
+natpmp_packages_$(NO_NATPMP) = $(natpmp_packages)
+
zmq_packages_$(NO_ZMQ) = $(zmq_packages)
multiprocess_packages_$(MULTIPROCESS) = $(multiprocess_packages)
-packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_)
+packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(natpmp_packages_)
native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages)
ifneq ($(zmq_packages_),)
@@ -163,12 +168,6 @@ $(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain)
include funcs.mk
-binutils_path=$($($(host_arch)_$(host_os)_native_binutils)_prefixbin)
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
-toolchain_path=$($($(host_arch)_$(host_os)_native_toolchain)_prefixbin)
-else
-toolchain_path=
-endif
final_build_id_long+=$(shell $(build_SHA256SUM) config.site.in)
final_build_id+=$(shell echo -n "$(final_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH))
$(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages)
@@ -179,15 +178,39 @@ $(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages)
$(AT)cd $(@D); $(foreach package,$^, tar xf $($(package)_cached); )
$(AT)touch $@
+# $PATH is not preserved between ./configure and make by convention. Its
+# modification and overriding at ./configure time is (as I understand it)
+# supposed to be captured by the AC_{PROG_{,OBJ}CXX,PATH_{PROG,TOOL}} macros,
+# which will expand the program names to their full absolute paths. The notable
+# exception is command line overriding: ./configure CC=clang, which skips the
+# program name expansion step, and works because the user implicitly indicates
+# with CC=clang that clang will be available in $PATH at all times, and is most
+# likely part of the user's system.
+#
+# Therefore, when we "seed the autoconf cache"/"override well-known program
+# vars" by setting AR=<blah> in our config.site, either one of two things needs
+# to be true for the build system to work correctly:
+#
+# 1. If we refer to the program by name (e.g. AR=riscv64-gnu-linux-ar), the
+# tool needs to be available in $PATH at all times.
+#
+# 2. If the tool is _**not**_ expected to be available in $PATH at all times
+# (such as is the case for our native_cctools binutils tools), it needs to
+# be referred to by its absolute path, such as would be output by the
+# AC_PATH_{PROG,TOOL} macros.
+#
+# Minor note: it is also okay to refer to tools by their absolute path even if
+# we expect them to be available in $PATH at all times, more specificity does
+# not hurt.
$(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_build_id)
$(AT)@mkdir -p $(@D)
$(AT)sed -e 's|@HOST@|$(host)|' \
- -e 's|@CC@|$(toolchain_path)$(host_CC)|' \
- -e 's|@CXX@|$(toolchain_path)$(host_CXX)|' \
- -e 's|@AR@|$(binutils_path)$(host_AR)|' \
- -e 's|@RANLIB@|$(binutils_path)$(host_RANLIB)|' \
- -e 's|@NM@|$(binutils_path)$(host_NM)|' \
- -e 's|@STRIP@|$(binutils_path)$(host_STRIP)|' \
+ -e 's|@CC@|$(host_CC)|' \
+ -e 's|@CXX@|$(host_CXX)|' \
+ -e 's|@AR@|$(host_AR)|' \
+ -e 's|@RANLIB@|$(host_RANLIB)|' \
+ -e 's|@NM@|$(host_NM)|' \
+ -e 's|@STRIP@|$(host_STRIP)|' \
-e 's|@build_os@|$(build_os)|' \
-e 's|@host_os@|$(host_os)|' \
-e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \
@@ -200,6 +223,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_
-e 's|@no_zmq@|$(NO_ZMQ)|' \
-e 's|@no_wallet@|$(NO_WALLET)|' \
-e 's|@no_upnp@|$(NO_UPNP)|' \
+ -e 's|@no_natpmp@|$(NO_NATPMP)|' \
-e 's|@multiprocess@|$(MULTIPROCESS)|' \
-e 's|@debug@|$(DEBUG)|' \
$< > $@
diff --git a/depends/README.md b/depends/README.md
index 085e0e6054..9bc9b6714b 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -94,6 +94,7 @@ The following can be set when running make: `make FOO=bar`
- `NO_BDB`: Don't download/build/cache BerkeleyDB
- `NO_SQLITE`: Don't download/build/cache SQLite
- `NO_UPNP`: Don't download/build/cache packages needed for enabling UPnP
+- `NO_NATPMP`: Don't download/build/cache packages needed for enabling NAT-PMP</dd>
- `ALLOW_HOST_PACKAGES`: Packages that are missed in dependencies (due to `NO_*` option or
build script logic) are searched for among the host system packages using
`pkg-config`. It allows building with packages of other (newer) versions
diff --git a/depends/config.site.in b/depends/config.site.in
index f4531830c8..391767357a 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -8,70 +8,74 @@ true # Dummy command because shellcheck treats all directives before first
# See: https://github.com/koalaman/shellcheck/wiki/Directive
# shellcheck disable=SC2154
-depends_prefix="$(cd "$(dirname ${ac_site_file})/.." && pwd)"
+depends_prefix="$(cd "$(dirname "$ac_site_file")/.." && pwd)"
cross_compiling=maybe
-host_alias=@HOST@
-ac_tool_prefix=${host_alias}-
+host_alias="@HOST@"
+ac_tool_prefix="${host_alias}-"
-if test -z $with_boost; then
- with_boost=$depends_prefix
+if test -z "$with_boost"; then
+ with_boost="$depends_prefix"
fi
-if test -z $with_qt_plugindir; then
- with_qt_plugindir=$depends_prefix/plugins
+if test -z "$with_qt_plugindir"; then
+ with_qt_plugindir="${depends_prefix}/plugins"
fi
-if test -z $with_qt_translationdir; then
- with_qt_translationdir=$depends_prefix/translations
+if test -z "$with_qt_translationdir"; then
+ with_qt_translationdir="${depends_prefix}/translations"
fi
-if test -z $with_qt_bindir && test -z "@no_qt@"; then
- with_qt_bindir=$depends_prefix/native/bin
+if test -z "$with_qt_bindir" && test -z "@no_qt@"; then
+ with_qt_bindir="${depends_prefix}/native/bin"
fi
-if test -z $with_mpgen && test -n "@multiprocess@"; then
- with_mpgen=$depends_prefix/native
+if test -z "$with_mpgen" && test -n "@multiprocess@"; then
+ with_mpgen="${depends_prefix}/native"
fi
-if test -z $with_qrencode && test -n "@no_qr@"; then
+if test -z "$with_qrencode" && test -n "@no_qr@"; then
with_qrencode=no
fi
-if test -z $enable_wallet && test -n "@no_wallet@"; then
+if test -z "$enable_wallet" && test -n "@no_wallet@"; then
enable_wallet=no
fi
-if test -z $enable_multiprocess && test -n "@multiprocess@"; then
+if test -z "$enable_multiprocess" && test -n "@multiprocess@"; then
enable_multiprocess=yes
fi
-if test -z $with_miniupnpc && test -n "@no_upnp@"; then
+if test -z "$with_miniupnpc" && test -n "@no_upnp@"; then
with_miniupnpc=no
fi
-if test -z $with_gui && test -n "@no_qt@"; then
+if test -z "$with_natpmp" && test -n "@no_natpmp@"; then
+ with_natpmp=no
+fi
+
+if test -z "$with_gui" && test -n "@no_qt@"; then
with_gui=no
fi
-if test -z $enable_zmq && test -n "@no_zmq@"; then
+if test -z "$enable_zmq" && test -n "@no_zmq@"; then
enable_zmq=no
fi
-if test x@host_os@ = xdarwin; then
+if test "x@host_os@" = xdarwin; then
BREW=no
PORT=no
fi
-PATH=$depends_prefix/native/bin:$PATH
+PATH="${depends_prefix}/native/bin:${PATH}"
PKG_CONFIG="$(which pkg-config) --static"
# These two need to remain exported because pkg-config does not see them
# otherwise. That means they must be unexported at the end of configure.ac to
# avoid ruining the cache. Sigh.
-export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig
+export PKG_CONFIG_PATH="${depends_prefix}/share/pkgconfig:${depends_prefix}/lib/pkgconfig"
if test -z "@allow_host_packages@"; then
- export PKG_CONFIG_LIBDIR=$depends_prefix/lib/pkgconfig
+ export PKG_CONFIG_LIBDIR="${depends_prefix}/lib/pkgconfig"
fi
-CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS"
-LDFLAGS="-L$depends_prefix/lib $LDFLAGS"
+CPPFLAGS="-I${depends_prefix}/include/ ${CPPFLAGS}"
+LDFLAGS="-L${depends_prefix}/lib ${LDFLAGS}"
if test -n "@CC@" -a -z "${CC}"; then
CC="@CC@"
@@ -82,18 +86,18 @@ fi
PYTHONPATH="${depends_prefix}/native/lib/python3/dist-packages${PYTHONPATH:+${PATH_SEPARATOR}}${PYTHONPATH}"
if test -n "@AR@"; then
- AR=@AR@
- ac_cv_path_ac_pt_AR=${AR}
+ AR="@AR@"
+ ac_cv_path_ac_pt_AR="${AR}"
fi
if test -n "@RANLIB@"; then
- RANLIB=@RANLIB@
- ac_cv_path_ac_pt_RANLIB=${RANLIB}
+ RANLIB="@RANLIB@"
+ ac_cv_path_ac_pt_RANLIB="${RANLIB}"
fi
if test -n "@NM@"; then
- NM=@NM@
- ac_cv_path_ac_pt_NM=${NM}
+ NM="@NM@"
+ ac_cv_path_ac_pt_NM="${NM}"
fi
if test -n "@debug@"; then
@@ -101,14 +105,14 @@ if test -n "@debug@"; then
fi
if test -n "@CFLAGS@"; then
- CFLAGS="@CFLAGS@ $CFLAGS"
+ CFLAGS="@CFLAGS@ ${CFLAGS}"
fi
if test -n "@CXXFLAGS@"; then
- CXXFLAGS="@CXXFLAGS@ $CXXFLAGS"
+ CXXFLAGS="@CXXFLAGS@ ${CXXFLAGS}"
fi
if test -n "@CPPFLAGS@"; then
- CPPFLAGS="@CPPFLAGS@ $CPPFLAGS"
+ CPPFLAGS="@CPPFLAGS@ ${CPPFLAGS}"
fi
if test -n "@LDFLAGS@"; then
- LDFLAGS="@LDFLAGS@ $LDFLAGS"
+ LDFLAGS="@LDFLAGS@ ${LDFLAGS}"
fi
diff --git a/depends/funcs.mk b/depends/funcs.mk
index 5697bd6f15..c0159f0e38 100644
--- a/depends/funcs.mk
+++ b/depends/funcs.mk
@@ -1,17 +1,23 @@
define int_vars
#Set defaults for vars which may be overridden per-package
-$(1)_cc=$($($(1)_type)_CC)
-$(1)_cxx=$($($(1)_type)_CXX)
-$(1)_objc=$($($(1)_type)_OBJC)
-$(1)_objcxx=$($($(1)_type)_OBJCXX)
-$(1)_ar=$($($(1)_type)_AR)
-$(1)_ranlib=$($($(1)_type)_RANLIB)
-$(1)_libtool=$($($(1)_type)_LIBTOOL)
-$(1)_nm=$($($(1)_type)_NM)
-$(1)_cflags=$($($(1)_type)_CFLAGS) $($($(1)_type)_$(release_type)_CFLAGS)
-$(1)_cxxflags=$($($(1)_type)_CXXFLAGS) $($($(1)_type)_$(release_type)_CXXFLAGS)
-$(1)_ldflags=$($($(1)_type)_LDFLAGS) $($($(1)_type)_$(release_type)_LDFLAGS) -L$($($(1)_type)_prefix)/lib
-$(1)_cppflags=$($($(1)_type)_CPPFLAGS) $($($(1)_type)_$(release_type)_CPPFLAGS) -I$($($(1)_type)_prefix)/include
+$(1)_cc=$$($$($(1)_type)_CC)
+$(1)_cxx=$$($$($(1)_type)_CXX)
+$(1)_objc=$$($$($(1)_type)_OBJC)
+$(1)_objcxx=$$($$($(1)_type)_OBJCXX)
+$(1)_ar=$$($$($(1)_type)_AR)
+$(1)_ranlib=$$($$($(1)_type)_RANLIB)
+$(1)_libtool=$$($$($(1)_type)_LIBTOOL)
+$(1)_nm=$$($$($(1)_type)_NM)
+$(1)_cflags=$$($$($(1)_type)_CFLAGS) \
+ $$($$($(1)_type)_$$(release_type)_CFLAGS)
+$(1)_cxxflags=$$($$($(1)_type)_CXXFLAGS) \
+ $$($$($(1)_type)_$$(release_type)_CXXFLAGS)
+$(1)_ldflags=$$($$($(1)_type)_LDFLAGS) \
+ $$($$($(1)_type)_$$(release_type)_LDFLAGS) \
+ -L$$($($(1)_type)_prefix)/lib
+$(1)_cppflags=$$($$($(1)_type)_CPPFLAGS) \
+ $$($$($(1)_type)_$$(release_type)_CPPFLAGS) \
+ -I$$($$($(1)_type)_prefix)/include
$(1)_recipe_hash:=
endef
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index e9faeba336..646e97837a 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -6,6 +6,49 @@ LD64_VERSION=530
OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-libcxx-headers
+darwin_native_binutils=native_cctools
+
+ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
+# FORCE_USE_SYSTEM_CLANG is empty, so we use our depends-managed, pinned clang
+# from llvm.org
+
+# The native_cctools package is what provides clang when FORCE_USE_SYSTEM_CLANG
+# is empty
+darwin_native_toolchain=native_cctools
+
+clang_prog=$(build_prefix)/bin/clang
+clangxx_prog=$(clang_prog)++
+
+clang_resource_dir=$(build_prefix)/lib/clang/$(native_cctools_clang_version)
+else
+# FORCE_USE_SYSTEM_CLANG is non-empty, so we use the clang from the user's
+# system
+
+darwin_native_toolchain=
+
+# We can't just use $(shell command -v clang) because GNU Make handles builtins
+# in a special way and doesn't know that `command` is a POSIX-standard builtin
+# prior to 1af314465e5dfe3e8baa839a32a72e83c04f26ef, first released in v4.2.90.
+# At the time of writing, GNU Make v4.2.1 is still being used in supported
+# distro releases.
+#
+# Source: https://lists.gnu.org/archive/html/bug-make/2017-11/msg00017.html
+clang_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang")
+clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++")
+
+clang_resource_dir=$(shell clang -print-resource-dir)
+endif
+
+cctools_TOOLS=AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL
+
+# Make-only lowercase function
+lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
+
+# For well-known tools provided by cctools, make sure that their well-known
+# variable is set to the full path of the tool, just like how AC_PATH_{TOO,PROG}
+# would.
+$(foreach TOOL,$(cctools_TOOLS),$(eval darwin_$(TOOL) = $$(build_prefix)/bin/$$(host)-$(call lc,$(TOOL))))
+
# Flag explanations:
#
# -mlinker-version
@@ -18,7 +61,7 @@ OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-
# Explicitly point to our binaries (e.g. cctools) so that they are
# ensured to be found and preferred over other possibilities.
#
-# -nostdinc++ -isystem $(OSX_SDK)/usr/include/c++/v1
+# -stdlib=libc++ -nostdinc++ -Xclang -cxx-isystem$(OSX_SDK)/usr/include/c++/v1
#
# Forces clang to use the libc++ headers from our SDK and completely
# forget about the libc++ headers from the standard directories
@@ -28,8 +71,49 @@ OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-
# https://reviews.llvm.org/D64089, we should use that instead. Read the
# differential summary there for more details.
#
-darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -B$(build_prefix)/bin
-darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -stdlib=libc++ -mlinker-version=$(LD64_VERSION) -B$(build_prefix)/bin -nostdinc++ -isystem $(OSX_SDK)/usr/include/c++/v1
+# -Xclang -*system<path_a> \
+# -Xclang -*system<path_b> \
+# -Xclang -*system<path_c> ...
+#
+# Adds path_a, path_b, and path_c to the bottom of clang's list of
+# include search paths. This is used to explicitly specify the list of
+# system include search paths and its ordering, rather than rely on
+# clang's autodetection routine. This routine has been shown to:
+# 1. Fail to pickup libc++ headers in $SYSROOT/usr/include/c++/v1
+# when clang was built manually (see: https://github.com/bitcoin/bitcoin/pull/17919#issuecomment-656785034)
+# 2. Fail to pickup C headers in $SYSROOT/usr/include when
+# C_INCLUDE_DIRS was specified at configure time (see: https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9)
+#
+# Talking directly to cc1 with -Xclang here grants us access to specify
+# more granular categories for these system include search paths, and we
+# can use the correct categories that these search paths would have been
+# placed in if the autodetection routine had worked correctly. (see:
+# https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9#the-treatment)
+#
+# Furthermore, it places these search paths after any "non-Xclang"
+# specified search paths. This prevents any additional clang options or
+# environment variables from coming after or in between these system
+# include search paths, as that would be wrong in general but would also
+# break #include_next's.
+#
+darwin_CC=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \
+ -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \
+ -u LIBRARY_PATH \
+ $(clang_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \
+ -B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \
+ --sysroot=$(OSX_SDK) \
+ -Xclang -internal-externc-isystem$(clang_resource_dir)/include \
+ -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include
+darwin_CXX=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \
+ -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \
+ -u LIBRARY_PATH \
+ $(clangxx_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \
+ -B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \
+ --sysroot=$(OSX_SDK) \
+ -stdlib=libc++ -nostdinc++ \
+ -Xclang -cxx-isystem$(OSX_SDK)/usr/include/c++/v1 \
+ -Xclang -internal-externc-isystem$(clang_resource_dir)/include \
+ -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include
darwin_CFLAGS=-pipe
darwin_CXXFLAGS=$(darwin_CFLAGS)
@@ -40,11 +124,4 @@ darwin_release_CXXFLAGS=$(darwin_release_CFLAGS)
darwin_debug_CFLAGS=-O1
darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS)
-darwin_native_binutils=native_cctools
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
-darwin_native_toolchain=native_cctools
-else
-darwin_native_toolchain=
-endif
-
darwin_cmake_system=Darwin
diff --git a/depends/packages/libnatpmp.mk b/depends/packages/libnatpmp.mk
new file mode 100644
index 0000000000..a24f201859
--- /dev/null
+++ b/depends/packages/libnatpmp.mk
@@ -0,0 +1,19 @@
+package=libnatpmp
+$(package)_version=20150609
+$(package)_download_path=https://miniupnp.tuxfamily.org/files/
+$(package)_file_name=$(package)-$($(package)_version).tar.gz
+$(package)_sha256_hash=e1aa9c4c4219bc06943d6b2130f664daee213fb262fcb94dd355815b8f4536b0
+
+define $(package)_set_vars
+ $(package)_build_opts=CC="$($(package)_cc)"
+endef
+
+define $(package)_build_cmds
+ $(MAKE) libnatpmp.a $($(package)_build_opts)
+endef
+
+define $(package)_stage_cmds
+ mkdir -p $($(package)_staging_prefix_dir)/include $($(package)_staging_prefix_dir)/lib &&\
+ install *.h $($(package)_staging_prefix_dir)/include &&\
+ install libnatpmp.a $($(package)_staging_prefix_dir)/lib
+endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index d4fd23a47b..0f35ca0d2d 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -16,6 +16,7 @@ sqlite_packages=sqlite
zmq_packages=zeromq
upnp_packages=miniupnpc
+natpmp_packages=libnatpmp
multiprocess_packages = libmultiprocess capnp
multiprocess_native_packages = native_libmultiprocess native_capnp
diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md
index c66e79af71..12807bfb86 100644
--- a/doc/JSON-RPC-interface.md
+++ b/doc/JSON-RPC-interface.md
@@ -88,13 +88,14 @@ RPC interface will be abused.
- **Secure string handling:** The RPC interface does not guarantee any
escaping of data beyond what's necessary to encode it as JSON,
although it does usually provide serialized data using a hex
- representation of the bytes. If you use RPC data in your programs or
- provide its data to other programs, you must ensure any problem
- strings are properly escaped. For example, multiple websites have
- been manipulated because they displayed decoded hex strings that
- included HTML `<script>` tags. For this reason, and other
- non-security reasons, it is recommended to display all serialized data
- in hex form only.
+ representation of the bytes. If you use RPC data in your programs or
+ provide its data to other programs, you must ensure any problem strings
+ are properly escaped. For example, the `createwallet` RPC accepts
+ arguments such as `wallet_name` which is a string and could be used
+ for a path traversal attack without application level checks. Multiple
+ websites have been manipulated because they displayed decoded hex strings
+ that included HTML `<script>` tags. For this reason, and others, it is
+ recommended to display all serialized data in hex form only.
## RPC consistency guarantees
diff --git a/doc/build-osx.md b/doc/build-osx.md
index c1d101fde1..04ee43f81d 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -19,7 +19,7 @@ Then install [Homebrew](https://brew.sh).
## Dependencies
```shell
-brew install automake libtool boost miniupnpc pkg-config python qt libevent qrencode
+brew install automake libtool boost miniupnpc libnatpmp pkg-config python qt libevent qrencode
```
If you run into issues, check [Homebrew's troubleshooting page](https://docs.brew.sh/Troubleshooting).
@@ -30,6 +30,11 @@ If you want to build the disk image with `make deploy` (.dmg / optional), you ne
brew install librsvg
```
+and [`macdeployqtplus`](../contrib/macdeploy/README.md) dependencies:
+```shell
+pip3 install ds_store mac_alias
+```
+
The wallet support requires one or both of the dependencies ([*SQLite*](#sqlite) and [*Berkeley DB*](#berkeley-db)) in the sections below.
To build Bitcoin Core without wallet, see [*Disable-wallet mode*](#disable-wallet-mode).
diff --git a/doc/build-unix.md b/doc/build-unix.md
index cfe3328b45..5c24886dbf 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -41,6 +41,7 @@ Optional dependencies:
Library | Purpose | Description
------------|------------------|----------------------
miniupnpc | UPnP Support | Firewall-jumping support
+ libnatpmp | NAT-PMP Support | Firewall-jumping support
libdb4.8 | Berkeley DB | Optional, wallet storage (only needed when wallet enabled)
qt | GUI | GUI toolkit (only needed when GUI enabled)
libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled)
@@ -99,9 +100,9 @@ SQLite is required for the wallet:
To build Bitcoin Core without wallet, see [*Disable-wallet mode*](/doc/build-unix.md#disable-wallet-mode)
-Optional (see `--with-miniupnpc` and `--enable-upnp-default`):
+Optional port mapping libraries (see: `--with-miniupnpc`, and `--enable-upnp-default`, `--with-natpmp`, `--enable-natpmp-default`):
- sudo apt-get install libminiupnpc-dev
+ sudo apt install libminiupnpc-dev libnatpmp-dev
ZMQ dependencies (provides ZMQ API):
@@ -133,9 +134,9 @@ Build requirements:
sudo dnf install gcc-c++ libtool make autoconf automake libevent-devel boost-devel libdb4-devel libdb4-cxx-devel python3
-Optional (see `--with-miniupnpc` and `--enable-upnp-default`):
+Optional port mapping libraries (see: `--with-miniupnpc`, and `--enable-upnp-default`, `--with-natpmp`, `--enable-natpmp-default`):
- sudo dnf install miniupnpc-devel
+ sudo dnf install miniupnpc-devel libnatpmp-devel
ZMQ dependencies (provides ZMQ API):
@@ -158,18 +159,27 @@ Notes
The release is built with GCC and then "strip bitcoind" to strip the debug
symbols, which reduces the executable size by about 90%.
-
miniupnpc
---------
[miniupnpc](https://miniupnp.tuxfamily.org) may be used for UPnP port mapping. It can be downloaded from [here](
https://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and
-turned off by default. See the configure options for upnp behavior desired:
+turned off by default. See the configure options for UPnP behavior desired:
- --without-miniupnpc No UPnP support miniupnp not required
+ --without-miniupnpc No UPnP support, miniupnp not required
--disable-upnp-default (the default) UPnP support turned off by default at runtime
--enable-upnp-default UPnP support turned on by default at runtime
+libnatpmp
+---------
+
+[libnatpmp](https://miniupnp.tuxfamily.org/libnatpmp.html) may be used for NAT-PMP port mapping. It can be downloaded
+from [here](https://miniupnp.tuxfamily.org/files/). NAT-PMP support is compiled in and
+turned off by default. See the configure options for NAT-PMP behavior desired:
+
+ --without-natpmp No NAT-PMP support, libnatpmp not required
+ --disable-natpmp-default (the default) NAT-PMP support turned off by default at runtime
+ --enable-natpmp-default NAT-PMP support turned on by default at runtime
Berkeley DB
-----------
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 76e8910871..6b2b904632 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -14,6 +14,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| GCC | | [7+](https://gcc.gnu.org/) (C++17 support) | | | |
| HarfBuzz-NG | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) |
| libevent | [2.1.11-stable](https://github.com/libevent/libevent/releases) | [2.0.21](https://github.com/bitcoin/bitcoin/pull/18676) | No | | |
+| libnatpmp | [20150609](https://miniupnp.tuxfamily.org/files) | | No | | |
| libpng | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) |
| librsvg | | | | | |
| MiniUPnPc | [2.0.20180203](https://miniupnp.tuxfamily.org/files) | | No | | |
@@ -32,7 +33,8 @@ Controlling dependencies
Some dependencies are not needed in all configurations. The following are some factors that affect the dependency list.
#### Options passed to `./configure`
-* MiniUPnPc is not needed with `--with-miniupnpc=no`.
+* MiniUPnPc is not needed with `--without-miniupnpc`.
+* libnatpmp is not needed with `--without-natpmp`.
* Berkeley DB is not needed with `--disable-wallet` or `--without-bdb`.
* SQLite is not needed with `--disable-wallet` or `--without-sqlite`.
* Qt is not needed with `--without-gui`.
diff --git a/doc/productivity.md b/doc/productivity.md
index 555f0afe3c..a01c6f545d 100644
--- a/doc/productivity.md
+++ b/doc/productivity.md
@@ -51,6 +51,7 @@ After running `./autogen.sh`, which generates the `./configure` file, use `./con
```sh
--without-miniupnpc
+--without-natpmp
--disable-bench
--disable-wallet
--without-gui
diff --git a/doc/release-notes-18077.md b/doc/release-notes-18077.md
new file mode 100644
index 0000000000..4034a4c19c
--- /dev/null
+++ b/doc/release-notes-18077.md
@@ -0,0 +1,10 @@
+P2P and network changes
+-----------------------
+
+- Added NAT-PMP port mapping support via [`libnatpmp`](https://miniupnp.tuxfamily.org/libnatpmp.html)
+
+Command-line options
+--------------------
+
+- The `-natpmp` option has been added to use NAT-PMP to map the listening port. If both UPnP
+and NAT-PMP are enabled, a successful allocation from UPnP prevails over one from NAT-PMP.
diff --git a/doc/tor.md b/doc/tor.md
index 86e5d9ddf3..1ba7137b8e 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -99,7 +99,7 @@ as well, use `discover` instead:
./bitcoind ... -discover
-and open port 8333 on your firewall (or use -upnp).
+and open port 8333 on your firewall (or use port mapping, i.e., `-upnp` or `-natpmp`).
If you only want to use Tor to reach .onion addresses, but not use it as a proxy
for normal IPv4/IPv6 communication, use:
diff --git a/src/Makefile.am b/src/Makefile.am
index 02797b19bc..1a0791dccd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -152,6 +152,7 @@ BITCOIN_CORE_H = \
key_io.h \
logging.h \
logging/timer.h \
+ mapport.h \
memusage.h \
merkleblock.h \
miner.h \
@@ -299,6 +300,7 @@ libbitcoin_server_a_SOURCES = \
index/blockfilterindex.cpp \
index/txindex.cpp \
init.cpp \
+ mapport.cpp \
miner.cpp \
net.cpp \
net_processing.cpp \
@@ -598,7 +600,7 @@ bitcoin_bin_ldadd = \
$(LIBMEMENV) \
$(LIBSECP256K1)
-bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS)
+bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS)
bitcoind_SOURCES = $(bitcoin_daemon_sources)
bitcoind_CPPFLAGS = $(bitcoin_bin_cppflags)
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index beb3f8dfd2..56b8ca8ce6 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -74,7 +74,7 @@ bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp
endif
-bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(SQLITE_LIBS)
+bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index f46310a603..3d41d203d3 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -320,7 +320,7 @@ if ENABLE_ZMQ
bitcoin_qt_ldadd += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS)
bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index c05dd38737..a6a857d952 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -55,7 +55,7 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
- $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS)
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index bdaddb4f0d..e9f9b73abe 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -167,7 +167,7 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(SQLITE_LIBS)
+test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -static
if ENABLE_ZMQ
diff --git a/src/flatfile.cpp b/src/flatfile.cpp
index 8a8f7b681c..11cf357f3d 100644
--- a/src/flatfile.cpp
+++ b/src/flatfile.cpp
@@ -92,6 +92,7 @@ bool FlatFileSeq::Flush(const FlatFilePos& pos, bool finalize)
fclose(file);
return error("%s: failed to commit file %d", __func__, pos.nFile);
}
+ DirectoryCommit(m_dir);
fclose(file);
return true;
diff --git a/src/init.cpp b/src/init.cpp
index 42e9925f98..9a63fe0e03 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -26,6 +26,7 @@
#include <interfaces/chain.h>
#include <interfaces/node.h>
#include <key.h>
+#include <mapport.h>
#include <miner.h>
#include <net.h>
#include <net_permissions.h>
@@ -468,6 +469,11 @@ void SetupServerArgs(NodeContext& node)
#else
hidden_args.emplace_back("-upnp");
#endif
+#ifdef USE_NATPMP
+ argsman.AddArg("-natpmp", strprintf("Use NAT-PMP to map the listening port (default: %s)", DEFAULT_NATPMP ? "1 when listening and no -proxy" : "0"), ArgsManager::ALLOW_BOOL, OptionsCategory::CONNECTION);
+#else
+ hidden_args.emplace_back("-natpmp");
+#endif // USE_NATPMP
argsman.AddArg("-whitebind=<[permissions@]addr>", "Bind to the given address and add permission flags to the peers connecting to it. "
"Use [host]:port notation for IPv6. Allowed permissions: " + Join(NET_PERMISSIONS_DOC, ", ") + ". "
"Specify multiple permissions separated by commas (default: download,noban,mempool,relay). Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -812,10 +818,13 @@ void InitParameterInteraction(ArgsManager& args)
// to protect privacy, do not listen by default if a default proxy server is specified
if (args.SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__);
- // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1
+ // to protect privacy, do not map ports when a proxy is set. The user may still specify -listen=1
// to listen locally, so don't rely on this happening through -listen below.
if (args.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__);
+ if (args.SoftSetBoolArg("-natpmp", false)) {
+ LogPrintf("%s: parameter interaction: -proxy set -> setting -natpmp=0\n", __func__);
+ }
// to protect privacy, do not discover addresses by default
if (args.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__);
@@ -825,6 +834,9 @@ void InitParameterInteraction(ArgsManager& args)
// do not map ports or try to retrieve public IP when not listening (pointless)
if (args.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__);
+ if (args.SoftSetBoolArg("-natpmp", false)) {
+ LogPrintf("%s: parameter interaction: -listen=0 -> setting -natpmp=0\n", __func__);
+ }
if (args.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__);
if (args.SoftSetBoolArg("-listenonion", false))
@@ -1898,10 +1910,8 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
Discover();
- // Map ports with UPnP
- if (args.GetBoolArg("-upnp", DEFAULT_UPNP)) {
- StartMapPort();
- }
+ // Map ports with UPnP or NAT-PMP.
+ StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), gArgs.GetBoolArg("-natpmp", DEFAULT_NATPMP));
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 97549aeb0e..15f7ef6256 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -82,7 +82,7 @@ public:
virtual bool shutdownRequested() = 0;
//! Map port.
- virtual void mapPort(bool use_upnp) = 0;
+ virtual void mapPort(bool use_upnp, bool use_natpmp) = 0;
//! Get proxy.
virtual bool getProxy(Network net, proxyType& proxy_info) = 0;
diff --git a/src/key_io.cpp b/src/key_io.cpp
index d2f5be93f5..a270ede864 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -8,16 +8,12 @@
#include <bech32.h>
#include <util/strencodings.h>
-#include <boost/variant/apply_visitor.hpp>
-#include <boost/variant/static_visitor.hpp>
-
+#include <algorithm>
#include <assert.h>
#include <string.h>
-#include <algorithm>
-namespace
-{
-class DestinationEncoder : public boost::static_visitor<std::string>
+namespace {
+class DestinationEncoder
{
private:
const CChainParams& m_params;
@@ -209,7 +205,7 @@ std::string EncodeExtKey(const CExtKey& key)
std::string EncodeDestination(const CTxDestination& dest)
{
- return boost::apply_visitor(DestinationEncoder(Params()), dest);
+ return std::visit(DestinationEncoder(Params()), dest);
}
CTxDestination DecodeDestination(const std::string& str)
diff --git a/src/mapport.cpp b/src/mapport.cpp
new file mode 100644
index 0000000000..2df4ce45d2
--- /dev/null
+++ b/src/mapport.cpp
@@ -0,0 +1,336 @@
+// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <mapport.h>
+
+#include <clientversion.h>
+#include <logging.h>
+#include <net.h>
+#include <netaddress.h>
+#include <netbase.h>
+#include <threadinterrupt.h>
+#include <util/system.h>
+
+#ifdef USE_NATPMP
+#include <compat.h>
+#include <natpmp.h>
+#endif // USE_NATPMP
+
+#ifdef USE_UPNP
+#include <miniupnpc/miniupnpc.h>
+#include <miniupnpc/upnpcommands.h>
+#include <miniupnpc/upnperrors.h>
+// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
+// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
+static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed");
+#endif // USE_UPNP
+
+#include <atomic>
+#include <cassert>
+#include <chrono>
+#include <functional>
+#include <string>
+#include <thread>
+
+#if defined(USE_NATPMP) || defined(USE_UPNP)
+static CThreadInterrupt g_mapport_interrupt;
+static std::thread g_mapport_thread;
+static std::atomic_uint g_mapport_enabled_protos{MapPortProtoFlag::NONE};
+static std::atomic<MapPortProtoFlag> g_mapport_current_proto{MapPortProtoFlag::NONE};
+
+using namespace std::chrono_literals;
+static constexpr auto PORT_MAPPING_REANNOUNCE_PERIOD{20min};
+static constexpr auto PORT_MAPPING_RETRY_PERIOD{5min};
+
+#ifdef USE_NATPMP
+static uint16_t g_mapport_external_port = 0;
+static bool NatpmpInit(natpmp_t* natpmp)
+{
+ const int r_init = initnatpmp(natpmp, /* detect gateway automatically */ 0, /* forced gateway - NOT APPLIED*/ 0);
+ if (r_init == 0) return true;
+ LogPrintf("natpmp: initnatpmp() failed with %d error.\n", r_init);
+ return false;
+}
+
+static bool NatpmpDiscover(natpmp_t* natpmp, struct in_addr& external_ipv4_addr)
+{
+ const int r_send = sendpublicaddressrequest(natpmp);
+ if (r_send == 2 /* OK */) {
+ int r_read;
+ natpmpresp_t response;
+ do {
+ r_read = readnatpmpresponseorretry(natpmp, &response);
+ } while (r_read == NATPMP_TRYAGAIN);
+
+ if (r_read == 0) {
+ external_ipv4_addr = response.pnu.publicaddress.addr;
+ return true;
+ } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) {
+ LogPrintf("natpmp: The gateway does not support NAT-PMP.\n");
+ } else {
+ LogPrintf("natpmp: readnatpmpresponseorretry() for public address failed with %d error.\n", r_read);
+ }
+ } else {
+ LogPrintf("natpmp: sendpublicaddressrequest() failed with %d error.\n", r_send);
+ }
+
+ return false;
+}
+
+static bool NatpmpMapping(natpmp_t* natpmp, const struct in_addr& external_ipv4_addr, uint16_t private_port, bool& external_ip_discovered)
+{
+ const uint16_t suggested_external_port = g_mapport_external_port ? g_mapport_external_port : private_port;
+ const int r_send = sendnewportmappingrequest(natpmp, NATPMP_PROTOCOL_TCP, private_port, suggested_external_port, 3600 /*seconds*/);
+ if (r_send == 12 /* OK */) {
+ int r_read;
+ natpmpresp_t response;
+ do {
+ r_read = readnatpmpresponseorretry(natpmp, &response);
+ } while (r_read == NATPMP_TRYAGAIN);
+
+ if (r_read == 0) {
+ auto pm = response.pnu.newportmapping;
+ if (private_port == pm.privateport && pm.lifetime > 0) {
+ g_mapport_external_port = pm.mappedpublicport;
+ const CService external{external_ipv4_addr, pm.mappedpublicport};
+ if (!external_ip_discovered && fDiscover) {
+ AddLocal(external, LOCAL_MAPPED);
+ external_ip_discovered = true;
+ }
+ LogPrintf("natpmp: Port mapping successful. External address = %s\n", external.ToString());
+ return true;
+ } else {
+ LogPrintf("natpmp: Port mapping failed.\n");
+ }
+ } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) {
+ LogPrintf("natpmp: The gateway does not support NAT-PMP.\n");
+ } else {
+ LogPrintf("natpmp: readnatpmpresponseorretry() for port mapping failed with %d error.\n", r_read);
+ }
+ } else {
+ LogPrintf("natpmp: sendnewportmappingrequest() failed with %d error.\n", r_send);
+ }
+
+ return false;
+}
+
+static bool ProcessNatpmp()
+{
+ bool ret = false;
+ natpmp_t natpmp;
+ struct in_addr external_ipv4_addr;
+ if (NatpmpInit(&natpmp) && NatpmpDiscover(&natpmp, external_ipv4_addr)) {
+ bool external_ip_discovered = false;
+ const uint16_t private_port = GetListenPort();
+ do {
+ ret = NatpmpMapping(&natpmp, external_ipv4_addr, private_port, external_ip_discovered);
+ } while (ret && g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
+ g_mapport_interrupt.reset();
+
+ const int r_send = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, private_port, g_mapport_external_port, /* remove a port mapping */ 0);
+ g_mapport_external_port = 0;
+ if (r_send == 12 /* OK */) {
+ LogPrintf("natpmp: Port mapping removed successfully.\n");
+ } else {
+ LogPrintf("natpmp: sendnewportmappingrequest(0) failed with %d error.\n", r_send);
+ }
+ }
+
+ closenatpmp(&natpmp);
+ return ret;
+}
+#endif // USE_NATPMP
+
+#ifdef USE_UPNP
+static bool ProcessUpnp()
+{
+ bool ret = false;
+ std::string port = strprintf("%u", GetListenPort());
+ const char * multicastif = nullptr;
+ const char * minissdpdpath = nullptr;
+ struct UPNPDev * devlist = nullptr;
+ char lanaddr[64];
+
+ int error = 0;
+#if MINIUPNPC_API_VERSION < 14
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
+#else
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
+#endif
+
+ struct UPNPUrls urls;
+ struct IGDdatas data;
+ int r;
+
+ r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
+ if (r == 1)
+ {
+ if (fDiscover) {
+ char externalIPAddress[40];
+ r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
+ if (r != UPNPCOMMAND_SUCCESS) {
+ LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
+ } else {
+ if (externalIPAddress[0]) {
+ CNetAddr resolved;
+ if (LookupHost(externalIPAddress, resolved, false)) {
+ LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString());
+ AddLocal(resolved, LOCAL_MAPPED);
+ }
+ } else {
+ LogPrintf("UPnP: GetExternalIPAddress failed.\n");
+ }
+ }
+ }
+
+ std::string strDesc = PACKAGE_NAME " " + FormatFullVersion();
+
+ do {
+ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
+
+ if (r != UPNPCOMMAND_SUCCESS) {
+ ret = false;
+ LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r));
+ break;
+ } else {
+ ret = true;
+ LogPrintf("UPnP Port Mapping successful.\n");
+ }
+ } while (g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
+ g_mapport_interrupt.reset();
+
+ r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
+ LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
+ freeUPNPDevlist(devlist); devlist = nullptr;
+ FreeUPNPUrls(&urls);
+ } else {
+ LogPrintf("No valid UPnP IGDs found\n");
+ freeUPNPDevlist(devlist); devlist = nullptr;
+ if (r != 0)
+ FreeUPNPUrls(&urls);
+ }
+
+ return ret;
+}
+#endif // USE_UPNP
+
+static void ThreadMapPort()
+{
+ bool ok;
+ do {
+ ok = false;
+
+#ifdef USE_UPNP
+ // High priority protocol.
+ if (g_mapport_enabled_protos & MapPortProtoFlag::UPNP) {
+ g_mapport_current_proto = MapPortProtoFlag::UPNP;
+ ok = ProcessUpnp();
+ if (ok) continue;
+ }
+#endif // USE_UPNP
+
+#ifdef USE_NATPMP
+ // Low priority protocol.
+ if (g_mapport_enabled_protos & MapPortProtoFlag::NAT_PMP) {
+ g_mapport_current_proto = MapPortProtoFlag::NAT_PMP;
+ ok = ProcessNatpmp();
+ if (ok) continue;
+ }
+#endif // USE_NATPMP
+
+ g_mapport_current_proto = MapPortProtoFlag::NONE;
+ if (g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ return;
+ }
+
+ } while (ok || g_mapport_interrupt.sleep_for(PORT_MAPPING_RETRY_PERIOD));
+}
+
+void StartThreadMapPort()
+{
+ if (!g_mapport_thread.joinable()) {
+ assert(!g_mapport_interrupt);
+ g_mapport_thread = std::thread(std::bind(&TraceThread<void (*)()>, "mapport", &ThreadMapPort));
+ }
+}
+
+static void DispatchMapPort()
+{
+ if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ return;
+ }
+
+ if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos != MapPortProtoFlag::NONE) {
+ StartThreadMapPort();
+ return;
+ }
+
+ if (g_mapport_current_proto != MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ InterruptMapPort();
+ StopMapPort();
+ return;
+ }
+
+ if (g_mapport_enabled_protos & g_mapport_current_proto) {
+ // Enabling another protocol does not cause switching from the currently used one.
+ return;
+ }
+
+ assert(g_mapport_thread.joinable());
+ assert(!g_mapport_interrupt);
+ // Interrupt a protocol-specific loop in the ThreadUpnp() or in the ThreadNatpmp()
+ // to force trying the next protocol in the ThreadMapPort() loop.
+ g_mapport_interrupt();
+}
+
+static void MapPortProtoSetEnabled(MapPortProtoFlag proto, bool enabled)
+{
+ if (enabled) {
+ g_mapport_enabled_protos |= proto;
+ } else {
+ g_mapport_enabled_protos &= ~proto;
+ }
+}
+
+void StartMapPort(bool use_upnp, bool use_natpmp)
+{
+ MapPortProtoSetEnabled(MapPortProtoFlag::UPNP, use_upnp);
+ MapPortProtoSetEnabled(MapPortProtoFlag::NAT_PMP, use_natpmp);
+ DispatchMapPort();
+}
+
+void InterruptMapPort()
+{
+ g_mapport_enabled_protos = MapPortProtoFlag::NONE;
+ if (g_mapport_thread.joinable()) {
+ g_mapport_interrupt();
+ }
+}
+
+void StopMapPort()
+{
+ if (g_mapport_thread.joinable()) {
+ g_mapport_thread.join();
+ g_mapport_interrupt.reset();
+ }
+}
+
+#else // #if defined(USE_NATPMP) || defined(USE_UPNP)
+void StartMapPort(bool use_upnp, bool use_natpmp)
+{
+ // Intentionally left blank.
+}
+void InterruptMapPort()
+{
+ // Intentionally left blank.
+}
+void StopMapPort()
+{
+ // Intentionally left blank.
+}
+#endif // #if defined(USE_NATPMP) || defined(USE_UPNP)
diff --git a/src/mapport.h b/src/mapport.h
new file mode 100644
index 0000000000..279d65167f
--- /dev/null
+++ b/src/mapport.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_MAPPORT_H
+#define BITCOIN_MAPPORT_H
+
+#ifdef USE_UPNP
+static constexpr bool DEFAULT_UPNP = USE_UPNP;
+#else
+static constexpr bool DEFAULT_UPNP = false;
+#endif // USE_UPNP
+
+#ifdef USE_NATPMP
+static constexpr bool DEFAULT_NATPMP = USE_NATPMP;
+#else
+static constexpr bool DEFAULT_NATPMP = false;
+#endif // USE_NATPMP
+
+enum MapPortProtoFlag : unsigned int {
+ NONE = 0x00,
+ UPNP = 0x01,
+ NAT_PMP = 0x02,
+};
+
+void StartMapPort(bool use_upnp, bool use_natpmp);
+void InterruptMapPort();
+void StopMapPort();
+
+#endif // BITCOIN_MAPPORT_H
diff --git a/src/net.cpp b/src/net.cpp
index 6050e1354c..4f74bbede4 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -33,15 +33,6 @@
#include <poll.h>
#endif
-#ifdef USE_UPNP
-#include <miniupnpc/miniupnpc.h>
-#include <miniupnpc/upnpcommands.h>
-#include <miniupnpc/upnperrors.h>
-// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
-// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
-static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed");
-#endif
-
#include <algorithm>
#include <cstdint>
#include <unordered_map>
@@ -507,9 +498,9 @@ void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNet
}
}
-std::string CNode::ConnectionTypeAsString() const
+std::string ConnectionTypeAsString(ConnectionType conn_type)
{
- switch (m_conn_type) {
+ switch (conn_type) {
case ConnectionType::INBOUND:
return "inbound";
case ConnectionType::MANUAL:
@@ -601,7 +592,6 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
}
X(m_permissionFlags);
if (m_tx_relay != nullptr) {
- LOCK(m_tx_relay->cs_feeFilter);
stats.minFeeFilter = m_tx_relay->minFeeFilter;
} else {
stats.minFeeFilter = 0;
@@ -627,7 +617,7 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
CService addrLocalUnlocked = GetAddrLocal();
stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : "";
- stats.m_conn_type_string = ConnectionTypeAsString();
+ X(m_conn_type);
}
#undef X
@@ -1560,121 +1550,6 @@ void CConnman::WakeMessageHandler()
condMsgProc.notify_one();
}
-
-
-
-
-
-#ifdef USE_UPNP
-static CThreadInterrupt g_upnp_interrupt;
-static std::thread g_upnp_thread;
-static void ThreadMapPort()
-{
- std::string port = strprintf("%u", GetListenPort());
- const char * multicastif = nullptr;
- const char * minissdpdpath = nullptr;
- struct UPNPDev * devlist = nullptr;
- char lanaddr[64];
-
- int error = 0;
-#if MINIUPNPC_API_VERSION < 14
- devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
-#else
- devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
-#endif
-
- struct UPNPUrls urls;
- struct IGDdatas data;
- int r;
-
- r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
- if (r == 1)
- {
- if (fDiscover) {
- char externalIPAddress[40];
- r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
- if (r != UPNPCOMMAND_SUCCESS) {
- LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
- } else {
- if (externalIPAddress[0]) {
- CNetAddr resolved;
- if (LookupHost(externalIPAddress, resolved, false)) {
- LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString());
- AddLocal(resolved, LOCAL_UPNP);
- }
- } else {
- LogPrintf("UPnP: GetExternalIPAddress failed.\n");
- }
- }
- }
-
- std::string strDesc = PACKAGE_NAME " " + FormatFullVersion();
-
- do {
- r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
-
- if (r != UPNPCOMMAND_SUCCESS) {
- LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r));
- } else {
- LogPrintf("UPnP Port Mapping successful.\n");
- }
- } while (g_upnp_interrupt.sleep_for(std::chrono::minutes(20)));
-
- r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
- LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
- freeUPNPDevlist(devlist); devlist = nullptr;
- FreeUPNPUrls(&urls);
- } else {
- LogPrintf("No valid UPnP IGDs found\n");
- freeUPNPDevlist(devlist); devlist = nullptr;
- if (r != 0)
- FreeUPNPUrls(&urls);
- }
-}
-
-void StartMapPort()
-{
- if (!g_upnp_thread.joinable()) {
- assert(!g_upnp_interrupt);
- g_upnp_thread = std::thread((std::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)));
- }
-}
-
-void InterruptMapPort()
-{
- if(g_upnp_thread.joinable()) {
- g_upnp_interrupt();
- }
-}
-
-void StopMapPort()
-{
- if(g_upnp_thread.joinable()) {
- g_upnp_thread.join();
- g_upnp_interrupt.reset();
- }
-}
-
-#else
-void StartMapPort()
-{
- // Intentionally left blank.
-}
-void InterruptMapPort()
-{
- // Intentionally left blank.
-}
-void StopMapPort()
-{
- // Intentionally left blank.
-}
-#endif
-
-
-
-
-
-
void CConnman::ThreadDNSAddressSeed()
{
FastRandomContext rng;
diff --git a/src/net.h b/src/net.h
index 2973ddd0b9..4f1a6b89a9 100644
--- a/src/net.h
+++ b/src/net.h
@@ -67,12 +67,6 @@ static const int MAX_BLOCK_RELAY_ONLY_CONNECTIONS = 2;
static const int MAX_FEELER_CONNECTIONS = 1;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
-/** -upnp default */
-#ifdef USE_UPNP
-static const bool DEFAULT_UPNP = USE_UPNP;
-#else
-static const bool DEFAULT_UPNP = false;
-#endif
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The default for -maxuploadtarget. 0 = Unlimited */
@@ -180,10 +174,9 @@ enum class ConnectionType {
ADDR_FETCH,
};
+/** Convert ConnectionType enum to a string value */
+std::string ConnectionTypeAsString(ConnectionType conn_type);
void Discover();
-void StartMapPort();
-void InterruptMapPort();
-void StopMapPort();
uint16_t GetListenPort();
enum
@@ -191,7 +184,7 @@ enum
LOCAL_NONE, // unknown
LOCAL_IF, // address a local interface listens on
LOCAL_BIND, // address explicit bound to
- LOCAL_UPNP, // address reported by UPnP
+ LOCAL_MAPPED, // address reported by UPnP or NAT-PMP
LOCAL_MANUAL, // address explicitly specified (-externalip=)
LOCAL_MAX
@@ -273,11 +266,10 @@ public:
// Network the peer connected through
Network m_network;
uint32_t m_mapped_as;
- std::string m_conn_type_string;
+ ConnectionType m_conn_type;
};
-
/** Transport protocol agnostic message container.
* Ideally it should only contain receive time, payload,
* command and size.
@@ -402,7 +394,7 @@ public:
std::unique_ptr<TransportDeserializer> m_deserializer;
std::unique_ptr<TransportSerializer> m_serializer;
- // socket
+ NetPermissionFlags m_permissionFlags{PF_NONE};
std::atomic<ServiceFlags> nServices{NODE_NONE};
SOCKET hSocket GUARDED_BY(cs_hSocket);
/** Total size of all vSendMsg entries */
@@ -536,11 +528,6 @@ public:
*/
Network ConnectedThroughNetwork() const;
-protected:
- mapMsgCmdSize mapSendBytesPerMsgCmd GUARDED_BY(cs_vSend);
- mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
-
-public:
// We selected peer as (compact blocks) high-bandwidth peer (BIP152)
std::atomic<bool> m_bip152_highbandwidth_to{false};
// Peer selected us as (compact blocks) high-bandwidth peer (BIP152)
@@ -573,9 +560,8 @@ public:
std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
std::chrono::microseconds nNextInvSend{0};
- RecursiveMutex cs_feeFilter;
- // Minimum fee rate with which to filter inv's to this node
- CAmount minFeeFilter GUARDED_BY(cs_feeFilter){0};
+ /** Minimum fee rate with which to filter inv's to this node */
+ std::atomic<CAmount> minFeeFilter{0};
CAmount lastSentFeeFilter{0};
int64_t nextSendTimeFeeFilter{0};
};
@@ -613,44 +599,6 @@ public:
CNode(const CNode&) = delete;
CNode& operator=(const CNode&) = delete;
-private:
- const NodeId id;
- const uint64_t nLocalHostNonce;
- const ConnectionType m_conn_type;
- std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
-
- //! Services offered to this peer.
- //!
- //! This is supplied by the parent CConnman during peer connection
- //! (CConnman::ConnectNode()) from its attribute of the same name.
- //!
- //! This is const because there is no protocol defined for renegotiating
- //! services initially offered to a peer. The set of local services we
- //! offer should not change after initialization.
- //!
- //! An interesting example of this is NODE_NETWORK and initial block
- //! download: a node which starts up from scratch doesn't have any blocks
- //! to serve, but still advertises NODE_NETWORK because it will eventually
- //! fulfill this role after IBD completes. P2P code is written in such a
- //! way that it can gracefully handle peers who don't make good on their
- //! service advertisements.
- const ServiceFlags nLocalServices;
-
- NetPermissionFlags m_permissionFlags{ PF_NONE };
- std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
-
- mutable RecursiveMutex cs_addrName;
- std::string addrName GUARDED_BY(cs_addrName);
-
- // Our address, as reported by the peer
- CService addrLocal GUARDED_BY(cs_addrLocal);
- mutable RecursiveMutex cs_addrLocal;
-
- //! Whether this peer is an inbound onion, e.g. connected via our Tor onion service.
- const bool m_inbound_onion{false};
-
-public:
-
NodeId GetId() const {
return id;
}
@@ -701,8 +649,6 @@ public:
nRefCount--;
}
-
-
void AddAddressKnown(const CAddress& _addr)
{
assert(m_addr_known);
@@ -734,7 +680,6 @@ public:
}
}
-
void AddKnownTx(const uint256& hash)
{
if (m_tx_relay != nullptr) {
@@ -765,10 +710,48 @@ public:
//! Sets the addrName only if it was not previously set
void MaybeSetAddrName(const std::string& addrNameIn);
- std::string ConnectionTypeAsString() const;
+ std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); }
/** Whether this peer is an inbound onion, e.g. connected via our Tor onion service. */
bool IsInboundOnion() const { return m_inbound_onion; }
+
+private:
+ const NodeId id;
+ const uint64_t nLocalHostNonce;
+ const ConnectionType m_conn_type;
+ std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
+
+ //! Services offered to this peer.
+ //!
+ //! This is supplied by the parent CConnman during peer connection
+ //! (CConnman::ConnectNode()) from its attribute of the same name.
+ //!
+ //! This is const because there is no protocol defined for renegotiating
+ //! services initially offered to a peer. The set of local services we
+ //! offer should not change after initialization.
+ //!
+ //! An interesting example of this is NODE_NETWORK and initial block
+ //! download: a node which starts up from scratch doesn't have any blocks
+ //! to serve, but still advertises NODE_NETWORK because it will eventually
+ //! fulfill this role after IBD completes. P2P code is written in such a
+ //! way that it can gracefully handle peers who don't make good on their
+ //! service advertisements.
+ const ServiceFlags nLocalServices;
+
+ std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
+
+ mutable RecursiveMutex cs_addrName;
+ std::string addrName GUARDED_BY(cs_addrName);
+
+ // Our address, as reported by the peer
+ CService addrLocal GUARDED_BY(cs_addrLocal);
+ mutable RecursiveMutex cs_addrLocal;
+
+ //! Whether this peer is an inbound onion, e.g. connected via our Tor onion service.
+ const bool m_inbound_onion{false};
+
+ mapMsgCmdSize mapSendBytesPerMsgCmd GUARDED_BY(cs_vSend);
+ mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
};
/**
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index dc9b051ddd..8f1cb952f2 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3712,7 +3712,6 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
vRecv >> newFeeFilter;
if (MoneyRange(newFeeFilter)) {
if (pfrom.m_tx_relay != nullptr) {
- LOCK(pfrom.m_tx_relay->cs_feeFilter);
pfrom.m_tx_relay->minFeeFilter = newFeeFilter;
}
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId());
@@ -4388,11 +4387,7 @@ bool PeerManager::SendMessages(CNode* pto)
if (fSendTrickle && pto->m_tx_relay->fSendMempool) {
auto vtxinfo = m_mempool.infoAll();
pto->m_tx_relay->fSendMempool = false;
- CFeeRate filterrate;
- {
- LOCK(pto->m_tx_relay->cs_feeFilter);
- filterrate = CFeeRate(pto->m_tx_relay->minFeeFilter);
- }
+ const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
LOCK(pto->m_tx_relay->cs_filter);
@@ -4426,11 +4421,7 @@ bool PeerManager::SendMessages(CNode* pto)
for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) {
vInvTx.push_back(it);
}
- CFeeRate filterrate;
- {
- LOCK(pto->m_tx_relay->cs_feeFilter);
- filterrate = CFeeRate(pto->m_tx_relay->minFeeFilter);
- }
+ const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
// Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
// A heap is used so that not all items need sorting if only a few are being sent.
CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool, state.m_wtxid_relay);
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index b1f9d32d34..85e46fd373 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -1068,15 +1068,24 @@ CSubNet::CSubNet(const CNetAddr& addr, const CNetAddr& mask) : CSubNet()
CSubNet::CSubNet(const CNetAddr& addr) : CSubNet()
{
- valid = addr.IsIPv4() || addr.IsIPv6();
- if (!valid) {
+ switch (addr.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ valid = true;
+ assert(addr.m_addr.size() <= sizeof(netmask));
+ memset(netmask, 0xFF, addr.m_addr.size());
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ valid = true;
+ break;
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
return;
}
- assert(addr.m_addr.size() <= sizeof(netmask));
-
- memset(netmask, 0xFF, addr.m_addr.size());
-
network = addr;
}
@@ -1088,6 +1097,21 @@ bool CSubNet::Match(const CNetAddr &addr) const
{
if (!valid || !addr.IsValid() || network.m_net != addr.m_net)
return false;
+
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ case NET_INTERNAL:
+ return addr == network;
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ return false;
+ }
+
assert(network.m_addr.size() == addr.m_addr.size());
for (size_t x = 0; x < addr.m_addr.size(); ++x) {
if ((addr.m_addr[x] & netmask[x]) != network.m_addr[x]) {
@@ -1099,18 +1123,35 @@ bool CSubNet::Match(const CNetAddr &addr) const
std::string CSubNet::ToString() const
{
- assert(network.m_addr.size() <= sizeof(netmask));
+ std::string suffix;
- uint8_t cidr = 0;
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6: {
+ assert(network.m_addr.size() <= sizeof(netmask));
- for (size_t i = 0; i < network.m_addr.size(); ++i) {
- if (netmask[i] == 0x00) {
- break;
+ uint8_t cidr = 0;
+
+ for (size_t i = 0; i < network.m_addr.size(); ++i) {
+ if (netmask[i] == 0x00) {
+ break;
+ }
+ cidr += NetmaskBits(netmask[i]);
}
- cidr += NetmaskBits(netmask[i]);
+
+ suffix = strprintf("/%u", cidr);
+ break;
+ }
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ break;
}
- return network.ToString() + strprintf("/%u", cidr);
+ return network.ToString() + suffix;
}
bool CSubNet::IsValid() const
@@ -1120,7 +1161,19 @@ bool CSubNet::IsValid() const
bool CSubNet::SanityCheck() const
{
- if (!(network.IsIPv4() || network.IsIPv6())) return false;
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ return true;
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ return false;
+ }
for (size_t x = 0; x < network.m_addr.size(); ++x) {
if (network.m_addr[x] & ~netmask[x]) return false;
diff --git a/src/netaddress.h b/src/netaddress.h
index cf878fe374..b9eade7fd5 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -462,11 +462,33 @@ class CSubNet
bool SanityCheck() const;
public:
+ /**
+ * Construct an invalid subnet (empty, `Match()` always returns false).
+ */
CSubNet();
+
+ /**
+ * Construct from a given network start and number of bits (CIDR mask).
+ * @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is
+ * created.
+ * @param[in] mask CIDR mask, must be in [0, 32] for IPv4 addresses and in [0, 128] for
+ * IPv6 addresses. Otherwise an invalid subnet is created.
+ */
CSubNet(const CNetAddr& addr, uint8_t mask);
+
+ /**
+ * Construct from a given network start and mask.
+ * @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is
+ * created.
+ * @param[in] mask Network mask, must be of the same type as `addr` and not contain 0-bits
+ * followed by 1-bits. Otherwise an invalid subnet is created.
+ */
CSubNet(const CNetAddr& addr, const CNetAddr& mask);
- //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
+ /**
+ * Construct a single-host subnet.
+ * @param[in] addr The sole address to be contained in the subnet, can also be non-IPv[46].
+ */
explicit CSubNet(const CNetAddr& addr);
bool Match(const CNetAddr &addr) const;
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 317a5c7cbe..e07eaa33d8 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -12,6 +12,7 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
+#include <mapport.h>
#include <net.h>
#include <net_processing.h>
#include <netaddress.h>
@@ -93,15 +94,7 @@ public:
}
}
bool shutdownRequested() override { return ShutdownRequested(); }
- void mapPort(bool use_upnp) override
- {
- if (use_upnp) {
- StartMapPort();
- } else {
- InterruptMapPort();
- StopMapPort();
- }
- }
+ void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
size_t getNodeCount(CConnman::NumConnections flags) override
{
diff --git a/src/outputtype.cpp b/src/outputtype.cpp
index e978852826..d96fb282c5 100644
--- a/src/outputtype.cpp
+++ b/src/outputtype.cpp
@@ -19,8 +19,6 @@ static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy";
static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit";
static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32";
-const std::array<OutputType, 3> OUTPUT_TYPES = {OutputType::LEGACY, OutputType::P2SH_SEGWIT, OutputType::BECH32};
-
bool ParseOutputType(const std::string& type, OutputType& output_type)
{
if (type == OUTPUT_TYPE_STRING_LEGACY) {
diff --git a/src/outputtype.h b/src/outputtype.h
index 57316b92d6..88422e5824 100644
--- a/src/outputtype.h
+++ b/src/outputtype.h
@@ -20,7 +20,11 @@ enum class OutputType {
BECH32,
};
-extern const std::array<OutputType, 3> OUTPUT_TYPES;
+static constexpr auto OUTPUT_TYPES = std::array{
+ OutputType::LEGACY,
+ OutputType::P2SH_SEGWIT,
+ OutputType::BECH32,
+};
[[nodiscard]] bool ParseOutputType(const std::string& str, OutputType& output_type);
const std::string& FormatOutputType(OutputType type);
diff --git a/src/policy/fees.h b/src/policy/fees.h
index dd9f530c99..c444d71a31 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -11,6 +11,7 @@
#include <random.h>
#include <sync.h>
+#include <array>
#include <map>
#include <memory>
#include <string>
@@ -25,9 +26,15 @@ class TxConfirmStats;
/* Identifier for each of the 3 different TxConfirmStats which will track
* history over different time horizons. */
enum class FeeEstimateHorizon {
- SHORT_HALFLIFE = 0,
- MED_HALFLIFE = 1,
- LONG_HALFLIFE = 2
+ SHORT_HALFLIFE,
+ MED_HALFLIFE,
+ LONG_HALFLIFE,
+};
+
+static constexpr auto ALL_FEE_ESTIMATE_HORIZONS = std::array{
+ FeeEstimateHorizon::SHORT_HALFLIFE,
+ FeeEstimateHorizon::MED_HALFLIFE,
+ FeeEstimateHorizon::LONG_HALFLIFE,
};
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon);
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 8b1308da5d..bb444f22b3 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -11,7 +11,6 @@
#include <wallet/wallet.h>
#include <algorithm>
-#include <typeinfo>
#include <QFont>
#include <QDebug>
@@ -82,8 +81,9 @@ public:
{
for (const auto& address : wallet.getAddresses())
{
- if (pk_hash_only && address.dest.type() != typeid(PKHash))
+ if (pk_hash_only && !std::holds_alternative<PKHash>(address.dest)) {
continue;
+ }
AddressTableEntry::Type addressType = translateTransactionType(
QString::fromStdString(address.purpose), address.is_mine);
cachedAddressTable.append(AddressTableEntry(addressType,
@@ -261,7 +261,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
} else if(index.column() == Address) {
CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
// Refuse to set invalid address, set error status and return false
- if(boost::get<CNoDestination>(&newAddress))
+ if(std::get_if<CNoDestination>(&newAddress))
{
editStatus = INVALID_ADDRESS;
return false;
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 75fa970d37..08abef7866 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -455,7 +455,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
else if(ExtractDestination(out.txout.scriptPubKey, address))
{
CPubKey pubkey;
- PKHash *pkhash = boost::get<PKHash>(&address);
+ PKHash* pkhash = std::get_if<PKHash>(&address);
if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey, ToKeyID(*pkhash), pubkey))
{
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index d8112117cc..bce578a158 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -1077,14 +1077,17 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="label_23">
+ <widget class="QLabel" name="peerConnectionTypeLabel">
+ <property name="toolTip">
+ <string>The type of peer connection:&lt;ul&gt;&lt;li&gt;Inbound: initiated by peer&lt;/li&gt;&lt;li&gt;Outbound Full Relay: default&lt;/li&gt;&lt;li&gt;Outbound Block Relay: does not relay transactions or addresses&lt;/li&gt;&lt;li&gt;Outbound Manual: added using RPC %1 or %2/%3 configuration options&lt;/li&gt;&lt;li&gt;Outbound Feeler: short-lived, for testing addresses&lt;/li&gt;&lt;li&gt;Outbound Address Fetch: short-lived, for soliciting addresses&lt;/li&gt;&lt;/ul&gt;</string>
+ </property>
<property name="text">
- <string>Direction</string>
+ <string>Connection Type</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QLabel" name="peerDirection">
+ <widget class="QLabel" name="peerConnectionType">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 88944a58a6..8181cc47e2 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -260,6 +260,16 @@
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="mapPortNatpmp">
+ <property name="toolTip">
+ <string>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</string>
+ </property>
+ <property name="text">
+ <string>Map port using NA&amp;T-PMP</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QCheckBox" name="allowIncoming">
<property name="toolTip">
<string>Accept connections from outside.</string>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 8205b0506c..430ecd322f 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -764,6 +764,19 @@ QString NetworkToQString(Network net)
assert(false);
}
+QString ConnectionTypeToQString(ConnectionType conn_type)
+{
+ switch (conn_type) {
+ case ConnectionType::INBOUND: return QObject::tr("Inbound");
+ case ConnectionType::OUTBOUND_FULL_RELAY: return QObject::tr("Outbound Full Relay");
+ case ConnectionType::BLOCK_RELAY: return QObject::tr("Outbound Block Relay");
+ case ConnectionType::MANUAL: return QObject::tr("Outbound Manual");
+ case ConnectionType::FEELER: return QObject::tr("Outbound Feeler");
+ case ConnectionType::ADDR_FETCH: return QObject::tr("Outbound Address Fetch");
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+}
+
QString formatDurationStr(int secs)
{
QStringList strList;
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 4bef13efb5..c471b888f7 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -7,17 +7,18 @@
#include <amount.h>
#include <fs.h>
+#include <net.h>
#include <netaddress.h>
#include <QEvent>
#include <QHeaderView>
#include <QItemDelegate>
+#include <QLabel>
#include <QMessageBox>
#include <QObject>
#include <QProgressBar>
#include <QString>
#include <QTableView>
-#include <QLabel>
class QValidatedLineEdit;
class SendCoinsRecipient;
@@ -228,6 +229,9 @@ namespace GUIUtil
/** Convert enum Network to QString */
QString NetworkToQString(Network net);
+ /** Convert enum ConnectionType to QString */
+ QString ConnectionTypeToQString(ConnectionType conn_type);
+
/** Convert seconds into a QString with days, hours, mins, secs */
QString formatDurationStr(int secs);
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 468008693a..416b9c83c9 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -24,6 +24,7 @@
#include <QIntValidator>
#include <QLocale>
#include <QMessageBox>
+#include <QSettings>
#include <QSystemTrayIcon>
#include <QTimer>
@@ -50,6 +51,13 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
#ifndef USE_UPNP
ui->mapPortUpnp->setEnabled(false);
#endif
+#ifndef USE_NATPMP
+ ui->mapPortNatpmp->setEnabled(false);
+#endif
+ connect(this, &QDialog::accepted, [this](){
+ QSettings settings;
+ model->node().mapPort(settings.value("fUseUPnP").toBool(), settings.value("fUseNatpmp").toBool());
+ });
ui->proxyIp->setEnabled(false);
ui->proxyPort->setEnabled(false);
@@ -214,6 +222,7 @@ void OptionsDialog::setMapper()
/* Network */
mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
+ mapper->addMapping(ui->mapPortNatpmp, OptionsModel::MapPortNatpmp);
mapper->addMapping(ui->allowIncoming, OptionsModel::Listen);
mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 152de6decb..1e0391a35c 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -13,11 +13,12 @@
#include <qt/guiutil.h>
#include <interfaces/node.h>
-#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
+#include <mapport.h>
#include <net.h>
#include <netbase.h>
-#include <txdb.h> // for -dbcache defaults
+#include <txdb.h> // for -dbcache defaults
#include <util/string.h>
+#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
#include <QDebug>
#include <QSettings>
@@ -123,6 +124,13 @@ void OptionsModel::Init(bool resetSettings)
if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
addOverriddenOption("-upnp");
+ if (!settings.contains("fUseNatpmp")) {
+ settings.setValue("fUseNatpmp", DEFAULT_NATPMP);
+ }
+ if (!gArgs.SoftSetBoolArg("-natpmp", settings.value("fUseNatpmp").toBool())) {
+ addOverriddenOption("-natpmp");
+ }
+
if (!settings.contains("fListen"))
settings.setValue("fListen", DEFAULT_LISTEN);
if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool()))
@@ -282,7 +290,13 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return settings.value("fUseUPnP");
#else
return false;
-#endif
+#endif // USE_UPNP
+ case MapPortNatpmp:
+#ifdef USE_NATPMP
+ return settings.value("fUseNatpmp");
+#else
+ return false;
+#endif // USE_NATPMP
case MinimizeOnClose:
return fMinimizeOnClose;
@@ -354,7 +368,9 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break;
case MapPortUPnP: // core option - can be changed on-the-fly
settings.setValue("fUseUPnP", value.toBool());
- node().mapPort(value.toBool());
+ break;
+ case MapPortNatpmp: // core option - can be changed on-the-fly
+ settings.setValue("fUseNatpmp", value.toBool());
break;
case MinimizeOnClose:
fMinimizeOnClose = value.toBool();
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index f1929a5e06..f7171951a1 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -48,6 +48,7 @@ public:
ShowTrayIcon, // bool
MinimizeToTray, // bool
MapPortUPnP, // bool
+ MapPortNatpmp, // bool
MinimizeOnClose, // bool
ProxyUse, // bool
ProxyIP, // QString
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index b02e4076e2..bad81d894c 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -185,6 +185,11 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
default:
return QVariant();
}
+ } else if (role == StatsRole) {
+ switch (index.column()) {
+ case NetNodeId: return QVariant::fromValue(rec);
+ default: return QVariant();
+ }
}
return QVariant();
@@ -220,11 +225,6 @@ QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent
return QModelIndex();
}
-const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx)
-{
- return priv->index(idx);
-}
-
void PeerTableModel::refresh()
{
Q_EMIT layoutAboutToBeChanged();
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index 61a0132e00..7bff239507 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -28,6 +28,7 @@ struct CNodeCombinedStats {
CNodeStateStats nodeStateStats;
bool fNodeStateStatsAvailable;
};
+Q_DECLARE_METATYPE(CNodeCombinedStats*)
class NodeLessThan
{
@@ -52,7 +53,6 @@ class PeerTableModel : public QAbstractTableModel
public:
explicit PeerTableModel(interfaces::Node& node, QObject* parent);
~PeerTableModel();
- const CNodeCombinedStats *getNodeStats(int idx);
int getRowByNodeId(NodeId nodeid);
void startAutoRefresh();
void stopAutoRefresh();
@@ -67,6 +67,10 @@ public:
Subversion = 6
};
+ enum {
+ StatsRole = Qt::UserRole,
+ };
+
/** @name Methods overridden from QAbstractTableModel
@{*/
int rowCount(const QModelIndex &parent) const override;
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 61f47e3ad3..df98dbbc99 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -463,6 +463,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir"));
ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME));
+ ui->peerConnectionTypeLabel->setToolTip(ui->peerConnectionTypeLabel->toolTip().arg("addnode").arg(QString(nonbreaking_hyphen) + "addnode").arg(QString(nonbreaking_hyphen) + "connect"));
if (platformStyle->getImagesOnButtons()) {
ui->openDebugLogfileButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
@@ -1021,11 +1022,9 @@ void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
void RPCConsole::peerLayoutAboutToChange()
{
- QModelIndexList selected = ui->peerWidget->selectionModel()->selectedIndexes();
cachedNodeids.clear();
- for(int i = 0; i < selected.size(); i++)
- {
- const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.at(i).row());
+ for (const QModelIndex& peer : GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId)) {
+ const auto stats = peer.data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>();
cachedNodeids.append(stats->nodeStats.nodeid);
}
}
@@ -1084,15 +1083,13 @@ void RPCConsole::peerLayoutChanged()
void RPCConsole::updateDetailWidget()
{
- QModelIndexList selected_rows;
- auto selection_model = ui->peerWidget->selectionModel();
- if (selection_model) selected_rows = selection_model->selectedRows();
- if (!clientModel || !clientModel->getPeerTableModel() || selected_rows.size() != 1) {
+ const QList<QModelIndex> selected_peers = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
+ if (!clientModel || !clientModel->getPeerTableModel() || selected_peers.size() != 1) {
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
return;
}
- const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected_rows.first().row());
+ const auto stats = selected_peers.first().data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>();
// update the detail ui with latest node information
QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
peerAddrDetails += tr("(peer id: %1)").arg(QString::number(stats->nodeStats.nodeid));
@@ -1111,7 +1108,7 @@ void RPCConsole::updateDetailWidget()
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
- ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
+ ui->peerConnectionType->setText(GUIUtil::ConnectionTypeToQString(stats->nodeStats.m_conn_type));
ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network));
if (stats->nodeStats.m_permissionFlags == PF_NONE) {
ui->peerPermissions->setText(tr("N/A"));
@@ -1205,19 +1202,9 @@ void RPCConsole::banSelectedNode(int bantime)
if (!clientModel)
return;
- // Get selected peer addresses
- QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
- for(int i = 0; i < nodes.count(); i++)
- {
- // Get currently selected peer address
- NodeId id = nodes.at(i).data().toLongLong();
-
- // Get currently selected peer address
- int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id);
- if (detailNodeRow < 0) return;
-
+ for (const QModelIndex& peer : GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId)) {
// Find possible nodes, ban it and clear the selected node
- const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
+ const auto stats = peer.data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>();
if (stats) {
m_node.ban(stats->nodeStats.addr, bantime);
m_node.disconnectByAddress(stats->nodeStats.addr);
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 4835dd7954..6c110f0688 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -120,7 +120,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- const PKHash* pkhash = boost::get<PKHash>(&destination);
+ const PKHash* pkhash = std::get_if<PKHash>(&destination);
if (!pkhash) {
ui->addressIn_SM->setValid(false);
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 06108f1d07..77fec93f0f 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -123,7 +123,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
continue;
}
- if (!boost::get<CNoDestination>(&wtx.txout_address[nOut]))
+ if (!std::get_if<CNoDestination>(&wtx.txout_address[nOut]))
{
// Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress;
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 965b278bfa..52e033d0cc 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1160,7 +1160,7 @@ static RPCHelpMan estimaterawfee()
UniValue result(UniValue::VOBJ);
- for (const FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) {
+ for (const FeeEstimateHorizon horizon : ALL_FEE_ESTIMATE_HORIZONS) {
CFeeRate feeRate;
EstimationResult buckets;
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index a96d9d774b..cfca8b4ad4 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -129,9 +129,6 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},
{RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"},
{RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"},
- {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
- "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
- "best capture connection behaviors."},
{RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"},
{RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"},
{RPCResult::Type::NUM, "synced_blocks", "The last block we have in common with this peer"},
@@ -157,6 +154,9 @@ static RPCHelpMan getpeerinfo()
"Only known message types can appear as keys in the object and all bytes received\n"
"of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
}},
+ {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
+ "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
+ "best capture connection behaviors."},
}},
}},
},
@@ -250,7 +250,7 @@ static RPCHelpMan getpeerinfo()
recvPerMsgCmd.pushKV(i.first, i.second);
}
obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd);
- obj.pushKV("connection_type", stats.m_conn_type_string);
+ obj.pushKV("connection_type", ConnectionTypeAsString(stats.m_conn_type));
ret.push_back(obj);
}
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index e377a80fbd..31072114da 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -209,7 +209,7 @@ CTxDestination AddAndGetMultisigDestination(const int required, const std::vecto
return dest;
}
-class DescribeAddressVisitor : public boost::static_visitor<UniValue>
+class DescribeAddressVisitor
{
public:
explicit DescribeAddressVisitor() {}
@@ -267,7 +267,7 @@ public:
UniValue DescribeAddress(const CTxDestination& dest)
{
- return boost::apply_visitor(DescribeAddressVisitor(), dest);
+ return std::visit(DescribeAddressVisitor(), dest);
}
unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target)
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index e5ba9ba6d2..9e4b8a9dd6 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -565,7 +565,7 @@ public:
Optional<OutputType> GetOutputType() const override
{
- switch (m_destination.which()) {
+ switch (m_destination.index()) {
case 1 /* PKHash */:
case 2 /* ScriptHash */: return OutputType::LEGACY;
case 3 /* WitnessV0ScriptHash */:
@@ -593,7 +593,7 @@ public:
{
CTxDestination dest;
ExtractDestination(m_script, dest);
- switch (dest.which()) {
+ switch (dest.index()) {
case 1 /* PKHash */:
case 2 /* ScriptHash */: return OutputType::LEGACY;
case 3 /* WitnessV0ScriptHash */:
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp
index 26d081f853..9781ec32af 100644
--- a/src/script/signingprovider.cpp
+++ b/src/script/signingprovider.cpp
@@ -179,18 +179,18 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination&
{
// Only supports destinations which map to single public keys, i.e. P2PKH,
// P2WPKH, and P2SH-P2WPKH.
- if (auto id = boost::get<PKHash>(&dest)) {
+ if (auto id = std::get_if<PKHash>(&dest)) {
return ToKeyID(*id);
}
- if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) {
+ if (auto witness_id = std::get_if<WitnessV0KeyHash>(&dest)) {
return ToKeyID(*witness_id);
}
- if (auto script_hash = boost::get<ScriptHash>(&dest)) {
+ if (auto script_hash = std::get_if<ScriptHash>(&dest)) {
CScript script;
CScriptID script_id(*script_hash);
CTxDestination inner_dest;
if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {
- if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) {
+ if (auto inner_witness_id = std::get_if<WitnessV0KeyHash>(&inner_dest)) {
return ToKeyID(*inner_witness_id);
}
}
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 57d68c7ce9..7967c01858 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -261,9 +261,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::v
return true;
}
-namespace
-{
-class CScriptVisitor : public boost::static_visitor<CScript>
+namespace {
+class CScriptVisitor
{
public:
CScript operator()(const CNoDestination& dest) const
@@ -300,7 +299,7 @@ public:
CScript GetScriptForDestination(const CTxDestination& dest)
{
- return boost::apply_visitor(CScriptVisitor(), dest);
+ return std::visit(CScriptVisitor(), dest);
}
CScript GetScriptForRawPubKey(const CPubKey& pubKey)
@@ -320,5 +319,5 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
}
bool IsValidDestination(const CTxDestination& dest) {
- return dest.which() != 0;
+ return dest.index() != 0;
}
diff --git a/src/script/standard.h b/src/script/standard.h
index 4d1ef61964..d5d87392ad 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -9,10 +9,8 @@
#include <script/interpreter.h>
#include <uint256.h>
-#include <boost/variant.hpp>
-
#include <string>
-
+#include <variant>
static const bool DEFAULT_ACCEPT_DATACARRIER = true;
@@ -211,7 +209,7 @@ struct WitnessUnknown
* (taproot outputs do not require their own type as long as no wallet support exists)
* A CTxDestination is the internal data type encoded in a bitcoin address
*/
-typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
+using CTxDestination = std::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown>;
/** Check whether a CTxDestination is a CNoDestination. */
bool IsValidDestination(const CTxDestination& dest);
diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp
index 4dfb2e3da0..fa4024fc38 100644
--- a/src/test/fuzz/kitchen_sink.cpp
+++ b/src/test/fuzz/kitchen_sink.cpp
@@ -28,12 +28,6 @@ constexpr TransactionError ALL_TRANSACTION_ERROR[] = {
TransactionError::SIGHASH_MISMATCH,
TransactionError::MAX_FEE_EXCEEDED,
};
-
-constexpr FeeEstimateHorizon ALL_FEE_EST_HORIZON[] = {
- FeeEstimateHorizon::SHORT_HALFLIFE,
- FeeEstimateHorizon::MED_HALFLIFE,
- FeeEstimateHorizon::LONG_HALFLIFE,
-};
}; // namespace
// The fuzzing kitchen sink: Fuzzing harness for functions that need to be
@@ -48,7 +42,7 @@ FUZZ_TARGET(kitchen_sink)
(void)RPCErrorFromTransactionError(transaction_error);
(void)TransactionErrorString(transaction_error);
- (void)StringForFeeEstimateHorizon(fuzzed_data_provider.PickValueInArray(ALL_FEE_EST_HORIZON));
+ (void)StringForFeeEstimateHorizon(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS));
const OutputType output_type = fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES);
const std::string& output_type_string = FormatOutputType(output_type);
diff --git a/src/test/fuzz/muhash.cpp b/src/test/fuzz/muhash.cpp
index 87359c9d39..8f843ca773 100644
--- a/src/test/fuzz/muhash.cpp
+++ b/src/test/fuzz/muhash.cpp
@@ -9,7 +9,7 @@
#include <vector>
-void test_one_input(const std::vector<uint8_t>& buffer)
+FUZZ_TARGET(muhash)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 8a17a4b51b..35cfc5230b 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -66,10 +66,10 @@ FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
}
(void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral<int>());
EstimationResult result;
- (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}), fuzzed_data_provider.ConsumeBool() ? &result : nullptr);
+ (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS), fuzzed_data_provider.ConsumeBool() ? &result : nullptr);
FeeCalculation fee_calculation;
(void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool());
- (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}));
+ (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS));
}
{
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index b6865c5347..58637662c5 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -65,9 +65,8 @@ void fuzz_target(const std::vector<uint8_t>& buffer, const std::string& LIMIT_TO
const bool jump_out_of_ibd{fuzzed_data_provider.ConsumeBool()};
if (jump_out_of_ibd) chainstate.JumpOutOfIbd();
CNode& p2p_node = *ConsumeNodeAsUniquePtr(fuzzed_data_provider).release();
+ FillNode(fuzzed_data_provider, p2p_node);
p2p_node.fSuccessfullyConnected = true;
- p2p_node.nVersion = PROTOCOL_VERSION;
- p2p_node.SetCommonVersion(PROTOCOL_VERSION);
connman.AddTestNode(p2p_node);
g_setup->m_node.peerman->InitializeNode(&p2p_node);
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index fcfa623508..db52da2f7e 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -49,11 +49,10 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages)
for (int i = 0; i < num_peers_to_add; ++i) {
peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release());
CNode& p2p_node = *peers.back();
+ FillNode(fuzzed_data_provider, p2p_node);
p2p_node.fSuccessfullyConnected = true;
p2p_node.fPauseSend = false;
- p2p_node.nVersion = PROTOCOL_VERSION;
- p2p_node.SetCommonVersion(PROTOCOL_VERSION);
g_setup->m_node.peerman->InitializeNode(&p2p_node);
connman.AddTestNode(p2p_node);
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 94c691936e..4e8e501895 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -296,7 +296,7 @@ inline CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcep
}
template <bool ReturnUniquePtr = false>
-auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = nullopt) noexcept
+auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
{
const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegral<NodeId>());
const ServiceFlags local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
@@ -316,6 +316,23 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
}
inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
+inline void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, const std::optional<int32_t>& version_in = std::nullopt) noexcept
+{
+ const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
+ const NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
+ const int32_t version = version_in.value_or(fuzzed_data_provider.ConsumeIntegral<int32_t>());
+ const bool filter_txs = fuzzed_data_provider.ConsumeBool();
+
+ node.nServices = remote_services;
+ node.m_permissionFlags = permission_flags;
+ node.nVersion = version;
+ node.SetCommonVersion(version);
+ if (node.m_tx_relay != nullptr) {
+ LOCK(node.m_tx_relay->cs_filter);
+ node.m_tx_relay->fRelayTxes = filter_txs;
+ }
+}
+
inline void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
{
static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index ac4db3a5b6..66ad7bb5ea 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -226,8 +226,22 @@ BOOST_AUTO_TEST_CASE(subnet_test)
// IPv4 address with IPv6 netmask or the other way around.
BOOST_CHECK(!CSubNet(ResolveIP("1.1.1.1"), ResolveIP("ffff::")).IsValid());
BOOST_CHECK(!CSubNet(ResolveIP("::1"), ResolveIP("255.0.0.0")).IsValid());
- // Can't subnet TOR (or any other non-IPv4 and non-IPv6 network).
- BOOST_CHECK(!CSubNet(ResolveIP("5wyqrzbvrdsumnok.onion"), ResolveIP("255.0.0.0")).IsValid());
+
+ // Create Non-IP subnets.
+
+ const CNetAddr tor_addr{
+ ResolveIP("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")};
+
+ subnet = CSubNet(tor_addr);
+ BOOST_CHECK(subnet.IsValid());
+ BOOST_CHECK_EQUAL(subnet.ToString(), tor_addr.ToString());
+ BOOST_CHECK(subnet.Match(tor_addr));
+ BOOST_CHECK(
+ !subnet.Match(ResolveIP("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion")));
+ BOOST_CHECK(!subnet.Match(ResolveIP("1.2.3.4")));
+
+ BOOST_CHECK(!CSubNet(tor_addr, 200).IsValid());
+ BOOST_CHECK(!CSubNet(tor_addr, ResolveIP("255.0.0.0")).IsValid());
subnet = ResolveSubNet("1.2.3.4/255.255.255.255");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
@@ -442,8 +456,7 @@ BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0"s, ret));
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com"s, ret));
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com\0"s, ret));
- // We only do subnetting for IPv4 and IPv6
- BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion"s, ret));
+ BOOST_CHECK(LookupSubNet("5wyqrzbvrdsumnok.onion"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com\0"s, ret));
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index fb84b7f2ac..366385b619 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -183,23 +183,23 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
s.clear();
s << ToByteVector(pubkey) << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<PKHash>(&address) &&
- *boost::get<PKHash>(&address) == PKHash(pubkey));
+ BOOST_CHECK(std::get_if<PKHash>(&address) &&
+ *std::get_if<PKHash>(&address) == PKHash(pubkey));
// TxoutType::PUBKEYHASH
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<PKHash>(&address) &&
- *boost::get<PKHash>(&address) == PKHash(pubkey));
+ BOOST_CHECK(std::get_if<PKHash>(&address) &&
+ *std::get_if<PKHash>(&address) == PKHash(pubkey));
// TxoutType::SCRIPTHASH
CScript redeemScript(s); // initialize with leftover P2PKH script
s.clear();
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<ScriptHash>(&address) &&
- *boost::get<ScriptHash>(&address) == ScriptHash(redeemScript));
+ BOOST_CHECK(std::get_if<ScriptHash>(&address) &&
+ *std::get_if<ScriptHash>(&address) == ScriptHash(redeemScript));
// TxoutType::MULTISIG
s.clear();
@@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
BOOST_CHECK(ExtractDestination(s, address));
WitnessV0KeyHash keyhash;
CHash160().Write(pubkey).Finalize(keyhash);
- BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash);
+ BOOST_CHECK(std::get_if<WitnessV0KeyHash>(&address) && *std::get_if<WitnessV0KeyHash>(&address) == keyhash);
// TxoutType::WITNESS_V0_SCRIPTHASH
s.clear();
@@ -225,7 +225,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin());
s << OP_0 << ToByteVector(scripthash);
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<WitnessV0ScriptHash>(&address) && *boost::get<WitnessV0ScriptHash>(&address) == scripthash);
+ BOOST_CHECK(std::get_if<WitnessV0ScriptHash>(&address) && *std::get_if<WitnessV0ScriptHash>(&address) == scripthash);
// TxoutType::WITNESS_UNKNOWN with unknown version
s.clear();
@@ -235,7 +235,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
unk.length = 33;
unk.version = 1;
std::copy(pubkey.begin(), pubkey.end(), unk.program);
- BOOST_CHECK(boost::get<WitnessUnknown>(&address) && *boost::get<WitnessUnknown>(&address) == unk);
+ BOOST_CHECK(std::get_if<WitnessUnknown>(&address) && *std::get_if<WitnessUnknown>(&address) == unk);
}
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
@@ -259,8 +259,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEY);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
- *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
+ BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) &&
+ *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
// TxoutType::PUBKEYHASH
s.clear();
@@ -269,8 +269,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEYHASH);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
- *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
+ BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) &&
+ *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
// TxoutType::SCRIPTHASH
CScript redeemScript(s); // initialize with leftover P2PKH script
@@ -280,8 +280,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TxoutType::SCRIPTHASH);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<ScriptHash>(&addresses[0]) &&
- *boost::get<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript));
+ BOOST_CHECK(std::get_if<ScriptHash>(&addresses[0]) &&
+ *std::get_if<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript));
// TxoutType::MULTISIG
s.clear();
@@ -293,10 +293,10 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TxoutType::MULTISIG);
BOOST_CHECK_EQUAL(addresses.size(), 2U);
BOOST_CHECK_EQUAL(nRequired, 2);
- BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
- *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
- BOOST_CHECK(boost::get<PKHash>(&addresses[1]) &&
- *boost::get<PKHash>(&addresses[1]) == PKHash(pubkeys[1]));
+ BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) &&
+ *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
+ BOOST_CHECK(std::get_if<PKHash>(&addresses[1]) &&
+ *std::get_if<PKHash>(&addresses[1]) == PKHash(pubkeys[1]));
// TxoutType::NULL_DATA
s.clear();
diff --git a/src/util/message.cpp b/src/util/message.cpp
index e1d5cff48c..73948e4ff1 100644
--- a/src/util/message.cpp
+++ b/src/util/message.cpp
@@ -31,7 +31,7 @@ MessageVerificationResult MessageVerify(
return MessageVerificationResult::ERR_INVALID_ADDRESS;
}
- if (boost::get<PKHash>(&destination) == nullptr) {
+ if (std::get_if<PKHash>(&destination) == nullptr) {
return MessageVerificationResult::ERR_ADDRESS_NO_KEY;
}
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 5f30136fa2..917d37ccc7 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1047,27 +1047,36 @@ bool FileCommit(FILE *file)
LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
return false;
}
-#else
- #if HAVE_FDATASYNC
- if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
- LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
- return false;
- }
- #elif defined(MAC_OSX) && defined(F_FULLFSYNC)
+#elif defined(MAC_OSX) && defined(F_FULLFSYNC)
if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
return false;
}
- #else
+#elif HAVE_FDATASYNC
+ if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
+ LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
+ return false;
+ }
+#else
if (fsync(fileno(file)) != 0 && errno != EINVAL) {
LogPrintf("%s: fsync failed: %d\n", __func__, errno);
return false;
}
- #endif
#endif
return true;
}
+void DirectoryCommit(const fs::path &dirname)
+{
+#ifndef WIN32
+ FILE* file = fsbridge::fopen(dirname, "r");
+ if (file) {
+ fsync(fileno(file));
+ fclose(file);
+ }
+#endif
+}
+
bool TruncateFile(FILE *file, unsigned int length) {
#if defined(WIN32)
return _chsize(_fileno(file), length) == 0;
diff --git a/src/util/system.h b/src/util/system.h
index 2be8bb754b..010fc5b49f 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -56,7 +56,19 @@ bool error(const char* fmt, const Args&... args)
}
void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
+
+/**
+ * Ensure file contents are fully committed to disk, using a platform-specific
+ * feature analogous to fsync().
+ */
bool FileCommit(FILE *file);
+
+/**
+ * Sync directory contents. This is required on some environments to ensure that
+ * newly created files are committed to disk.
+ */
+void DirectoryCommit(const fs::path &dirname);
+
bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index ae4e8f2898..7705794c63 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -627,7 +627,7 @@ static RPCHelpMan signmessage()
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}
- const PKHash *pkhash = boost::get<PKHash>(&dest);
+ const PKHash* pkhash = std::get_if<PKHash>(&dest);
if (!pkhash) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}
@@ -3002,7 +3002,7 @@ static RPCHelpMan listunspent()
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
if (provider) {
if (scriptPubKey.IsPayToScriptHash()) {
- const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address));
+ const CScriptID& hash = CScriptID(std::get<ScriptHash>(address));
CScript redeemScript;
if (provider->GetCScript(hash, redeemScript)) {
entry.pushKV("redeemScript", HexStr(redeemScript));
@@ -3012,7 +3012,7 @@ static RPCHelpMan listunspent()
bool extracted = ExtractDestination(redeemScript, witness_destination);
CHECK_NONFATAL(extracted);
// Also return the witness script
- const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(witness_destination);
+ const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(witness_destination);
CScriptID id;
CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
CScript witnessScript;
@@ -3022,7 +3022,7 @@ static RPCHelpMan listunspent()
}
}
} else if (scriptPubKey.IsPayToWitnessScriptHash()) {
- const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(address);
+ const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(address);
CScriptID id;
CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
CScript witnessScript;
@@ -3645,7 +3645,7 @@ static RPCHelpMan rescanblockchain()
};
}
-class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
+class DescribeWalletAddressVisitor
{
public:
const SigningProvider * const provider;
@@ -3664,7 +3664,7 @@ public:
UniValue subobj(UniValue::VOBJ);
UniValue detail = DescribeAddress(embedded);
subobj.pushKVs(detail);
- UniValue wallet_detail = boost::apply_visitor(*this, embedded);
+ UniValue wallet_detail = std::visit(*this, embedded);
subobj.pushKVs(wallet_detail);
subobj.pushKV("address", EncodeDestination(embedded));
subobj.pushKV("scriptPubKey", HexStr(subscript));
@@ -3747,7 +3747,7 @@ static UniValue DescribeWalletAddress(const CWallet* const pwallet, const CTxDes
provider = pwallet->GetSolvingProvider(script);
}
ret.pushKVs(detail);
- ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(provider.get()), dest));
+ ret.pushKVs(std::visit(DescribeWalletAddressVisitor(provider.get()), dest));
return ret;
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index a6db261914..5480f3ab22 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -550,7 +550,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
list = wallet->ListCoins();
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);
// Check initial balance from one mature coinbase transaction.
@@ -566,7 +566,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
list = wallet->ListCoins();
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);
// Lock both coins. Confirm number of available coins drops to 0.
@@ -595,7 +595,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
list = wallet->ListCoins();
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 0bcbff3b2f..918946f9e7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2789,7 +2789,7 @@ bool CWallet::CreateTransactionInternal(
CScript scriptChange;
// coin control: send change to custom address
- if (!boost::get<CNoDestination>(&coin_control.destChange)) {
+ if (!std::get_if<CNoDestination>(&coin_control.destChange)) {
scriptChange = GetScriptForDestination(coin_control.destChange);
} else { // no coin control: send change to newly generated address
// Note: We use a new key here to keep it from being obvious which side is the change.
@@ -3724,7 +3724,7 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
bool CWallet::AddDestData(WalletBatch& batch, const CTxDestination &dest, const std::string &key, const std::string &value)
{
- if (boost::get<CNoDestination>(&dest))
+ if (std::get_if<CNoDestination>(&dest))
return false;
m_address_book[dest].destdata.insert(std::make_pair(key, value));
diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py
index 8ac91bd008..eb08765ebf 100755
--- a/test/functional/mempool_compatibility.py
+++ b/test/functional/mempool_compatibility.py
@@ -16,15 +16,15 @@ Only v0.15.2 is required by this test. The rest is used in other backwards compa
import os
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.wallet import MiniWallet
class MempoolCompatibilityTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.wallet_names = [None, self.default_wallet_name]
+ self.wallet_names = [None]
def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
self.skip_if_no_previous_releases()
def setup_network(self):
@@ -38,8 +38,15 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Test that mempool.dat is compatible between versions")
- old_node = self.nodes[0]
- new_node = self.nodes[1]
+ old_node, new_node = self.nodes
+ new_wallet = MiniWallet(new_node)
+ new_wallet.generate(1)
+ new_node.generate(100)
+ # Sync the nodes to ensure old_node has the block that contains the coinbase that new_wallet will spend.
+ # Otherwise, because coinbases are only valid in a block and not as loose txns, if the nodes aren't synced
+ # unbroadcasted_tx won't pass old_node's `MemPoolAccept::PreChecks`.
+ self.connect_nodes(0, 1)
+ self.sync_blocks()
recipient = old_node.getnewaddress()
self.stop_node(1)
@@ -58,7 +65,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
assert old_tx_hash in new_node.getrawmempool()
self.log.info("Add unbroadcasted tx to mempool on new node and shutdown")
- unbroadcasted_tx_hash = new_node.sendtoaddress(recipient, 0.0001)
+ unbroadcasted_tx_hash = new_wallet.send_self_transfer(from_node=new_node)['txid']
assert unbroadcasted_tx_hash in new_node.getrawmempool()
mempool = new_node.getrawmempool(True)
assert mempool[unbroadcasted_tx_hash]['unbroadcast']
diff --git a/test/functional/rpc_setban.py b/test/functional/rpc_setban.py
index 523fdc9f63..fd5f8aa098 100755
--- a/test/functional/rpc_setban.py
+++ b/test/functional/rpc_setban.py
@@ -15,6 +15,9 @@ class SetBanTests(BitcoinTestFramework):
self.setup_clean_chain = True
self.extra_args = [[],[]]
+ def is_banned(self, node, addr):
+ return any(e['address'] == addr for e in node.listbanned())
+
def run_test(self):
# Node 0 connects to Node 1, check that the noban permission is not granted
self.connect_nodes(0, 1)
@@ -42,5 +45,18 @@ class SetBanTests(BitcoinTestFramework):
peerinfo = self.nodes[1].getpeerinfo()[0]
assert(not 'noban' in peerinfo['permissions'])
+ self.log.info("Test that a non-IP address can be banned/unbanned")
+ node = self.nodes[1]
+ tor_addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"
+ ip_addr = "1.2.3.4"
+ assert(not self.is_banned(node, tor_addr))
+ assert(not self.is_banned(node, ip_addr))
+ node.setban(tor_addr, "add")
+ assert(self.is_banned(node, tor_addr))
+ assert(not self.is_banned(node, ip_addr))
+ node.setban(tor_addr, "remove")
+ assert(not self.is_banned(self.nodes[1], tor_addr))
+ assert(not self.is_banned(node, ip_addr))
+
if __name__ == '__main__':
SetBanTests().main()
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 62ff5c6e33..b3eb2d61a7 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -362,6 +362,7 @@ def initialize_datadir(dirname, n, chain):
f.write("listenonion=0\n")
f.write("printtoconsole=0\n")
f.write("upnp=0\n")
+ f.write("natpmp=0\n")
f.write("shrinkdebugfile=0\n")
os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index a71f2c69cb..7cb74bdcb3 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -71,9 +71,9 @@ class MiniWallet:
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
tx_hex = tx.serialize().hex()
- txid = from_node.sendrawtransaction(tx_hex)
- self._utxos.append({'txid': txid, 'vout': 0, 'value': send_value})
- tx_info = from_node.getmempoolentry(txid)
+ tx_info = from_node.testmempoolaccept([tx_hex])[0]
+ self._utxos.append({'txid': tx_info['txid'], 'vout': 0, 'value': send_value})
+ from_node.sendrawtransaction(tx_hex)
assert_equal(tx_info['vsize'], vsize)
- assert_equal(tx_info['fee'], fee)
- return {'txid': txid, 'wtxid': tx_info['wtxid'], 'hex': tx_hex}
+ assert_equal(tx_info['fees']['base'], fee)
+ return {'txid': tx_info['txid'], 'wtxid': from_node.decoderawtransaction(tx_hex)['hash'], 'hex': tx_hex}
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index 393f734abe..dc032665e4 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -71,9 +71,6 @@ EXPECTED_BOOST_INCLUDES=(
boost/thread/mutex.hpp
boost/thread/shared_mutex.hpp
boost/thread/thread.hpp
- boost/variant.hpp
- boost/variant/apply_visitor.hpp
- boost/variant/static_visitor.hpp
)
for BOOST_INCLUDE in $(git grep '^#include <boost/' -- "*.cpp" "*.h" | cut -f2 -d: | cut -f2 -d'<' | cut -f1 -d'>' | sort -u); do