aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml4
-rw-r--r--build-aux/m4/l_socket.m436
-rw-r--r--build_msvc/common.init.vcxproj2
-rw-r--r--build_msvc/libleveldb/libleveldb.vcxproj2
-rw-r--r--build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj3
-rw-r--r--configure.ac2
-rw-r--r--depends/hosts/darwin.mk5
-rw-r--r--depends/packages/native_cctools.mk96
-rw-r--r--depends/packages/native_clang.mk26
-rw-r--r--depends/packages/native_libtapi.mk20
-rw-r--r--depends/packages/packages.mk7
-rw-r--r--doc/REST-interface.md5
-rw-r--r--doc/release-notes.md15
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile.qttest.include3
-rw-r--r--src/Makefile.test.include4
-rw-r--r--src/Makefile.test_util.include1
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/bitcoind.cpp5
-rw-r--r--src/core_io.h4
-rw-r--r--src/core_write.cpp24
-rw-r--r--src/httprpc.cpp4
-rw-r--r--src/httprpc.h8
-rw-r--r--src/i2p.cpp42
-rw-r--r--src/i2p.h12
-rw-r--r--src/init.cpp11
-rw-r--r--src/init.h6
-rw-r--r--src/net.cpp117
-rw-r--r--src/net.h41
-rw-r--r--src/net_processing.cpp55
-rw-r--r--src/net_processing.h7
-rw-r--r--src/netbase.cpp59
-rw-r--r--src/netbase.h4
-rw-r--r--src/node/context.cpp1
-rw-r--r--src/node/context.h2
-rw-r--r--src/node/interfaces.cpp8
-rw-r--r--src/qt/test/compattests.cpp25
-rw-r--r--src/qt/test/compattests.h19
-rw-r--r--src/qt/test/test_main.cpp5
-rw-r--r--src/randomenv.cpp4
-rw-r--r--src/rest.cpp42
-rw-r--r--src/rpc/blockchain.cpp34
-rw-r--r--src/rpc/blockchain.h16
-rw-r--r--src/rpc/misc.cpp14
-rw-r--r--src/rpc/net.cpp6
-rw-r--r--src/rpc/rawtransaction.cpp21
-rw-r--r--src/rpc/request.h11
-rw-r--r--src/rpc/server.cpp4
-rw-r--r--src/script/standard.cpp2
-rw-r--r--src/script/standard.h2
-rw-r--r--src/test/bswap_tests.cpp1
-rw-r--r--src/test/denialofservice_tests.cpp38
-rw-r--r--src/test/fuzz/coins_view.cpp7
-rw-r--r--src/test/fuzz/connman.cpp25
-rw-r--r--src/test/fuzz/i2p.cpp57
-rw-r--r--src/test/fuzz/node_eviction.cpp1
-rw-r--r--src/test/fuzz/script.cpp6
-rw-r--r--src/test/fuzz/script_flags.cpp11
-rw-r--r--src/test/fuzz/signature_checker.cpp17
-rw-r--r--src/test/fuzz/transaction.cpp6
-rw-r--r--src/test/fuzz/util.cpp2
-rw-r--r--src/test/fuzz/util.h107
-rw-r--r--src/test/i2p_tests.cpp44
-rw-r--r--src/test/net_peer_eviction_tests.cpp348
-rw-r--r--src/test/net_tests.cpp143
-rw-r--r--src/test/ref_tests.cpp33
-rw-r--r--src/test/rpc_tests.cpp5
-rw-r--r--src/test/util/net.h69
-rw-r--r--src/test/util/script.cpp13
-rw-r--r--src/test/util/script.h3
-rw-r--r--src/test/util/setup_common.cpp11
-rw-r--r--src/util/ref.h38
-rw-r--r--src/util/sock.cpp10
-rw-r--r--src/util/sock.h19
-rw-r--r--src/util/system.h13
-rw-r--r--src/wallet/interfaces.cpp3
-rw-r--r--src/wallet/rpcwallet.cpp10
-rw-r--r--src/wallet/rpcwallet.h3
-rw-r--r--src/wallet/test/wallet_tests.cpp8
-rwxr-xr-xtest/functional/feature_rbf.py7
-rwxr-xr-xtest/functional/feature_segwit.py2
-rwxr-xr-xtest/functional/mempool_package_onemore.py2
-rwxr-xr-xtest/functional/p2p_feefilter.py14
-rwxr-xr-xtest/functional/p2p_filter.py6
-rw-r--r--test/functional/rpc_addresses_deprecation.py58
-rwxr-xr-xtest/functional/rpc_createmultisig.py2
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py10
-rwxr-xr-xtest/functional/rpc_generateblock.py8
-rwxr-xr-xtest/functional/rpc_psbt.py12
-rw-r--r--test/functional/test_framework/util.py2
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_address_types.py2
-rwxr-xr-xtest/functional/wallet_avoidreuse.py2
-rwxr-xr-xtest/functional/wallet_basic.py2
-rwxr-xr-xtest/functional/wallet_bumpfee.py2
-rwxr-xr-xtest/functional/wallet_hd.py2
-rwxr-xr-xtest/functional/wallet_send.py4
-rwxr-xr-xtest/functional/wallet_txn_clone.py4
-rwxr-xr-xtest/lint/extended-lint-cppcheck.sh1
-rw-r--r--test/util/data/tt-delin1-out.json14
-rw-r--r--test/util/data/tt-delout1-out.json7
-rw-r--r--test/util/data/tt-locktime317000-out.json14
-rw-r--r--test/util/data/txcreate1.json14
-rw-r--r--test/util/data/txcreatedata1.json7
-rw-r--r--test/util/data/txcreatedata2.json7
-rw-r--r--test/util/data/txcreatedata_seq0.json7
-rw-r--r--test/util/data/txcreatedata_seq1.json7
-rw-r--r--test/util/data/txcreatemultisig1.json8
-rw-r--r--test/util/data/txcreatemultisig2.json7
-rw-r--r--test/util/data/txcreatemultisig3.json7
-rw-r--r--test/util/data/txcreatemultisig4.json7
-rw-r--r--test/util/data/txcreatemultisig5.json7
-rw-r--r--test/util/data/txcreateoutpubkey2.json7
-rw-r--r--test/util/data/txcreateoutpubkey3.json7
-rw-r--r--test/util/data/txcreatescript2.json7
-rw-r--r--test/util/data/txcreatescript3.json7
-rw-r--r--test/util/data/txcreatescript4.json7
-rw-r--r--test/util/data/txcreatesignv1.json7
118 files changed, 1316 insertions, 882 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index b3d58461e0..d7d5ab6c5c 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -168,13 +168,13 @@ task:
FILE_ENV: "./ci/test/00_setup_env_mac.sh"
task:
- name: 'macOS 10.15 native [gui] [no depends]'
+ name: 'macOS 11 native [gui] [no depends]'
macos_brew_addon_script:
- 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)
- image: catalina-xcode-12.1 # https://cirrus-ci.org/guide/macOS
+ image: big-sur-xcode-12.4 # https://cirrus-ci.org/guide/macOS
env:
DANGER_RUN_CI_ON_HOST: "true"
CI_USE_APT_INSTALL: "no"
diff --git a/build-aux/m4/l_socket.m4 b/build-aux/m4/l_socket.m4
new file mode 100644
index 0000000000..38923a98fc
--- /dev/null
+++ b/build-aux/m4/l_socket.m4
@@ -0,0 +1,36 @@
+# Illumos/SmartOS requires linking with -lsocket if
+# using getifaddrs & freeifaddrs
+
+m4_define([_CHECK_SOCKET_testbody], [[
+ #include <sys/types.h>
+ #include <ifaddrs.h>
+
+ int main() {
+ struct ifaddrs *ifaddr;
+ getifaddrs(&ifaddr);
+ freeifaddrs(ifaddr);
+ }
+]])
+
+AC_DEFUN([CHECK_SOCKET], [
+
+ AC_LANG_PUSH(C++)
+
+ AC_MSG_CHECKING([whether ifaddrs funcs can be used without link library])
+
+ AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_SOCKET_testbody])],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ LIBS="$LIBS -lsocket"
+ AC_MSG_CHECKING([whether getifaddrs needs -lsocket])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_SOCKET_testbody])],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ AC_MSG_FAILURE([cannot figure out how to use getifaddrs])
+ ])
+ ])
+
+ AC_LANG_POP
+])
diff --git a/build_msvc/common.init.vcxproj b/build_msvc/common.init.vcxproj
index a3487c7a0d..f195d3d451 100644
--- a/build_msvc/common.init.vcxproj
+++ b/build_msvc/common.init.vcxproj
@@ -97,7 +97,7 @@
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalOptions>/utf-8 /Zc:__cplusplus /std:c++17 %(AdditionalOptions)</AdditionalOptions>
- <DisableSpecificWarnings>4018;4221;4244;4267;4334;4715;4805;4834</DisableSpecificWarnings>
+ <DisableSpecificWarnings>4018;4244;4267;4334;4715;4805;4834</DisableSpecificWarnings>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;ZMQ_STATIC;NOMINMAX;WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;_WIN32_WINNT=0x0601;_WIN32_IE=0x0501;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
diff --git a/build_msvc/libleveldb/libleveldb.vcxproj b/build_msvc/libleveldb/libleveldb.vcxproj
index 1610ae7d86..009be30dec 100644
--- a/build_msvc/libleveldb/libleveldb.vcxproj
+++ b/build_msvc/libleveldb/libleveldb.vcxproj
@@ -51,7 +51,7 @@
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>HAVE_CRC32C=0;HAVE_SNAPPY=0;__STDC_LIMIT_MACROS;LEVELDB_IS_BIG_ENDIAN=0;_UNICODE;UNICODE;_CRT_NONSTDC_NO_DEPRECATE;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <DisableSpecificWarnings>4244;4267;4312;4722;</DisableSpecificWarnings>
+ <DisableSpecificWarnings>4244;4267</DisableSpecificWarnings>
<AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
diff --git a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
index 1ddd62edf2..1d2c86b7ac 100644
--- a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
+++ b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
@@ -11,7 +11,6 @@
<ClCompile Include="..\..\src\test\util\setup_common.cpp" />
<ClCompile Include="..\..\src\qt\test\addressbooktests.cpp" />
<ClCompile Include="..\..\src\qt\test\apptests.cpp" />
- <ClCompile Include="..\..\src\qt\test\compattests.cpp" />
<ClCompile Include="..\..\src\qt\test\rpcnestedtests.cpp" />
<ClCompile Include="..\..\src\qt\test\test_main.cpp" />
<ClCompile Include="..\..\src\qt\test\uritests.cpp" />
@@ -20,7 +19,6 @@
<ClCompile Include="..\..\src\wallet\test\wallet_test_fixture.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_addressbooktests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_apptests.cpp" />
- <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_compattests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_rpcnestedtests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_uritests.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_wallettests.cpp" />
@@ -89,7 +87,6 @@
<ItemGroup>
<MocTestFiles Include="..\..\src\qt\test\addressbooktests.h" />
<MocTestFiles Include="..\..\src\qt\test\apptests.h" />
- <MocTestFiles Include="..\..\src\qt\test\compattests.h" />
<MocTestFiles Include="..\..\src\qt\test\rpcnestedtests.h" />
<MocTestFiles Include="..\..\src\qt\test\uritests.h" />
<MocTestFiles Include="..\..\src\qt\test\wallettests.h" />
diff --git a/configure.ac b/configure.ac
index 9ac2643374..c3eabad131 100644
--- a/configure.ac
+++ b/configure.ac
@@ -936,7 +936,7 @@ fi
AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h sys/sysctl.h vm/vm_param.h sys/vmmeter.h sys/resources.h])
-AC_CHECK_DECLS([getifaddrs, freeifaddrs],,,
+AC_CHECK_DECLS([getifaddrs, freeifaddrs],[CHECK_SOCKET],,
[#include <sys/types.h>
#include <ifaddrs.h>]
)
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index 646e97837a..dd71697f0f 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -12,14 +12,13 @@ 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
+# Clang is a dependency of native_cctools 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)
+clang_resource_dir=$(build_prefix)/lib/clang/$(native_clang_version)
else
# FORCE_USE_SYSTEM_CLANG is non-empty, so we use the clang from the user's
# system
diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk
index d56b636695..c789dab74c 100644
--- a/depends/packages/native_cctools.mk
+++ b/depends/packages/native_cctools.mk
@@ -5,81 +5,19 @@ $(package)_file_name=$($(package)_version).tar.gz
$(package)_sha256_hash=e51995a843533a3dac155dd0c71362dd471597a2d23f13dff194c6285362f875
$(package)_build_subdir=cctools
$(package)_patches=ld64_disable_threading.patch
-
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
-$(package)_clang_version=8.0.0
-$(package)_clang_download_path=https://releases.llvm.org/$($(package)_clang_version)
-$(package)_clang_download_file=clang+llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz
-$(package)_clang_file_name=clang-llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz
-$(package)_clang_sha256_hash=9ef854b71949f825362a119bf2597f744836cb571131ae6b721cd102ffea8cd0
-endif
-
-$(package)_libtapi_version=3efb201881e7a76a21e0554906cf306432539cef
-$(package)_libtapi_download_path=https://github.com/tpoechtrager/apple-libtapi/archive
-$(package)_libtapi_download_file=$($(package)_libtapi_version).tar.gz
-$(package)_libtapi_file_name=$($(package)_libtapi_version).tar.gz
-$(package)_libtapi_sha256_hash=380c1ca37cfa04a8699d0887a8d3ee1ad27f3d08baba78887c73b09485c0fbd3
-
-$(package)_extra_sources=$($(package)_libtapi_file_name)
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
-$(package)_extra_sources += $($(package)_clang_file_name)
-endif
-
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
-define $(package)_fetch_cmds
-$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \
-$(call fetch_file,$(package),$($(package)_clang_download_path),$($(package)_clang_download_file),$($(package)_clang_file_name),$($(package)_clang_sha256_hash)) && \
-$(call fetch_file,$(package),$($(package)_libtapi_download_path),$($(package)_libtapi_download_file),$($(package)_libtapi_file_name),$($(package)_libtapi_sha256_hash))
-endef
-else
-define $(package)_fetch_cmds
-$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \
-$(call fetch_file,$(package),$($(package)_libtapi_download_path),$($(package)_libtapi_download_file),$($(package)_libtapi_file_name),$($(package)_libtapi_sha256_hash))
-endef
-endif
-
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
-define $(package)_extract_cmds
- mkdir -p $($(package)_extract_dir) && \
- echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \
- echo "$($(package)_clang_sha256_hash) $($(package)_source_dir)/$($(package)_clang_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \
- echo "$($(package)_libtapi_sha256_hash) $($(package)_source_dir)/$($(package)_libtapi_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \
- $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \
- mkdir -p toolchain/bin toolchain/lib/clang/$($(package)_clang_version)/include && \
- mkdir -p libtapi && \
- tar --no-same-owner --strip-components=1 -C libtapi -xf $($(package)_source_dir)/$($(package)_libtapi_file_name) && \
- tar --no-same-owner --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \
- rm -f toolchain/lib/libc++abi.so* && \
- tar --no-same-owner --strip-components=1 -xf $($(package)_source)
-endef
-else
-define $(package)_extract_cmds
- mkdir -p $($(package)_extract_dir) && \
- echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \
- echo "$($(package)_libtapi_sha256_hash) $($(package)_source_dir)/$($(package)_libtapi_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \
- $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \
- mkdir -p libtapi && \
- tar --no-same-owner --strip-components=1 -C libtapi -xf $($(package)_source_dir)/$($(package)_libtapi_file_name) && \
- tar --no-same-owner --strip-components=1 -xf $($(package)_source)
-endef
-endif
+$(package)_dependencies=native_libtapi
define $(package)_set_vars
- $(package)_config_opts=--target=$(host) --with-libtapi=$($(package)_extract_dir)
+ $(package)_config_opts=--target=$(host)
$(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib
ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
- $(package)_config_opts+=--enable-lto-support --with-llvm-config=$($(package)_extract_dir)/toolchain/bin/llvm-config
- $(package)_cc=$($(package)_extract_dir)/toolchain/bin/clang
- $(package)_cxx=$($(package)_extract_dir)/toolchain/bin/clang++
- else
- $(package)_cc=clang
- $(package)_cxx=clang++
+ $(package)_config_opts+=--enable-lto-support --with-llvm-config=$(build_prefix)/bin/llvm-config
endif
+ $(package)_cc=$(clang_prog)
+ $(package)_cxx=$(clangxx_prog)
endef
define $(package)_preprocess_cmds
- CC=$($(package)_cc) CXX=$($(package)_cxx) INSTALLPREFIX=$($(package)_extract_dir) ./libtapi/build.sh && \
- CC=$($(package)_cc) CXX=$($(package)_cxx) INSTALLPREFIX=$($(package)_extract_dir) ./libtapi/install.sh && \
patch -p1 < $($(package)_patch_dir)/ld64_disable_threading.patch
endef
@@ -91,26 +29,10 @@ define $(package)_build_cmds
$(MAKE)
endef
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install && \
- mkdir -p $($(package)_staging_prefix_dir)/lib/ && \
- cd $($(package)_extract_dir) && \
- cp lib/libtapi.so.6 $($(package)_staging_prefix_dir)/lib/ && \
- cd $($(package)_extract_dir)/toolchain && \
- mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include && \
- mkdir -p $($(package)_staging_prefix_dir)/bin $($(package)_staging_prefix_dir)/include && \
- cp bin/clang $($(package)_staging_prefix_dir)/bin/ &&\
- cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ &&\
- cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \
- cp -rf lib/clang/$($(package)_clang_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include/ && \
- cp bin/dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
-else
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install && \
- mkdir -p $($(package)_staging_prefix_dir)/lib/ && \
- cd $($(package)_extract_dir) && \
- cp lib/libtapi.so.6 $($(package)_staging_prefix_dir)/lib/
+
+define $(package)_postprocess_cmds
+ rm -rf share
endef
-endif
diff --git a/depends/packages/native_clang.mk b/depends/packages/native_clang.mk
new file mode 100644
index 0000000000..741ddacf09
--- /dev/null
+++ b/depends/packages/native_clang.mk
@@ -0,0 +1,26 @@
+package=native_clang
+$(package)_version=8.0.0
+$(package)_download_path=https://releases.llvm.org/$($(package)_version)
+$(package)_download_file=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz
+$(package)_file_name=clang-llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz
+$(package)_sha256_hash=9ef854b71949f825362a119bf2597f744836cb571131ae6b721cd102ffea8cd0
+
+define $(package)_preprocess_cmds
+ rm -f $($(package)_extract_dir)/lib/libc++abi.so*
+endef
+
+define $(package)_stage_cmds
+ mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include && \
+ mkdir -p $($(package)_staging_prefix_dir)/bin && \
+ mkdir -p $($(package)_staging_prefix_dir)/include && \
+ cp bin/clang $($(package)_staging_prefix_dir)/bin/ && \
+ cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ && \
+ cp bin/dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil && \
+ cp bin/llvm-config $($(package)_staging_prefix_dir)/bin/ && \
+ cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \
+ cp -rf lib/clang/$($(package)_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include/
+endef
+
+define $(package)_postprocess_cmds
+ rmdir include
+endef
diff --git a/depends/packages/native_libtapi.mk b/depends/packages/native_libtapi.mk
new file mode 100644
index 0000000000..d7ac4156a7
--- /dev/null
+++ b/depends/packages/native_libtapi.mk
@@ -0,0 +1,20 @@
+package=native_libtapi
+$(package)_version=3efb201881e7a76a21e0554906cf306432539cef
+$(package)_download_path=https://github.com/tpoechtrager/apple-libtapi/archive
+$(package)_download_file=$($(package)_version).tar.gz
+$(package)_file_name=$($(package)_version).tar.gz
+$(package)_sha256_hash=380c1ca37cfa04a8699d0887a8d3ee1ad27f3d08baba78887c73b09485c0fbd3
+
+ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
+$(package)_dependencies=native_clang
+endif
+
+define $(package)_build_cmds
+ CC=$(clang_prog) CXX=$(clangxx_prog) INSTALLPREFIX=$($(package)_staging_prefix_dir) ./build.sh
+endef
+
+define $(package)_stage_cmds
+ ./install.sh && \
+ mkdir -p $($(package)_staging_prefix_dir)/include/llvm-c && \
+ cp src/llvm/include/llvm-c/lto.h $($(package)_staging_prefix_dir)/include/llvm-c
+endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 810068b686..9094e327ef 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -24,5 +24,10 @@ darwin_native_packages = native_ds_store native_mac_alias
$(host_arch)_$(host_os)_native_packages += native_b2
ifneq ($(build_os),darwin)
-darwin_native_packages += native_cctools native_libdmg-hfsplus
+darwin_native_packages += native_cctools native_libtapi native_libdmg-hfsplus
+
+ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
+darwin_native_packages+= native_clang
+endif
+
endif
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index ea06952af4..8b281acca7 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -95,11 +95,8 @@ $ curl localhost:18332/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff76
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 1c7cebb529b86a04c683dfa87be49de35bcf589e OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a9141c7cebb529b86a04c683dfa87be49de35bcf589e88ac",
- "reqSigs" : 1,
"type" : "pubkeyhash",
- "addresses" : [
- "mi7as51dvLJsizWnTMurtRmrP8hG2m1XvD"
- ]
+ "address" : "mi7as51dvLJsizWnTMurtRmrP8hG2m1XvD"
}
}
]
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 3cd83a2003..e46380b38f 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -67,6 +67,21 @@ Updated RPCs
`whitelisted`, the `permissions` field indicates if the peer has special
privileges. The `banscore` field has simply been removed. (#20755)
+- The following RPCs: `gettxout`, `getrawtransaction`, `decoderawtransaction`,
+ `decodescript`, `gettransaction`, and REST endpoints: `/rest/tx`,
+ `/rest/getutxos`, `/rest/block` deprecated the following fields (which are no
+ longer returned in the responses by default): `addresses`, `reqSigs`.
+ The `-deprecatedrpc=addresses` flag must be passed for these fields to be
+ included in the RPC response. This flag/option will be available until v23, at which
+ point the deprecation will be removed entirely. Note that these fields are attributes of
+ the `scriptPubKey` object returned in the RPC response. However, in the response
+ of `decodescript` these fields are top-level attributes, and included again as attributes
+ of the `scriptPubKey` object. (#20286)
+
+- When creating a hex-encoded bitcoin transaction using the `bitcoin-tx` utility
+ with the `-json` option set, the following fields: `addresses`, `reqSigs` are no longer
+ returned in the tx output of the response. (#20286)
+
Changes to Wallet or GUI related RPCs can be found in the GUI or Wallet section below.
New RPCs
diff --git a/src/Makefile.am b/src/Makefile.am
index 9903c2e9b3..4e09c86ebd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -243,7 +243,6 @@ BITCOIN_CORE_H = \
util/moneystr.h \
util/rbf.h \
util/readwritefile.h \
- util/ref.h \
util/settings.h \
util/sock.h \
util/spanparsing.h \
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index a6a857d952..91a5e9fd9b 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -7,7 +7,6 @@ TESTS += qt/test/test_bitcoin-qt
TEST_QT_MOC_CPP = \
qt/test/moc_apptests.cpp \
- qt/test/moc_compattests.cpp \
qt/test/moc_rpcnestedtests.cpp \
qt/test/moc_uritests.cpp
@@ -20,7 +19,6 @@ endif # ENABLE_WALLET
TEST_QT_H = \
qt/test/addressbooktests.h \
qt/test/apptests.h \
- qt/test/compattests.h \
qt/test/rpcnestedtests.h \
qt/test/uritests.h \
qt/test/util.h \
@@ -31,7 +29,6 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_
qt_test_test_bitcoin_qt_SOURCES = \
qt/test/apptests.cpp \
- qt/test/compattests.cpp \
qt/test/rpcnestedtests.cpp \
qt/test/test_main.cpp \
qt/test/uritests.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index e00f17a83f..570f011f7a 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -90,6 +90,7 @@ BITCOIN_TESTS =\
test/fs_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
+ test/i2p_tests.cpp \
test/interfaces_tests.cpp \
test/key_io_tests.cpp \
test/key_tests.cpp \
@@ -101,6 +102,7 @@ BITCOIN_TESTS =\
test/merkleblock_tests.cpp \
test/miner_tests.cpp \
test/multisig_tests.cpp \
+ test/net_peer_eviction_tests.cpp \
test/net_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
@@ -110,7 +112,6 @@ BITCOIN_TESTS =\
test/prevector_tests.cpp \
test/raii_event_tests.cpp \
test/random_tests.cpp \
- test/ref_tests.cpp \
test/reverselock_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
@@ -239,6 +240,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/golomb_rice.cpp \
test/fuzz/hex.cpp \
test/fuzz/http_request.cpp \
+ test/fuzz/i2p.cpp \
test/fuzz/integer.cpp \
test/fuzz/key.cpp \
test/fuzz/key_io.cpp \
diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include
index f7f393ccac..85e50ebf70 100644
--- a/src/Makefile.test_util.include
+++ b/src/Makefile.test_util.include
@@ -26,6 +26,7 @@ libtest_util_a_SOURCES = \
test/util/logging.cpp \
test/util/mining.cpp \
test/util/net.cpp \
+ test/util/script.cpp \
test/util/setup_common.cpp \
test/util/str.cpp \
test/util/transaction_utils.cpp \
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 321d62fe4d..93ac4b8f7e 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -725,7 +725,7 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
static void OutputTxJSON(const CTransaction& tx)
{
UniValue entry(UniValue::VOBJ);
- TxToUniv(tx, uint256(), entry);
+ TxToUniv(tx, uint256(), /* include_addresses */ false, entry);
std::string jsonOutput = entry.write(4);
tfm::format(std::cout, "%s\n", jsonOutput);
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 1b4ca3e9a8..80ab69c131 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -16,7 +16,7 @@
#include <node/ui_interface.h>
#include <noui.h>
#include <shutdown.h>
-#include <util/ref.h>
+#include <util/check.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/threadnames.h>
@@ -24,6 +24,7 @@
#include <util/translation.h>
#include <util/url.h>
+#include <any>
#include <functional>
#include <optional>
@@ -142,7 +143,7 @@ static bool AppInit(int argc, char* argv[])
// end, which is interpreted as failure to start.
TokenPipeEnd daemon_ep;
#endif
- util::Ref context{node};
+ std::any context{&node};
try
{
if (!CheckDataDirOption()) {
diff --git a/src/core_io.h b/src/core_io.h
index 01340ae2ee..3b9b66574c 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -44,8 +44,8 @@ UniValue ValueFromAmount(const CAmount amount);
std::string FormatScript(const CScript& script);
std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
std::string SighashToStr(unsigned char sighash_type);
-void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
+void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex, bool include_addresses);
void ScriptToUniv(const CScript& script, UniValue& out, bool include_address);
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr);
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, bool include_addresses, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_write.cpp b/src/core_write.cpp
index d3034ae25d..b35f835f42 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -156,10 +156,13 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
}
}
+// TODO: from v23 ("addresses" and "reqSigs" deprecated) this method should be refactored to remove the `include_addresses` option
+// this method can also be combined with `ScriptToUniv` as they will overlap
void ScriptPubKeyToUniv(const CScript& scriptPubKey,
- UniValue& out, bool fIncludeHex)
+ UniValue& out, bool fIncludeHex, bool include_addresses)
{
TxoutType type;
+ CTxDestination address;
std::vector<CTxDestination> addresses;
int nRequired;
@@ -172,17 +175,22 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
return;
}
- out.pushKV("reqSigs", nRequired);
+ if (ExtractDestination(scriptPubKey, address)) {
+ out.pushKV("address", EncodeDestination(address));
+ }
out.pushKV("type", GetTxnOutputType(type));
- UniValue a(UniValue::VARR);
- for (const CTxDestination& addr : addresses) {
- a.push_back(EncodeDestination(addr));
+ if (include_addresses) {
+ UniValue a(UniValue::VARR);
+ for (const CTxDestination& addr : addresses) {
+ a.push_back(EncodeDestination(addr));
+ }
+ out.pushKV("addresses", a);
+ out.pushKV("reqSigs", nRequired);
}
- out.pushKV("addresses", a);
}
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo)
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, bool include_addresses, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo)
{
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
@@ -241,7 +249,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
out.pushKV("n", (int64_t)i);
UniValue o(UniValue::VOBJ);
- ScriptPubKeyToUniv(txout.scriptPubKey, o, true);
+ ScriptPubKeyToUniv(txout.scriptPubKey, o, true, include_addresses);
out.pushKV("scriptPubKey", o);
vout.push_back(out);
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 867ddb090e..16ab38e0b2 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -144,7 +144,7 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna
return multiUserAuthorized(strUserPass);
}
-static bool HTTPReq_JSONRPC(const util::Ref& context, HTTPRequest* req)
+static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
{
// JSONRPC handles only POST
if (req->GetRequestMethod() != HTTPRequest::POST) {
@@ -288,7 +288,7 @@ static bool InitRPCAuthentication()
return true;
}
-bool StartHTTPRPC(const util::Ref& context)
+bool StartHTTPRPC(const std::any& context)
{
LogPrint(BCLog::RPC, "Starting HTTP RPC server\n");
if (!InitRPCAuthentication())
diff --git a/src/httprpc.h b/src/httprpc.h
index 97af6f7bb1..5a3b990646 100644
--- a/src/httprpc.h
+++ b/src/httprpc.h
@@ -5,14 +5,12 @@
#ifndef BITCOIN_HTTPRPC_H
#define BITCOIN_HTTPRPC_H
-namespace util {
-class Ref;
-} // namespace util
+#include <any>
/** Start HTTP RPC subsystem.
* Precondition; HTTP and RPC has been started.
*/
-bool StartHTTPRPC(const util::Ref& context);
+bool StartHTTPRPC(const std::any& context);
/** Interrupt HTTP RPC subsystem.
*/
void InterruptHTTPRPC();
@@ -24,7 +22,7 @@ void StopHTTPRPC();
/** Start HTTP REST subsystem.
* Precondition; HTTP and RPC has been started.
*/
-void StartREST(const util::Ref& context);
+void StartREST(const std::any& context);
/** Interrupt RPC REST subsystem.
*/
void InterruptREST();
diff --git a/src/i2p.cpp b/src/i2p.cpp
index d16c620d88..a44f09f043 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -20,6 +20,7 @@
#include <util/system.h>
#include <chrono>
+#include <memory>
#include <stdexcept>
#include <string>
@@ -115,7 +116,8 @@ namespace sam {
Session::Session(const fs::path& private_key_file,
const CService& control_host,
CThreadInterrupt* interrupt)
- : m_private_key_file(private_key_file), m_control_host(control_host), m_interrupt(interrupt)
+ : m_private_key_file(private_key_file), m_control_host(control_host), m_interrupt(interrupt),
+ m_control_sock(std::make_unique<Sock>(INVALID_SOCKET))
{
}
@@ -145,7 +147,7 @@ bool Session::Accept(Connection& conn)
try {
while (!*m_interrupt) {
Sock::Event occurred;
- conn.sock.Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred);
+ conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred);
if ((occurred & Sock::RECV) == 0) {
// Timeout, no incoming connections within MAX_WAIT_FOR_IO.
@@ -153,7 +155,7 @@ bool Session::Accept(Connection& conn)
}
const std::string& peer_dest =
- conn.sock.RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
+ conn.sock->RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
conn.peer = CService(DestB64ToAddr(peer_dest), Params().GetDefaultPort());
@@ -171,7 +173,7 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error)
proxy_error = true;
std::string session_id;
- Sock sock;
+ std::unique_ptr<Sock> sock;
conn.peer = to;
try {
@@ -184,12 +186,12 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error)
}
const Reply& lookup_reply =
- SendRequestAndGetReply(sock, strprintf("NAMING LOOKUP NAME=%s", to.ToStringIP()));
+ SendRequestAndGetReply(*sock, strprintf("NAMING LOOKUP NAME=%s", to.ToStringIP()));
const std::string& dest = lookup_reply.Get("VALUE");
const Reply& connect_reply = SendRequestAndGetReply(
- sock, strprintf("STREAM CONNECT ID=%s DESTINATION=%s SILENT=false", session_id, dest),
+ *sock, strprintf("STREAM CONNECT ID=%s DESTINATION=%s SILENT=false", session_id, dest),
false);
const std::string& result = connect_reply.Get("RESULT");
@@ -271,7 +273,7 @@ Session::Reply Session::SendRequestAndGetReply(const Sock& sock,
return reply;
}
-Sock Session::Hello() const
+std::unique_ptr<Sock> Session::Hello() const
{
auto sock = CreateSock(m_control_host);
@@ -279,13 +281,13 @@ Sock Session::Hello() const
throw std::runtime_error("Cannot create socket");
}
- if (!ConnectSocketDirectly(m_control_host, sock->Get(), nConnectTimeout, true)) {
+ if (!ConnectSocketDirectly(m_control_host, *sock, nConnectTimeout, true)) {
throw std::runtime_error(strprintf("Cannot connect to %s", m_control_host.ToString()));
}
SendRequestAndGetReply(*sock, "HELLO VERSION MIN=3.1 MAX=3.1");
- return std::move(*sock);
+ return sock;
}
void Session::CheckControlSock()
@@ -293,7 +295,7 @@ void Session::CheckControlSock()
LOCK(m_mutex);
std::string errmsg;
- if (!m_control_sock.IsConnected(errmsg)) {
+ if (!m_control_sock->IsConnected(errmsg)) {
Log("Control socket error: %s", errmsg);
Disconnect();
}
@@ -341,26 +343,26 @@ Binary Session::MyDestination() const
void Session::CreateIfNotCreatedAlready()
{
std::string errmsg;
- if (m_control_sock.IsConnected(errmsg)) {
+ if (m_control_sock->IsConnected(errmsg)) {
return;
}
Log("Creating SAM session with %s", m_control_host.ToString());
- Sock sock = Hello();
+ auto sock = Hello();
const auto& [read_ok, data] = ReadBinaryFile(m_private_key_file);
if (read_ok) {
m_private_key.assign(data.begin(), data.end());
} else {
- GenerateAndSavePrivateKey(sock);
+ GenerateAndSavePrivateKey(*sock);
}
const std::string& session_id = GetRandHash().GetHex().substr(0, 10); // full is an overkill, too verbose in the logs
const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));
- SendRequestAndGetReply(sock, strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
- session_id, private_key_b64));
+ SendRequestAndGetReply(*sock, strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
+ session_id, private_key_b64));
m_my_addr = CService(DestBinToAddr(MyDestination()), Params().GetDefaultPort());
m_session_id = session_id;
@@ -370,12 +372,12 @@ void Session::CreateIfNotCreatedAlready()
m_my_addr.ToString());
}
-Sock Session::StreamAccept()
+std::unique_ptr<Sock> Session::StreamAccept()
{
- Sock sock = Hello();
+ auto sock = Hello();
const Reply& reply = SendRequestAndGetReply(
- sock, strprintf("STREAM ACCEPT ID=%s SILENT=false", m_session_id), false);
+ *sock, strprintf("STREAM ACCEPT ID=%s SILENT=false", m_session_id), false);
const std::string& result = reply.Get("RESULT");
@@ -393,14 +395,14 @@ Sock Session::StreamAccept()
void Session::Disconnect()
{
- if (m_control_sock.Get() != INVALID_SOCKET) {
+ if (m_control_sock->Get() != INVALID_SOCKET) {
if (m_session_id.empty()) {
Log("Destroying incomplete session");
} else {
Log("Destroying session %s", m_session_id);
}
}
- m_control_sock.Reset();
+ m_control_sock->Reset();
m_session_id.clear();
}
} // namespace sam
diff --git a/src/i2p.h b/src/i2p.h
index 1ebe7d0329..cb2efedba8 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -12,6 +12,7 @@
#include <threadinterrupt.h>
#include <util/sock.h>
+#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
@@ -29,7 +30,7 @@ using Binary = std::vector<uint8_t>;
*/
struct Connection {
/** Connected socket. */
- Sock sock;
+ std::unique_ptr<Sock> sock;
/** Our I2P address. */
CService me;
@@ -166,7 +167,7 @@ private:
* @return a connected socket
* @throws std::runtime_error if an error occurs
*/
- Sock Hello() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
+ std::unique_ptr<Sock> Hello() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Check the control socket for errors and possibly disconnect.
@@ -204,10 +205,11 @@ private:
/**
* Open a new connection to the SAM proxy and issue "STREAM ACCEPT" request using the existing
- * session id. Return the idle socket that is waiting for a peer to connect to us.
+ * session id.
+ * @return the idle socket that is waiting for a peer to connect to us
* @throws std::runtime_error if an error occurs
*/
- Sock StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
+ std::unique_ptr<Sock> StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Destroy the session, closing the internally used sockets.
@@ -248,7 +250,7 @@ private:
* connections and make outgoing ones.
* See https://geti2p.net/en/docs/api/samv3
*/
- Sock m_control_sock GUARDED_BY(m_mutex);
+ std::unique_ptr<Sock> m_control_sock GUARDED_BY(m_mutex);
/**
* Our .b32.i2p address.
diff --git a/src/init.cpp b/src/init.cpp
index f4b7699233..17b216573f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -228,6 +228,7 @@ void Shutdown(NodeContext& node)
node.peerman.reset();
node.connman.reset();
node.banman.reset();
+ node.addrman.reset();
if (node.mempool && node.mempool->IsLoaded() && node.args->GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool(*node.mempool);
@@ -787,7 +788,7 @@ static bool InitSanityCheck()
return true;
}
-static bool AppInitServers(const util::Ref& context, NodeContext& node)
+static bool AppInitServers(const std::any& context, NodeContext& node)
{
const ArgsManager& args = *Assert(node.args);
RPCServer::OnStarted(&OnRPCStarted);
@@ -1276,7 +1277,7 @@ bool AppInitInterfaces(NodeContext& node)
return true;
}
-bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
+bool AppInitMain(const std::any& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
{
const ArgsManager& args = *Assert(node.args);
const CChainParams& chainparams = Params();
@@ -1402,10 +1403,12 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
fDiscover = args.GetBoolArg("-discover", true);
const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)};
+ assert(!node.addrman);
+ node.addrman = std::make_unique<CAddrMan>();
assert(!node.banman);
node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman);
- node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), args.GetBoolArg("-networkactive", true));
+ node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), *node.addrman, args.GetBoolArg("-networkactive", true));
assert(!node.fee_estimator);
// Don't initialize fee estimation with old data if we don't relay transactions,
@@ -1421,7 +1424,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
ChainstateManager& chainman = *Assert(node.chainman);
assert(!node.peerman);
- node.peerman = PeerManager::make(chainparams, *node.connman, node.banman.get(),
+ node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(),
*node.scheduler, chainman, *node.mempool, ignores_incoming_txs);
RegisterValidationInterface(node.peerman.get());
diff --git a/src/init.h b/src/init.h
index 34bca09dd1..5d01d4c1ac 100644
--- a/src/init.h
+++ b/src/init.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_INIT_H
#define BITCOIN_INIT_H
+#include <any>
#include <memory>
#include <string>
@@ -22,9 +23,6 @@ struct BlockAndHeaderTipInfo;
namespace boost {
class thread_group;
} // namespace boost
-namespace util {
-class Ref;
-} // namespace util
/** Interrupt threads */
void Interrupt(NodeContext& node);
@@ -66,7 +64,7 @@ bool AppInitInterfaces(NodeContext& node);
* @note This should only be done after daemonization. Call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read, AppInitLockDataDirectory should have been called.
*/
-bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info = nullptr);
+bool AppInitMain(const std::any& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info = nullptr);
/**
* Register all arguments with the ArgsManager
diff --git a/src/net.cpp b/src/net.cpp
index 3b1ebede98..1dcb141421 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -31,6 +31,10 @@
#include <fcntl.h>
#endif
+#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
+#include <ifaddrs.h>
+#endif
+
#ifdef USE_POLL
#include <poll.h>
#endif
@@ -432,7 +436,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
i2p::Connection conn;
if (m_i2p_sam_session->Connect(addrConnect, conn, proxyConnectionFailed)) {
connected = true;
- sock = std::make_unique<Sock>(std::move(conn.sock));
+ sock = std::move(conn.sock);
addr_bind = CAddress{conn.me, NODE_NONE};
}
} else if (GetProxy(addrConnect.GetNetwork(), proxy)) {
@@ -448,7 +452,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (!sock) {
return nullptr;
}
- connected = ConnectSocketDirectly(addrConnect, sock->Get(), nConnectTimeout,
+ connected = ConnectSocketDirectly(addrConnect, *sock, nConnectTimeout,
conn_type == ConnectionType::MANUAL);
}
if (!proxyConnectionFailed) {
@@ -840,6 +844,12 @@ static bool CompareLocalHostTimeConnected(const NodeEvictionCandidate &a, const
return a.nTimeConnected > b.nTimeConnected;
}
+static bool CompareOnionTimeConnected(const NodeEvictionCandidate& a, const NodeEvictionCandidate& b)
+{
+ if (a.m_is_onion != b.m_is_onion) return b.m_is_onion;
+ return a.nTimeConnected > b.nTimeConnected;
+}
+
static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) {
return a.nKeyedNetGroup < b.nKeyedNetGroup;
}
@@ -870,13 +880,51 @@ static bool CompareNodeBlockRelayOnlyTime(const NodeEvictionCandidate &a, const
return a.nTimeConnected > b.nTimeConnected;
}
-//! Sort an array by the specified comparator, then erase the last K elements.
-template<typename T, typename Comparator>
-static void EraseLastKElements(std::vector<T> &elements, Comparator comparator, size_t k)
+//! Sort an array by the specified comparator, then erase the last K elements where predicate is true.
+template <typename T, typename Comparator>
+static void EraseLastKElements(
+ std::vector<T>& elements, Comparator comparator, size_t k,
+ std::function<bool(const NodeEvictionCandidate&)> predicate = [](const NodeEvictionCandidate& n) { return true; })
{
std::sort(elements.begin(), elements.end(), comparator);
size_t eraseSize = std::min(k, elements.size());
- elements.erase(elements.end() - eraseSize, elements.end());
+ elements.erase(std::remove_if(elements.end() - eraseSize, elements.end(), predicate), elements.end());
+}
+
+void ProtectEvictionCandidatesByRatio(std::vector<NodeEvictionCandidate>& vEvictionCandidates)
+{
+ // Protect the half of the remaining nodes which have been connected the longest.
+ // This replicates the non-eviction implicit behavior, and precludes attacks that start later.
+ // To favorise the diversity of our peer connections, reserve up to (half + 2) of
+ // these protected spots for onion and localhost peers, if any, even if they're not
+ // longest uptime overall. This helps protect tor peers, which tend to be otherwise
+ // disadvantaged under our eviction criteria.
+ const size_t initial_size = vEvictionCandidates.size();
+ size_t total_protect_size = initial_size / 2;
+ const size_t onion_protect_size = total_protect_size / 2;
+
+ if (onion_protect_size) {
+ // Pick out up to 1/4 peers connected via our onion service, sorted by longest uptime.
+ EraseLastKElements(vEvictionCandidates, CompareOnionTimeConnected, onion_protect_size,
+ [](const NodeEvictionCandidate& n) { return n.m_is_onion; });
+ }
+
+ const size_t localhost_min_protect_size{2};
+ if (onion_protect_size >= localhost_min_protect_size) {
+ // Allocate any remaining slots of the 1/4, or minimum 2 additional slots,
+ // to localhost peers, sorted by longest uptime, as manually configured
+ // hidden services not using `-bind=addr[:port]=onion` will not be detected
+ // as inbound onion connections.
+ const size_t remaining_tor_slots{onion_protect_size - (initial_size - vEvictionCandidates.size())};
+ const size_t localhost_protect_size{std::max(remaining_tor_slots, localhost_min_protect_size)};
+ EraseLastKElements(vEvictionCandidates, CompareLocalHostTimeConnected, localhost_protect_size,
+ [](const NodeEvictionCandidate& n) { return n.m_is_local; });
+ }
+
+ // Calculate how many we removed, and update our total number of peers that
+ // we want to protect based on uptime accordingly.
+ total_protect_size -= initial_size - vEvictionCandidates.size();
+ EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, total_protect_size);
}
[[nodiscard]] std::optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates)
@@ -893,30 +941,17 @@ static void EraseLastKElements(std::vector<T> &elements, Comparator comparator,
// An attacker cannot manipulate this metric without performing useful work.
EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
// Protect up to 8 non-tx-relay peers that have sent us novel blocks.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeBlockRelayOnlyTime);
- size_t erase_size = std::min(size_t(8), vEvictionCandidates.size());
- vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.end() - erase_size, vEvictionCandidates.end(), [](NodeEvictionCandidate const &n) { return !n.fRelayTxes && n.fRelevantServices; }), vEvictionCandidates.end());
+ const size_t erase_size = std::min(size_t(8), vEvictionCandidates.size());
+ EraseLastKElements(vEvictionCandidates, CompareNodeBlockRelayOnlyTime, erase_size,
+ [](const NodeEvictionCandidate& n) { return !n.fRelayTxes && n.fRelevantServices; });
// Protect 4 nodes that most recently sent us novel blocks.
// An attacker cannot manipulate this metric without performing useful work.
EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4);
- // Protect the half of the remaining nodes which have been connected the longest.
- // This replicates the non-eviction implicit behavior, and precludes attacks that start later.
- // Reserve half of these protected spots for localhost peers, even if
- // they're not longest-uptime overall. This helps protect tor peers, which
- // tend to be otherwise disadvantaged under our eviction criteria.
- size_t initial_size = vEvictionCandidates.size();
- size_t total_protect_size = initial_size / 2;
-
- // Pick out up to 1/4 peers that are localhost, sorted by longest uptime.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareLocalHostTimeConnected);
- size_t local_erase_size = total_protect_size / 2;
- vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.end() - local_erase_size, vEvictionCandidates.end(), [](NodeEvictionCandidate const &n) { return n.m_is_local; }), vEvictionCandidates.end());
- // Calculate how many we removed, and update our total number of peers that
- // we want to protect based on uptime accordingly.
- total_protect_size -= initial_size - vEvictionCandidates.size();
- EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, total_protect_size);
+ // Protect some of the remaining eviction candidates by ratios of desirable
+ // or disadvantaged characteristics.
+ ProtectEvictionCandidatesByRatio(vEvictionCandidates);
if (vEvictionCandidates.empty()) return std::nullopt;
@@ -937,7 +972,7 @@ static void EraseLastKElements(std::vector<T> &elements, Comparator comparator,
for (const NodeEvictionCandidate &node : vEvictionCandidates) {
std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup];
group.push_back(node);
- int64_t grouptime = group[0].nTimeConnected;
+ const int64_t grouptime = group[0].nTimeConnected;
if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
nMostConnections = group.size();
@@ -985,7 +1020,8 @@ bool CConnman::AttemptToEvictConnection()
node->nLastBlockTime, node->nLastTXTime,
HasAllDesirableServiceFlags(node->nServices),
peer_relay_txes, peer_filter_not_null, node->nKeyedNetGroup,
- node->m_prefer_evict, node->addr.IsLocal()};
+ node->m_prefer_evict, node->addr.IsLocal(),
+ node->m_inbound_onion};
vEvictionCandidates.push_back(candidate);
}
}
@@ -2221,7 +2257,7 @@ void CConnman::ThreadI2PAcceptIncoming()
continue;
}
- CreateNodeFromAcceptedSocket(conn.sock.Release(), NetPermissionFlags::PF_NONE,
+ CreateNodeFromAcceptedSocket(conn.sock->Release(), NetPermissionFlags::PF_NONE,
CAddress{conn.me, NODE_NONE}, CAddress{conn.peer, NODE_NONE});
}
}
@@ -2351,8 +2387,8 @@ void CConnman::SetNetworkActive(bool active)
uiInterface.NotifyNetworkActiveChanged(fNetworkActive);
}
-CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, bool network_active)
- : nSeed0(nSeed0In), nSeed1(nSeed1In)
+CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, CAddrMan& addrman_in, bool network_active)
+ : addrman(addrman_in), nSeed0(nSeed0In), nSeed1(nSeed1In)
{
SetTryNewOutboundPeer(false);
@@ -2621,11 +2657,7 @@ void CConnman::StopNodes()
void CConnman::DeleteNode(CNode* pnode)
{
assert(pnode);
- bool fUpdateConnectionTime = false;
- m_msgproc->FinalizeNode(*pnode, fUpdateConnectionTime);
- if (fUpdateConnectionTime) {
- addrman.Connected(pnode->addr);
- }
+ m_msgproc->FinalizeNode(*pnode);
delete pnode;
}
@@ -2635,21 +2667,6 @@ CConnman::~CConnman()
Stop();
}
-void CConnman::SetServices(const CService &addr, ServiceFlags nServices)
-{
- addrman.SetServices(addr, nServices);
-}
-
-void CConnman::MarkAddressGood(const CAddress& addr)
-{
- addrman.Good(addr);
-}
-
-bool CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty)
-{
- return addrman.Add(vAddr, addrFrom, nTimePenalty);
-}
-
std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct)
{
std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct);
diff --git a/src/net.h b/src/net.h
index 66868be7c8..cae22969ce 100644
--- a/src/net.h
+++ b/src/net.h
@@ -425,6 +425,7 @@ public:
std::atomic<int64_t> nLastSend{0};
std::atomic<int64_t> nLastRecv{0};
+ //! Unix epoch time at peer connection, in seconds.
const int64_t nTimeConnected;
std::atomic<int64_t> nTimeOffset{0};
// Address of this peer
@@ -771,7 +772,7 @@ public:
virtual void InitializeNode(CNode* pnode) = 0;
/** Handle removal of a peer (clear state) */
- virtual void FinalizeNode(const CNode& node, bool& update_connection_time) = 0;
+ virtual void FinalizeNode(const CNode& node) = 0;
/**
* Process protocol messages received from a given node
@@ -857,7 +858,7 @@ public:
m_onion_binds = connOptions.onion_binds;
}
- CConnman(uint64_t seed0, uint64_t seed1, bool network_active = true);
+ CConnman(uint64_t seed0, uint64_t seed1, CAddrMan& addrman, bool network_active = true);
~CConnman();
bool Start(CScheduler& scheduler, const Options& options);
@@ -922,9 +923,6 @@ public:
};
// Addrman functions
- void SetServices(const CService &addr, ServiceFlags nServices);
- void MarkAddressGood(const CAddress& addr);
- bool AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct);
/**
* Cache is used to minimize topology leaks, so it should
@@ -1131,7 +1129,7 @@ private:
std::vector<ListenSocket> vhListenSocket;
std::atomic<bool> fNetworkActive{true};
bool fAddressesInitialized{false};
- CAddrMan addrman;
+ CAddrMan& addrman;
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
RecursiveMutex m_addr_fetches_mutex;
std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
@@ -1282,8 +1280,39 @@ struct NodeEvictionCandidate
uint64_t nKeyedNetGroup;
bool prefer_evict;
bool m_is_local;
+ bool m_is_onion;
};
+/**
+ * Select an inbound peer to evict after filtering out (protecting) peers having
+ * distinct, difficult-to-forge characteristics. The protection logic picks out
+ * fixed numbers of desirable peers per various criteria, followed by (mostly)
+ * ratios of desirable or disadvantaged peers. If any eviction candidates
+ * remain, the selection logic chooses a peer to evict.
+ */
[[nodiscard]] std::optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates);
+/** Protect desirable or disadvantaged inbound peers from eviction by ratio.
+ *
+ * This function protects half of the peers which have been connected the
+ * longest, to replicate the non-eviction implicit behavior and preclude attacks
+ * that start later.
+ *
+ * Half of these protected spots (1/4 of the total) are reserved for onion peers
+ * connected via our tor control service, if any, sorted by longest uptime, even
+ * if they're not longest uptime overall. Any remaining slots of the 1/4 are
+ * then allocated to protect localhost peers, if any (or up to 2 localhost peers
+ * if no slots remain and 2 or more onion peers were protected), sorted by
+ * longest uptime, as manually configured hidden services not using
+ * `-bind=addr[:port]=onion` will not be detected as inbound onion connections.
+ *
+ * This helps protect onion peers, which tend to be otherwise disadvantaged
+ * under our eviction criteria for their higher min ping times relative to IPv4
+ * and IPv6 peers, and favorise the diversity of peer connections.
+ *
+ * This function was extracted from SelectNodeToEvict() to be able to test the
+ * ratio-based protection logic deterministically.
+ */
+void ProtectEvictionCandidatesByRatio(std::vector<NodeEvictionCandidate>& vEvictionCandidates);
+
#endif // BITCOIN_NET_H
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 4fd37d3f76..14b628acf0 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -226,9 +226,9 @@ using PeerRef = std::shared_ptr<Peer>;
class PeerManagerImpl final : public PeerManager
{
public:
- PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
- CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
- bool ignore_incoming_txs);
+ PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
+ BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman,
+ CTxMemPool& pool, bool ignore_incoming_txs);
/** Overridden from CValidationInterface. */
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override;
@@ -239,7 +239,7 @@ public:
/** Implement NetEventsInterface */
void InitializeNode(CNode* pnode) override;
- void FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) override;
+ void FinalizeNode(const CNode& node) override;
bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override;
bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
@@ -328,6 +328,7 @@ private:
const CChainParams& m_chainparams;
CConnman& m_connman;
+ CAddrMan& m_addrman;
/** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
BanMan* const m_banman;
ChainstateManager& m_chainman;
@@ -974,13 +975,13 @@ void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler)
scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
}
-void PeerManagerImpl::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime)
+void PeerManagerImpl::FinalizeNode(const CNode& node)
{
NodeId nodeid = node.GetId();
- fUpdateConnectionTime = false;
- LOCK(cs_main);
int misbehavior{0};
{
+ LOCK(cs_main);
+ {
// We remove the PeerRef from g_peer_map here, but we don't always
// destruct the Peer. Sometimes another thread is still holding a
// PeerRef, so the refcount is >= 1. Be careful not to do any
@@ -996,12 +997,6 @@ void PeerManagerImpl::FinalizeNode(const CNode& node, bool& fUpdateConnectionTim
if (state->fSyncStarted)
nSyncStarted--;
- if (node.fSuccessfullyConnected && misbehavior == 0 &&
- !node.IsBlockOnlyConn() && !node.IsInboundConn()) {
- // Only change visible addrman state for outbound, full-relay peers
- fUpdateConnectionTime = true;
- }
-
for (const QueuedBlock& entry : state->vBlocksInFlight) {
mapBlocksInFlight.erase(entry.hash);
}
@@ -1026,6 +1021,14 @@ void PeerManagerImpl::FinalizeNode(const CNode& node, bool& fUpdateConnectionTim
assert(m_wtxid_relay_peers == 0);
assert(m_txrequest.Size() == 0);
}
+ } // cs_main
+ if (node.fSuccessfullyConnected && misbehavior == 0 &&
+ !node.IsBlockOnlyConn() && !node.IsInboundConn()) {
+ // Only change visible addrman state for full outbound peers. We don't
+ // call Connected() for feeler connections since they don't have
+ // fSuccessfullyConnected set.
+ m_addrman.Connected(node.addr);
+ }
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
}
@@ -1207,18 +1210,19 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
}
-std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
- CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
- bool ignore_incoming_txs)
+std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
+ BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman,
+ CTxMemPool& pool, bool ignore_incoming_txs)
{
- return std::make_unique<PeerManagerImpl>(chainparams, connman, banman, scheduler, chainman, pool, ignore_incoming_txs);
+ return std::make_unique<PeerManagerImpl>(chainparams, connman, addrman, banman, scheduler, chainman, pool, ignore_incoming_txs);
}
-PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
- CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
- bool ignore_incoming_txs)
+PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
+ BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman,
+ CTxMemPool& pool, bool ignore_incoming_txs)
: m_chainparams(chainparams),
m_connman(connman),
+ m_addrman(addrman),
m_banman(banman),
m_chainman(chainman),
m_mempool(pool),
@@ -2336,7 +2340,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
nServices = ServiceFlags(nServiceInt);
if (!pfrom.IsInboundConn())
{
- m_connman.SetServices(pfrom.addr, nServices);
+ m_addrman.SetServices(pfrom.addr, nServices);
}
if (pfrom.ExpectServicesFromConn() && !HasAllDesirableServiceFlags(nServices))
{
@@ -2480,7 +2484,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
//
// This moves an address from New to Tried table in Addrman,
// resolves tried-table collisions, etc.
- m_connman.MarkAddressGood(pfrom.addr);
+ m_addrman.Good(pfrom.addr);
}
std::string remoteAddr;
@@ -2685,7 +2689,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (fReachable)
vAddrOk.push_back(addr);
}
- m_connman.AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60);
+ m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
if (vAddr.size() < 1000)
pfrom.fGetAddr = false;
if (pfrom.IsAddrFetchConn()) {
@@ -4700,7 +4704,10 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
//
// Message: feefilter
//
- if (pto->m_tx_relay != nullptr && pto->GetCommonVersion() >= FEEFILTER_VERSION && gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ if (pto->m_tx_relay != nullptr &&
+ !m_ignore_incoming_txs &&
+ pto->GetCommonVersion() >= FEEFILTER_VERSION &&
+ gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
!pto->HasPermission(PF_FORCERELAY) // peers with the forcerelay permission should not filter txs to us
) {
CAmount currentFilter = m_mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
diff --git a/src/net_processing.h b/src/net_processing.h
index f6f2d73721..4556d32377 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -10,6 +10,7 @@
#include <sync.h>
#include <validationinterface.h>
+class CAddrMan;
class CChainParams;
class CTxMemPool;
class ChainstateManager;
@@ -36,9 +37,9 @@ struct CNodeStateStats {
class PeerManager : public CValidationInterface, public NetEventsInterface
{
public:
- static std::unique_ptr<PeerManager> make(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
- CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
- bool ignore_incoming_txs);
+ static std::unique_ptr<PeerManager> make(const CChainParams& chainparams, CConnman& connman, CAddrMan& addrman,
+ BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman,
+ CTxMemPool& pool, bool ignore_incoming_txs);
virtual ~PeerManager() { }
/** Get statistics from node state */
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 49e455aa84..2980bdf459 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -537,12 +537,12 @@ static void LogConnectFailure(bool manual_connection, const char* fmt, const Arg
}
}
-bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
+bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nTimeout, bool manual_connection)
{
// Create a sockaddr from the specified service.
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
- if (hSocket == INVALID_SOCKET) {
+ if (sock.Get() == INVALID_SOCKET) {
LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
return false;
}
@@ -552,8 +552,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
}
// Connect to the addrConnect service on the hSocket socket.
- if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
- {
+ if (sock.Connect(reinterpret_cast<struct sockaddr*>(&sockaddr), len) == SOCKET_ERROR) {
int nErr = WSAGetLastError();
// WSAEINVAL is here because some legacy version of winsock uses it
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
@@ -561,46 +560,34 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
// Connection didn't actually fail, but is being established
// asynchronously. Thus, use async I/O api (select/poll)
// synchronously to check for successful connection with a timeout.
-#ifdef USE_POLL
- struct pollfd pollfd = {};
- pollfd.fd = hSocket;
- pollfd.events = POLLIN | POLLOUT;
- int nRet = poll(&pollfd, 1, nTimeout);
-#else
- struct timeval timeout = MillisToTimeval(nTimeout);
- fd_set fdset;
- FD_ZERO(&fdset);
- FD_SET(hSocket, &fdset);
- int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
-#endif
- // Upon successful completion, both select and poll return the total
- // number of file descriptors that have been selected. A value of 0
- // indicates that the call timed out and no file descriptors have
- // been selected.
- if (nRet == 0)
- {
- LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
+ const Sock::Event requested = Sock::RECV | Sock::SEND;
+ Sock::Event occurred;
+ if (!sock.Wait(std::chrono::milliseconds{nTimeout}, requested, &occurred)) {
+ LogPrintf("wait for connect to %s failed: %s\n",
+ addrConnect.ToString(),
+ NetworkErrorString(WSAGetLastError()));
return false;
- }
- if (nRet == SOCKET_ERROR)
- {
- LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
+ } else if (occurred == 0) {
+ LogPrint(BCLog::NET, "connection attempt to %s timed out\n", addrConnect.ToString());
return false;
}
- // Even if the select/poll was successful, the connect might not
+ // Even if the wait was successful, the connect might not
// have been successful. The reason for this failure is hidden away
// in the SO_ERROR for the socket in modern systems. We read it into
- // nRet here.
- socklen_t nRetSize = sizeof(nRet);
- if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
- {
+ // sockerr here.
+ int sockerr;
+ socklen_t sockerr_len = sizeof(sockerr);
+ if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&sockerr, &sockerr_len) ==
+ SOCKET_ERROR) {
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
return false;
}
- if (nRet != 0)
- {
- LogConnectFailure(manual_connection, "connect() to %s failed after select(): %s", addrConnect.ToString(), NetworkErrorString(nRet));
+ if (sockerr != 0) {
+ LogConnectFailure(manual_connection,
+ "connect() to %s failed after wait: %s",
+ addrConnect.ToString(),
+ NetworkErrorString(sockerr));
return false;
}
}
@@ -668,7 +655,7 @@ bool IsProxy(const CNetAddr &addr) {
bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
{
// first connect to proxy server
- if (!ConnectSocketDirectly(proxy.proxy, sock.Get(), nTimeout, true)) {
+ if (!ConnectSocketDirectly(proxy.proxy, sock, nTimeout, true)) {
outProxyConnectionFailed = true;
return false;
}
diff --git a/src/netbase.h b/src/netbase.h
index 08172b9984..1f35c29dcb 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -194,7 +194,7 @@ extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
* Try to connect to the specified service on the specified socket.
*
* @param addrConnect The service to which to connect.
- * @param hSocket The socket on which to connect.
+ * @param sock The socket on which to connect.
* @param nTimeout Wait this many milliseconds for the connection to be
* established.
* @param manual_connection Whether or not the connection was manually requested
@@ -202,7 +202,7 @@ extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
*
* @returns Whether or not a connection was successfully made.
*/
-bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection);
+bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nTimeout, bool manual_connection);
/**
* Connect to a specified destination service through a SOCKS5 proxy by first
diff --git a/src/node/context.cpp b/src/node/context.cpp
index 958221a913..6d22a6b110 100644
--- a/src/node/context.cpp
+++ b/src/node/context.cpp
@@ -4,6 +4,7 @@
#include <node/context.h>
+#include <addrman.h>
#include <banman.h>
#include <interfaces/chain.h>
#include <net.h>
diff --git a/src/node/context.h b/src/node/context.h
index 9b611bf8f5..2be9a584e6 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -12,6 +12,7 @@
class ArgsManager;
class BanMan;
+class CAddrMan;
class CBlockPolicyEstimator;
class CConnman;
class CScheduler;
@@ -35,6 +36,7 @@ class WalletClient;
//! any member functions. It should just be a collection of references that can
//! be used without pulling in unwanted dependencies or functionality.
struct NodeContext {
+ std::unique_ptr<CAddrMan> addrman;
std::unique_ptr<CConnman> connman;
std::unique_ptr<CTxMemPool> mempool;
std::unique_ptr<CBlockPolicyEstimator> fee_estimator;
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 50c8c29175..0f4094e14b 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -38,7 +38,6 @@
#include <uint256.h>
#include <univalue.h>
#include <util/check.h>
-#include <util/ref.h>
#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
@@ -49,6 +48,7 @@
#include <config/bitcoin-config.h>
#endif
+#include <any>
#include <memory>
#include <optional>
#include <utility>
@@ -298,13 +298,13 @@ public:
{
m_context = context;
if (context) {
- m_context_ref.Set(*context);
+ m_context_ref = context;
} else {
- m_context_ref.Clear();
+ m_context_ref.reset();
}
}
NodeContext* m_context{nullptr};
- util::Ref m_context_ref;
+ std::any m_context_ref;
};
bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active)
diff --git a/src/qt/test/compattests.cpp b/src/qt/test/compattests.cpp
deleted file mode 100644
index c76dee5091..0000000000
--- a/src/qt/test/compattests.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
-#include <qt/test/compattests.h>
-
-#include <compat/byteswap.h>
-
-void CompatTests::bswapTests()
-{
- // Sibling in bitcoin/src/test/bswap_tests.cpp
- uint16_t u1 = 0x1234;
- uint32_t u2 = 0x56789abc;
- uint64_t u3 = 0xdef0123456789abc;
- uint16_t e1 = 0x3412;
- uint32_t e2 = 0xbc9a7856;
- uint64_t e3 = 0xbc9a78563412f0de;
- QVERIFY(bswap_16(u1) == e1);
- QVERIFY(bswap_32(u2) == e2);
- QVERIFY(bswap_64(u3) == e3);
-}
diff --git a/src/qt/test/compattests.h b/src/qt/test/compattests.h
deleted file mode 100644
index 1af97696b2..0000000000
--- a/src/qt/test/compattests.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2009-2016 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_QT_TEST_COMPATTESTS_H
-#define BITCOIN_QT_TEST_COMPATTESTS_H
-
-#include <QObject>
-#include <QTest>
-
-class CompatTests : public QObject
-{
- Q_OBJECT
-
-private Q_SLOTS:
- void bswapTests();
-};
-
-#endif // BITCOIN_QT_TEST_COMPATTESTS_H
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index a1baf6a402..eb86f027ef 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -11,7 +11,6 @@
#include <qt/test/apptests.h>
#include <qt/test/rpcnestedtests.h>
#include <qt/test/uritests.h>
-#include <qt/test/compattests.h>
#include <test/util/setup_common.h>
#ifdef ENABLE_WALLET
@@ -92,10 +91,6 @@ int main(int argc, char* argv[])
if (QTest::qExec(&test3) != 0) {
fInvalid = true;
}
- CompatTests test4;
- if (QTest::qExec(&test4) != 0) {
- fInvalid = true;
- }
#ifdef ENABLE_WALLET
WalletTests test5(app.node());
if (QTest::qExec(&test5) != 0) {
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index 9248db1539..fa2a3a0607 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -38,7 +38,7 @@
#include <sys/utsname.h>
#include <unistd.h>
#endif
-#if HAVE_DECL_GETIFADDRS
+#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
#include <ifaddrs.h>
#endif
#if HAVE_SYSCTL
@@ -361,7 +361,7 @@ void RandAddStaticEnv(CSHA512& hasher)
hasher.Write((const unsigned char*)hname, strnlen(hname, 256));
}
-#if HAVE_DECL_GETIFADDRS
+#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
// Network interfaces
struct ifaddrs *ifad = NULL;
getifaddrs(&ifad);
diff --git a/src/rest.cpp b/src/rest.cpp
index 71426a4dc4..aa97470ca7 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -18,10 +18,12 @@
#include <sync.h>
#include <txmempool.h>
#include <util/check.h>
-#include <util/ref.h>
+#include <util/system.h>
#include <validation.h>
#include <version.h>
+#include <any>
+
#include <boost/algorithm/string.hpp>
#include <univalue.h>
@@ -73,10 +75,10 @@ static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string me
* context is not found.
* @returns Pointer to the node context or nullptr if not found.
*/
-static NodeContext* GetNodeContext(const util::Ref& context, HTTPRequest* req)
+static NodeContext* GetNodeContext(const std::any& context, HTTPRequest* req)
{
- NodeContext* node = context.Has<NodeContext>() ? &context.Get<NodeContext>() : nullptr;
- if (!node) {
+ auto node_context = util::AnyPtr<NodeContext>(context);
+ if (!node_context) {
RESTERR(req, HTTP_INTERNAL_SERVER_ERROR,
strprintf("%s:%d (%s)\n"
"Internal bug detected: Node context not found!\n"
@@ -84,7 +86,7 @@ static NodeContext* GetNodeContext(const util::Ref& context, HTTPRequest* req)
__FILE__, __LINE__, __func__, PACKAGE_BUGREPORT));
return nullptr;
}
- return node;
+ return node_context;
}
/**
@@ -94,14 +96,14 @@ static NodeContext* GetNodeContext(const util::Ref& context, HTTPRequest* req)
* context mempool is not found.
* @returns Pointer to the mempool or nullptr if no mempool found.
*/
-static CTxMemPool* GetMemPool(const util::Ref& context, HTTPRequest* req)
+static CTxMemPool* GetMemPool(const std::any& context, HTTPRequest* req)
{
- NodeContext* node = context.Has<NodeContext>() ? &context.Get<NodeContext>() : nullptr;
- if (!node || !node->mempool) {
+ auto node_context = util::AnyPtr<NodeContext>(context);
+ if (!node_context || !node_context->mempool) {
RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found");
return nullptr;
}
- return node->mempool.get();
+ return node_context->mempool.get();
}
static RetFormat ParseDataFormat(std::string& param, const std::string& strReq)
@@ -151,7 +153,7 @@ static bool CheckWarmup(HTTPRequest* req)
return true;
}
-static bool rest_headers(const util::Ref& context,
+static bool rest_headers(const std::any& context,
HTTPRequest* req,
const std::string& strURIPart)
{
@@ -293,12 +295,12 @@ static bool rest_block(HTTPRequest* req,
}
}
-static bool rest_block_extended(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_block_extended(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
return rest_block(req, strURIPart, true);
}
-static bool rest_block_notxdetails(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_block_notxdetails(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
return rest_block(req, strURIPart, false);
}
@@ -306,7 +308,7 @@ static bool rest_block_notxdetails(const util::Ref& context, HTTPRequest* req, c
// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
RPCHelpMan getblockchaininfo();
-static bool rest_chaininfo(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_chaininfo(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
if (!CheckWarmup(req))
return false;
@@ -329,7 +331,7 @@ static bool rest_chaininfo(const util::Ref& context, HTTPRequest* req, const std
}
}
-static bool rest_mempool_info(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_mempool_info(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
if (!CheckWarmup(req))
return false;
@@ -353,7 +355,7 @@ static bool rest_mempool_info(const util::Ref& context, HTTPRequest* req, const
}
}
-static bool rest_mempool_contents(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_mempool_contents(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
if (!CheckWarmup(req)) return false;
const CTxMemPool* mempool = GetMemPool(context, req);
@@ -376,7 +378,7 @@ static bool rest_mempool_contents(const util::Ref& context, HTTPRequest* req, co
}
}
-static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
if (!CheckWarmup(req))
return false;
@@ -435,7 +437,7 @@ static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::strin
}
}
-static bool rest_getutxos(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
if (!CheckWarmup(req))
return false;
@@ -621,7 +623,7 @@ static bool rest_getutxos(const util::Ref& context, HTTPRequest* req, const std:
}
}
-static bool rest_blockhash_by_height(const util::Ref& context, HTTPRequest* req,
+static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req,
const std::string& str_uri_part)
{
if (!CheckWarmup(req)) return false;
@@ -669,7 +671,7 @@ static bool rest_blockhash_by_height(const util::Ref& context, HTTPRequest* req,
static const struct {
const char* prefix;
- bool (*handler)(const util::Ref& context, HTTPRequest* req, const std::string& strReq);
+ bool (*handler)(const std::any& context, HTTPRequest* req, const std::string& strReq);
} uri_prefixes[] = {
{"/rest/tx/", rest_tx},
{"/rest/block/notxdetails/", rest_block_notxdetails},
@@ -682,7 +684,7 @@ static const struct {
{"/rest/blockhashbyheight/", rest_blockhash_by_height},
};
-void StartREST(const util::Ref& context)
+void StartREST(const std::any& context)
{
for (const auto& up : uri_prefixes) {
auto handler = [&context, up](HTTPRequest* req, const std::string& prefix) { return up.handler(context, req, prefix); };
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 3ba2fa46ae..961478155f 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -30,7 +30,6 @@
#include <txdb.h>
#include <txmempool.h>
#include <undo.h>
-#include <util/ref.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/translation.h>
@@ -56,15 +55,16 @@ static Mutex cs_blockchange;
static std::condition_variable cond_blockchange;
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
-NodeContext& EnsureNodeContext(const util::Ref& context)
+NodeContext& EnsureNodeContext(const std::any& context)
{
- if (!context.Has<NodeContext>()) {
+ auto node_context = util::AnyPtr<NodeContext>(context);
+ if (!node_context) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Node context not found");
}
- return context.Get<NodeContext>();
+ return *node_context;
}
-CTxMemPool& EnsureMemPool(const util::Ref& context)
+CTxMemPool& EnsureMemPool(const std::any& context)
{
const NodeContext& node = EnsureNodeContext(context);
if (!node.mempool) {
@@ -73,7 +73,7 @@ CTxMemPool& EnsureMemPool(const util::Ref& context)
return *node.mempool;
}
-ChainstateManager& EnsureChainman(const util::Ref& context)
+ChainstateManager& EnsureChainman(const std::any& context)
{
const NodeContext& node = EnsureNodeContext(context);
if (!node.chainman) {
@@ -82,7 +82,7 @@ ChainstateManager& EnsureChainman(const util::Ref& context)
return *node.chainman;
}
-CBlockPolicyEstimator& EnsureFeeEstimator(const util::Ref& context)
+CBlockPolicyEstimator& EnsureFeeEstimator(const std::any& context)
{
NodeContext& node = EnsureNodeContext(context);
if (!node.fee_estimator) {
@@ -1113,11 +1113,13 @@ static RPCHelpMan gettxout()
{RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
{RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
{RPCResult::Type::OBJ, "scriptPubKey", "", {
- {RPCResult::Type::STR_HEX, "asm", ""},
+ {RPCResult::Type::STR, "asm", ""},
{RPCResult::Type::STR_HEX, "hex", ""},
- {RPCResult::Type::NUM, "reqSigs", "Number of required signatures"},
- {RPCResult::Type::STR_HEX, "type", "The type, eg pubkeyhash"},
- {RPCResult::Type::ARR, "addresses", "array of bitcoin addresses", {{RPCResult::Type::STR, "address", "bitcoin address"}}},
+ {RPCResult::Type::NUM, "reqSigs", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures"},
+ {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
+ {RPCResult::Type::STR, "address", /* optional */ true, "bitcoin address (only if a well-defined address exists)"},
+ {RPCResult::Type::ARR, "addresses", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of bitcoin addresses",
+ {{RPCResult::Type::STR, "address", "bitcoin address"}}},
}},
{RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
}},
@@ -1775,6 +1777,16 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],
}
}
+void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
+{
+ ScriptPubKeyToUniv(scriptPubKey, out, fIncludeHex, IsDeprecatedRPCEnabled("addresses"));
+}
+
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo)
+{
+ TxToUniv(tx, hashBlock, IsDeprecatedRPCEnabled("addresses"), entry, include_hex, serialize_flags, txundo);
+}
+
template<typename T>
static inline bool SetHasKeys(const std::set<T>& set) {return false;}
template<typename T, typename Tk, typename... Args>
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index d8cae4dd24..cd04c9a10f 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -6,9 +6,11 @@
#define BITCOIN_RPC_BLOCKCHAIN_H
#include <amount.h>
+#include <core_io.h>
#include <streams.h>
#include <sync.h>
+#include <any>
#include <stdint.h>
#include <vector>
@@ -22,9 +24,6 @@ class CTxMemPool;
class ChainstateManager;
class UniValue;
struct NodeContext;
-namespace util {
-class Ref;
-} // namespace util
static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
@@ -54,10 +53,13 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
/** Used by getblockstats to get feerates at different percentiles by weight */
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight);
-NodeContext& EnsureNodeContext(const util::Ref& context);
-CTxMemPool& EnsureMemPool(const util::Ref& context);
-ChainstateManager& EnsureChainman(const util::Ref& context);
-CBlockPolicyEstimator& EnsureFeeEstimator(const util::Ref& context);
+void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr);
+
+NodeContext& EnsureNodeContext(const std::any& context);
+CTxMemPool& EnsureMemPool(const std::any& context);
+ChainstateManager& EnsureChainman(const std::any& context);
+CBlockPolicyEstimator& EnsureFeeEstimator(const std::any& context);
/**
* Helper to create UTXO snapshots given a chainstate and a file handle.
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 143be1274e..1df5c51718 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -17,7 +17,6 @@
#include <script/descriptor.h>
#include <util/check.h>
#include <util/message.h> // For MessageSign(), MessageVerify()
-#include <util/ref.h>
#include <util/strencodings.h>
#include <util/system.h>
@@ -391,8 +390,9 @@ static RPCHelpMan setmocktime()
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime can not be negative: %s.", time));
}
SetMockTime(time);
- if (request.context.Has<NodeContext>()) {
- for (const auto& chain_client : request.context.Get<NodeContext>().chain_clients) {
+ auto node_context = util::AnyPtr<NodeContext>(request.context);
+ if (node_context) {
+ for (const auto& chain_client : node_context->chain_clients) {
chain_client->setMockTime(time);
}
}
@@ -424,11 +424,11 @@ static RPCHelpMan mockscheduler()
throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)");
}
+ auto node_context = util::AnyPtr<NodeContext>(request.context);
// protect against null pointer dereference
- CHECK_NONFATAL(request.context.Has<NodeContext>());
- NodeContext& node = request.context.Get<NodeContext>();
- CHECK_NONFATAL(node.scheduler);
- node.scheduler->MockForward(std::chrono::seconds(delta_seconds));
+ CHECK_NONFATAL(node_context);
+ CHECK_NONFATAL(node_context->scheduler);
+ node_context->scheduler->MockForward(std::chrono::seconds(delta_seconds));
return NullUniValue;
},
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index d4c1ab4b53..96533a50c8 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -907,8 +907,8 @@ static RPCHelpMan addpeeraddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
NodeContext& node = EnsureNodeContext(request.context);
- if (!node.connman) {
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ if (!node.addrman) {
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Address manager functionality missing or disabled");
}
UniValue obj(UniValue::VOBJ);
@@ -925,7 +925,7 @@ static RPCHelpMan addpeeraddress()
address.nTime = GetAdjustedTime();
// The source address is set equal to the address. This is equivalent to the peer
// announcing itself.
- if (!node.connman->AddNewAddresses({address}, address)) {
+ if (!node.addrman->Add(address, address)) {
obj.pushKV("success", false);
return obj;
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 2f92a321f8..7932bd2915 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -35,7 +35,6 @@
#include <validation.h>
#include <validationinterface.h>
-
#include <numeric>
#include <stdint.h>
@@ -132,9 +131,10 @@ static RPCHelpMan getrawtransaction()
{
{RPCResult::Type::STR, "asm", "the asm"},
{RPCResult::Type::STR, "hex", "the hex"},
- {RPCResult::Type::NUM, "reqSigs", "The required sigs"},
+ {RPCResult::Type::NUM, "reqSigs", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
- {RPCResult::Type::ARR, "addresses", "",
+ {RPCResult::Type::STR, "address", /* optional */ true, "bitcoin address (only if a well-defined address exists)"},
+ {RPCResult::Type::ARR, "addresses", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of bitcoin addresses",
{
{RPCResult::Type::STR, "address", "bitcoin address"},
}},
@@ -490,9 +490,10 @@ static RPCHelpMan decoderawtransaction()
{
{RPCResult::Type::STR, "asm", "the asm"},
{RPCResult::Type::STR_HEX, "hex", "the hex"},
- {RPCResult::Type::NUM, "reqSigs", "The required sigs"},
+ {RPCResult::Type::NUM, "reqSigs", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
- {RPCResult::Type::ARR, "addresses", "",
+ {RPCResult::Type::STR, "address", /* optional */ true, "bitcoin address (only if a well-defined address exists)"},
+ {RPCResult::Type::ARR, "addresses", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of bitcoin addresses",
{
{RPCResult::Type::STR, "address", "bitcoin address"},
}},
@@ -548,8 +549,9 @@ static RPCHelpMan decodescript()
{
{RPCResult::Type::STR, "asm", "Script public key"},
{RPCResult::Type::STR, "type", "The output type (e.g. "+GetAllOutputTypes()+")"},
- {RPCResult::Type::NUM, "reqSigs", "The required signatures"},
- {RPCResult::Type::ARR, "addresses", "",
+ {RPCResult::Type::STR, "address", /* optional */ true, "bitcoin address (only if a well-defined address exists)"},
+ {RPCResult::Type::NUM, "reqSigs", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures"},
+ {RPCResult::Type::ARR, "addresses", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of bitcoin addresses",
{
{RPCResult::Type::STR, "address", "bitcoin address"},
}},
@@ -559,8 +561,9 @@ static RPCHelpMan decodescript()
{RPCResult::Type::STR, "asm", "String representation of the script public key"},
{RPCResult::Type::STR_HEX, "hex", "Hex string of the script public key"},
{RPCResult::Type::STR, "type", "The type of the script public key (e.g. witness_v0_keyhash or witness_v0_scripthash)"},
- {RPCResult::Type::NUM, "reqSigs", "The required signatures (always 1)"},
- {RPCResult::Type::ARR, "addresses", "(always length 1)",
+ {RPCResult::Type::STR, "address", /* optional */ true, "bitcoin address (only if a well-defined address exists)"},
+ {RPCResult::Type::NUM, "reqSigs", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures"},
+ {RPCResult::Type::ARR, "addresses", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of bitcoin addresses",
{
{RPCResult::Type::STR, "address", "segwit address"},
}},
diff --git a/src/rpc/request.h b/src/rpc/request.h
index 27d06f3c92..e1569673f6 100644
--- a/src/rpc/request.h
+++ b/src/rpc/request.h
@@ -6,14 +6,11 @@
#ifndef BITCOIN_RPC_REQUEST_H
#define BITCOIN_RPC_REQUEST_H
+#include <any>
#include <string>
#include <univalue.h>
-namespace util {
-class Ref;
-} // namespace util
-
UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
@@ -38,14 +35,14 @@ public:
std::string URI;
std::string authUser;
std::string peerAddr;
- const util::Ref& context;
+ const std::any& context;
- explicit JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), context(context) {}
+ explicit JSONRPCRequest(const std::any& context) : id(NullUniValue), params(NullUniValue), context(context) {}
//! Initializes request information from another request object and the
//! given context. The implementation should be updated if any members are
//! added or removed above.
- JSONRPCRequest(const JSONRPCRequest& other, const util::Ref& context)
+ JSONRPCRequest(const JSONRPCRequest& other, const std::any& context)
: id(other.id), strMethod(other.strMethod), params(other.params), mode(other.mode), URI(other.URI),
authUser(other.authUser), peerAddr(other.peerAddr), context(context)
{
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 39938f4eb9..2f05c8842f 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -87,7 +87,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front()));
sort(vCommands.begin(), vCommands.end());
- JSONRPCRequest jreq(helpreq);
+ JSONRPCRequest jreq = helpreq;
jreq.mode = JSONRPCRequest::GET_HELP;
jreq.params = UniValue();
@@ -494,7 +494,7 @@ std::vector<std::string> CRPCTable::listCommands() const
UniValue CRPCTable::dumpArgMap(const JSONRPCRequest& args_request) const
{
- JSONRPCRequest request(args_request);
+ JSONRPCRequest request = args_request;
request.mode = JSONRPCRequest::GET_ARGS;
UniValue ret{UniValue::VARR};
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 4d882cd1f1..700155c8d4 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -220,7 +220,6 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
return true;
}
case TxoutType::MULTISIG:
- // Multisig txns have more than one address...
case TxoutType::NULL_DATA:
case TxoutType::NONSTANDARD:
return false;
@@ -228,6 +227,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
assert(false);
}
+// TODO: from v23 ("addresses" and "reqSigs" deprecated) "ExtractDestinations" should be removed
bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
{
addressRet.clear();
diff --git a/src/script/standard.h b/src/script/standard.h
index d5d87392ad..f2bf4a8af3 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -247,6 +247,8 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
* Note: this function confuses destinations (a subset of CScripts that are
* encodable as an address) with key identifiers (of keys involved in a
* CScript), and its use should be phased out.
+ *
+ * TODO: from v23 ("addresses" and "reqSigs" deprecated) "ExtractDestinations" should be removed
*/
bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp
index c89cb5488d..2dbca4e8b6 100644
--- a/src/test/bswap_tests.cpp
+++ b/src/test/bswap_tests.cpp
@@ -11,7 +11,6 @@ BOOST_FIXTURE_TEST_SUITE(bswap_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(bswap_tests)
{
- // Sibling in bitcoin/src/qt/test/compattests.cpp
uint16_t u1 = 0x1234;
uint32_t u2 = 0x56789abc;
uint64_t u3 = 0xdef0123456789abc;
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index e75982bc6f..7557d4618a 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -67,9 +67,9 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
const CChainParams& chainparams = Params();
- auto connman = std::make_unique<CConnman>(0x1337, 0x1337);
- auto peerLogic = PeerManager::make(chainparams, *connman, nullptr, *m_node.scheduler,
- *m_node.chainman, *m_node.mempool, false);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
+ auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
+ *m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
// Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
@@ -117,8 +117,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
BOOST_CHECK(dummyNode1.fDisconnect == true);
SetMockTime(0);
- bool dummy;
- peerLogic->FinalizeNode(dummyNode1, dummy);
+ peerLogic->FinalizeNode(dummyNode1);
}
static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerManager &peerLogic, CConnmanTest* connman)
@@ -137,9 +136,9 @@ static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerManager &pee
BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{
const CChainParams& chainparams = Params();
- auto connman = std::make_unique<CConnmanTest>(0x1337, 0x1337);
- auto peerLogic = PeerManager::make(chainparams, *connman, nullptr, *m_node.scheduler,
- *m_node.chainman, *m_node.mempool, false);
+ auto connman = std::make_unique<CConnmanTest>(0x1337, 0x1337, *m_node.addrman);
+ auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
+ *m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
CConnman::Options options;
@@ -199,9 +198,8 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true);
BOOST_CHECK(vNodes.back()->fDisconnect == false);
- bool dummy;
for (const CNode *node : vNodes) {
- peerLogic->FinalizeNode(*node, dummy);
+ peerLogic->FinalizeNode(*node);
}
connman->ClearNodes();
@@ -211,9 +209,9 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
{
const CChainParams& chainparams = Params();
auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = std::make_unique<CConnman>(0x1337, 0x1337);
- auto peerLogic = PeerManager::make(chainparams, *connman, banman.get(), *m_node.scheduler,
- *m_node.chainman, *m_node.mempool, false);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
+ auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
+ *m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
banman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
@@ -249,18 +247,17 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_CHECK(banman->IsDiscouraged(addr1)); // Expect both 1 and 2
BOOST_CHECK(banman->IsDiscouraged(addr2)); // to be discouraged now
- bool dummy;
- peerLogic->FinalizeNode(dummyNode1, dummy);
- peerLogic->FinalizeNode(dummyNode2, dummy);
+ peerLogic->FinalizeNode(dummyNode1);
+ peerLogic->FinalizeNode(dummyNode2);
}
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
const CChainParams& chainparams = Params();
auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = std::make_unique<CConnman>(0x1337, 0x1337);
- auto peerLogic = PeerManager::make(chainparams, *connman, banman.get(), *m_node.scheduler,
- *m_node.chainman, *m_node.mempool, false);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
+ auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
+ *m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
banman->ClearBanned();
int64_t nStartTime = GetTime();
@@ -279,8 +276,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
}
BOOST_CHECK(banman->IsDiscouraged(addr));
- bool dummy;
- peerLogic->FinalizeNode(dummyNode, dummy);
+ peerLogic->FinalizeNode(dummyNode);
}
class TxOrphanageTest : public TxOrphanage
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index d951bda20f..b21d2eae79 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -230,11 +230,8 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
// consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed.
return;
}
- try {
- (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out);
- assert(MoneyRange(tx_fee_out));
- } catch (const std::runtime_error&) {
- }
+ (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out);
+ assert(MoneyRange(tx_fee_out));
},
[&] {
const CTransaction transaction{random_mutable_transaction};
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index ae77a45e44..e07f25dedf 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -25,40 +25,25 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
- CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeBool()};
- CAddress random_address;
+ CAddrMan addrman;
+ CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()};
CNetAddr random_netaddr;
CNode random_node = ConsumeNode(fuzzed_data_provider);
- CService random_service;
CSubNet random_subnet;
std::string random_string;
while (fuzzed_data_provider.ConsumeBool()) {
CallOneOf(
fuzzed_data_provider,
[&] {
- random_address = ConsumeAddress(fuzzed_data_provider);
- },
- [&] {
random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
},
[&] {
- random_service = ConsumeService(fuzzed_data_provider);
- },
- [&] {
random_subnet = ConsumeSubNet(fuzzed_data_provider);
},
[&] {
random_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
},
[&] {
- std::vector<CAddress> addresses;
- while (fuzzed_data_provider.ConsumeBool()) {
- addresses.push_back(ConsumeAddress(fuzzed_data_provider));
- }
- // Limit nTimePenalty to int32_t to avoid signed integer overflow
- (void)connman.AddNewAddresses(addresses, ConsumeAddress(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>());
- },
- [&] {
connman.AddNode(random_string);
},
[&] {
@@ -98,9 +83,6 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
(void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({ConnectionDirection::None, ConnectionDirection::In, ConnectionDirection::Out, ConnectionDirection::Both}));
},
[&] {
- connman.MarkAddressGood(random_address);
- },
- [&] {
(void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool());
},
[&] {
@@ -128,9 +110,6 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
},
[&] {
- connman.SetServices(random_service, ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
- },
- [&] {
connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
});
}
diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp
new file mode 100644
index 0000000000..345d68502a
--- /dev/null
+++ b/src/test/fuzz/i2p.cpp
@@ -0,0 +1,57 @@
+// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <i2p.h>
+#include <netaddress.h>
+#include <netbase.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <threadinterrupt.h>
+#include <util/system.h>
+
+void initialize_i2p()
+{
+ static const auto testing_setup = MakeNoLogFileContext<>();
+}
+
+FUZZ_TARGET_INIT(i2p, initialize_i2p)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
+ // Mock CreateSock() to create FuzzedSock.
+ auto CreateSockOrig = CreateSock;
+ CreateSock = [&fuzzed_data_provider](const CService&) {
+ return std::make_unique<FuzzedSock>(fuzzed_data_provider);
+ };
+
+ const CService sam_proxy;
+ CThreadInterrupt interrupt;
+
+ i2p::sam::Session sess{GetDataDir() / "fuzzed_i2p_private_key", sam_proxy, &interrupt};
+
+ i2p::Connection conn;
+
+ if (sess.Listen(conn)) {
+ if (sess.Accept(conn)) {
+ try {
+ conn.sock->RecvUntilTerminator('\n', 10ms, interrupt, i2p::sam::MAX_MSG_SIZE);
+ } catch (const std::runtime_error&) {
+ }
+ }
+ }
+
+ const CService to;
+ bool proxy_error;
+
+ if (sess.Connect(to, conn, proxy_error)) {
+ try {
+ conn.sock->SendComplete("verack\n", 10ms, interrupt);
+ } catch (const std::runtime_error&) {
+ }
+ }
+
+ CreateSock = CreateSockOrig;
+}
diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp
index 603d520cf5..70ffc6bf37 100644
--- a/src/test/fuzz/node_eviction.cpp
+++ b/src/test/fuzz/node_eviction.cpp
@@ -31,6 +31,7 @@ FUZZ_TARGET(node_eviction)
/* nKeyedNetGroup */ fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
/* prefer_evict */ fuzzed_data_provider.ConsumeBool(),
/* m_is_local */ fuzzed_data_provider.ConsumeBool(),
+ /* m_is_onion */ fuzzed_data_provider.ConsumeBool(),
});
}
// Make a copy since eviction_candidates may be in some valid but otherwise
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index 8219a04e49..e87ae5b04b 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -103,9 +103,11 @@ FUZZ_TARGET_INIT(script, initialize_script)
(void)ScriptToAsmStr(script, true);
UniValue o1(UniValue::VOBJ);
- ScriptPubKeyToUniv(script, o1, true);
+ ScriptPubKeyToUniv(script, o1, true, true);
+ ScriptPubKeyToUniv(script, o1, true, false);
UniValue o2(UniValue::VOBJ);
- ScriptPubKeyToUniv(script, o2, false);
+ ScriptPubKeyToUniv(script, o2, false, true);
+ ScriptPubKeyToUniv(script, o2, false, false);
UniValue o3(UniValue::VOBJ);
ScriptToUniv(script, o3, true);
UniValue o4(UniValue::VOBJ);
diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp
index 561230707c..387f9c069c 100644
--- a/src/test/fuzz/script_flags.cpp
+++ b/src/test/fuzz/script_flags.cpp
@@ -5,13 +5,11 @@
#include <pubkey.h>
#include <script/interpreter.h>
#include <streams.h>
+#include <test/util/script.h>
#include <version.h>
#include <test/fuzz/fuzz.h>
-/** Flags that are not forbidden by an assert */
-static bool IsValidFlagCombination(unsigned flags);
-
void initialize_script_flags()
{
static const ECCVerifyHandle verify_handle;
@@ -74,10 +72,3 @@ FUZZ_TARGET_INIT(script_flags, initialize_script_flags)
return;
}
}
-
-static bool IsValidFlagCombination(unsigned flags)
-{
- if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
- if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
- return true;
-}
diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp
index 7b57c5dfd8..6b86c8889d 100644
--- a/src/test/fuzz/signature_checker.cpp
+++ b/src/test/fuzz/signature_checker.cpp
@@ -6,6 +6,8 @@
#include <script/interpreter.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/script.h>
#include <cstdint>
#include <limits>
@@ -56,17 +58,12 @@ FUZZ_TARGET_INIT(signature_checker, initialize_signature_checker)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
const SigVersion sig_version = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
- const std::string script_string_1 = fuzzed_data_provider.ConsumeRandomLengthString(65536);
- const std::vector<uint8_t> script_bytes_1{script_string_1.begin(), script_string_1.end()};
- const std::string script_string_2 = fuzzed_data_provider.ConsumeRandomLengthString(65536);
- const std::vector<uint8_t> script_bytes_2{script_string_2.begin(), script_string_2.end()};
+ const auto script_1 = ConsumeScript(fuzzed_data_provider, 65536);
+ const auto script_2 = ConsumeScript(fuzzed_data_provider, 65536);
std::vector<std::vector<unsigned char>> stack;
- (void)EvalScript(stack, {script_bytes_1.begin(), script_bytes_1.end()}, flags, FuzzedSignatureChecker(fuzzed_data_provider), sig_version, nullptr);
- if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0 && ((flags & SCRIPT_VERIFY_P2SH) == 0 || (flags & SCRIPT_VERIFY_WITNESS) == 0)) {
+ (void)EvalScript(stack, script_1, flags, FuzzedSignatureChecker(fuzzed_data_provider), sig_version, nullptr);
+ if (!IsValidFlagCombination(flags)) {
return;
}
- if ((flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
- return;
- }
- (void)VerifyScript({script_bytes_1.begin(), script_bytes_1.end()}, {script_bytes_2.begin(), script_bytes_2.end()}, nullptr, flags, FuzzedSignatureChecker(fuzzed_data_provider), nullptr);
+ (void)VerifyScript(script_1, script_2, nullptr, flags, FuzzedSignatureChecker(fuzzed_data_provider), nullptr);
}
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 41e1687405..17e4405a13 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -100,7 +100,9 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
(void)IsWitnessStandard(tx, coins_view_cache);
UniValue u(UniValue::VOBJ);
- TxToUniv(tx, /* hashBlock */ {}, u);
+ TxToUniv(tx, /* hashBlock */ {}, /* include_addresses */ true, u);
+ TxToUniv(tx, /* hashBlock */ {}, /* include_addresses */ false, u);
static const uint256 u256_max(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
- TxToUniv(tx, u256_max, u);
+ TxToUniv(tx, u256_max, /* include_addresses */ true, u);
+ TxToUniv(tx, u256_max, /* include_addresses */ false, u);
}
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index 93418ab1ff..d786ac1db1 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -80,7 +80,7 @@ CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, co
CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length, const bool maybe_p2wsh) noexcept
{
- const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
CScript r_script{b.begin(), b.end()};
if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) {
uint256 script_hash;
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index d5c54911c5..50d3ac66e5 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -567,36 +567,37 @@ class FuzzedSock : public Sock
{
FuzzedDataProvider& m_fuzzed_data_provider;
+ /**
+ * Data to return when `MSG_PEEK` is used as a `Recv()` flag.
+ * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next
+ * `Recv()` call we must return the same data, thus we remember it here.
+ */
+ mutable std::optional<uint8_t> m_peek_data;
+
public:
explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}
{
+ m_socket = fuzzed_data_provider.ConsumeIntegral<SOCKET>();
}
~FuzzedSock() override
{
+ // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
+ // Sock::Reset() (not FuzzedSock::Reset()!) which will call CloseSocket(m_socket).
+ // Avoid closing an arbitrary file descriptor (m_socket is just a random number which
+ // may concide with a real opened file descriptor).
+ Reset();
}
FuzzedSock& operator=(Sock&& other) override
{
- assert(false && "Not implemented yet.");
+ assert(false && "Move of Sock into FuzzedSock not allowed.");
return *this;
}
- SOCKET Get() const override
- {
- assert(false && "Not implemented yet.");
- return INVALID_SOCKET;
- }
-
- SOCKET Release() override
- {
- assert(false && "Not implemented yet.");
- return INVALID_SOCKET;
- }
-
void Reset() override
{
- assert(false && "Not implemented yet.");
+ m_socket = INVALID_SOCKET;
}
ssize_t Send(const void* data, size_t len, int flags) const override
@@ -633,10 +634,13 @@ public:
ssize_t Recv(void* buf, size_t len, int flags) const override
{
+ // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
+ // returning -1 and setting errno to EAGAIN repeatedly.
constexpr std::array recv_errnos{
+ ECONNREFUSED,
EAGAIN,
EBADF,
- ECONNREFUSED,
EFAULT,
EINTR,
EINVAL,
@@ -653,8 +657,26 @@ public:
}
return r;
}
- const std::vector<uint8_t> random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
- m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
+ std::vector<uint8_t> random_bytes;
+ bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
+ if (m_peek_data.has_value()) {
+ // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
+ random_bytes.assign({m_peek_data.value()});
+ if ((flags & MSG_PEEK) == 0) {
+ m_peek_data.reset();
+ }
+ pad_to_len_bytes = false;
+ } else if ((flags & MSG_PEEK) != 0) {
+ // New call with `MSG_PEEK`.
+ random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
+ if (!random_bytes.empty()) {
+ m_peek_data = random_bytes[0];
+ pad_to_len_bytes = false;
+ }
+ } else {
+ random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
+ m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
+ }
if (random_bytes.empty()) {
const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
if (r == -1) {
@@ -663,7 +685,7 @@ public:
return r;
}
std::memcpy(buf, random_bytes.data(), random_bytes.size());
- if (m_fuzzed_data_provider.ConsumeBool()) {
+ if (pad_to_len_bytes) {
if (len > random_bytes.size()) {
std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
}
@@ -675,10 +697,59 @@ public:
return random_bytes.size();
}
+ int Connect(const sockaddr*, socklen_t) const override
+ {
+ // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
+ // returning -1 and setting errno to EAGAIN repeatedly.
+ constexpr std::array connect_errnos{
+ ECONNREFUSED,
+ EAGAIN,
+ ECONNRESET,
+ EHOSTUNREACH,
+ EINPROGRESS,
+ EINTR,
+ ENETUNREACH,
+ ETIMEDOUT,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
+ return -1;
+ }
+ return 0;
+ }
+
+ int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override
+ {
+ constexpr std::array getsockopt_errnos{
+ ENOMEM,
+ ENOBUFS,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
+ return -1;
+ }
+ if (opt_val == nullptr) {
+ return 0;
+ }
+ std::memcpy(opt_val,
+ ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(),
+ *opt_len);
+ return 0;
+ }
+
bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override
{
return m_fuzzed_data_provider.ConsumeBool();
}
+
+ bool IsConnected(std::string& errmsg) const override {
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ return true;
+ }
+ errmsg = "disconnected at random by the fuzzer";
+ return false;
+ }
};
[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp
new file mode 100644
index 0000000000..334f71106c
--- /dev/null
+++ b/src/test/i2p_tests.cpp
@@ -0,0 +1,44 @@
+// Copyright (c) 2021-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <i2p.h>
+#include <netaddress.h>
+#include <test/util/logging.h>
+#include <test/util/net.h>
+#include <test/util/setup_common.h>
+#include <threadinterrupt.h>
+#include <util/system.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <memory>
+#include <string>
+
+BOOST_FIXTURE_TEST_SUITE(i2p_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(unlimited_recv)
+{
+ auto CreateSockOrig = CreateSock;
+
+ // Mock CreateSock() to create MockSock.
+ CreateSock = [](const CService&) {
+ return std::make_unique<StaticContentsSock>(std::string(i2p::sam::MAX_MSG_SIZE + 1, 'a'));
+ };
+
+ CThreadInterrupt interrupt;
+ i2p::sam::Session session(GetDataDir() / "test_i2p_private_key", CService{}, &interrupt);
+
+ {
+ ASSERT_DEBUG_LOG("Creating SAM session");
+ ASSERT_DEBUG_LOG("too many bytes without a terminator");
+
+ i2p::Connection conn;
+ bool proxy_error;
+ BOOST_REQUIRE(!session.Connect(CService{}, conn, proxy_error));
+ }
+
+ CreateSock = CreateSockOrig;
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/net_peer_eviction_tests.cpp b/src/test/net_peer_eviction_tests.cpp
new file mode 100644
index 0000000000..31d391bf7d
--- /dev/null
+++ b/src/test/net_peer_eviction_tests.cpp
@@ -0,0 +1,348 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <net.h>
+#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <optional>
+#include <unordered_set>
+#include <vector>
+
+BOOST_FIXTURE_TEST_SUITE(net_peer_eviction_tests, BasicTestingSetup)
+
+namespace {
+constexpr int NODE_EVICTION_TEST_ROUNDS{10};
+constexpr int NODE_EVICTION_TEST_UP_TO_N_NODES{200};
+} // namespace
+
+std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(const int n_candidates, FastRandomContext& random_context)
+{
+ std::vector<NodeEvictionCandidate> candidates;
+ for (int id = 0; id < n_candidates; ++id) {
+ candidates.push_back({
+ /* id */ id,
+ /* nTimeConnected */ static_cast<int64_t>(random_context.randrange(100)),
+ /* m_min_ping_time */ std::chrono::microseconds{random_context.randrange(100)},
+ /* nLastBlockTime */ static_cast<int64_t>(random_context.randrange(100)),
+ /* nLastTXTime */ static_cast<int64_t>(random_context.randrange(100)),
+ /* fRelevantServices */ random_context.randbool(),
+ /* fRelayTxes */ random_context.randbool(),
+ /* fBloomFilter */ random_context.randbool(),
+ /* nKeyedNetGroup */ random_context.randrange(100),
+ /* prefer_evict */ random_context.randbool(),
+ /* m_is_local */ random_context.randbool(),
+ /* m_is_onion */ random_context.randbool(),
+ });
+ }
+ return candidates;
+}
+
+// Create `num_peers` random nodes, apply setup function `candidate_setup_fn`,
+// call ProtectEvictionCandidatesByRatio() to apply protection logic, and then
+// return true if all of `protected_peer_ids` and none of `unprotected_peer_ids`
+// are protected from eviction, i.e. removed from the eviction candidates.
+bool IsProtected(int num_peers,
+ std::function<void(NodeEvictionCandidate&)> candidate_setup_fn,
+ const std::unordered_set<NodeId>& protected_peer_ids,
+ const std::unordered_set<NodeId>& unprotected_peer_ids,
+ FastRandomContext& random_context)
+{
+ std::vector<NodeEvictionCandidate> candidates{GetRandomNodeEvictionCandidates(num_peers, random_context)};
+ for (NodeEvictionCandidate& candidate : candidates) {
+ candidate_setup_fn(candidate);
+ }
+ Shuffle(candidates.begin(), candidates.end(), random_context);
+
+ const size_t size{candidates.size()};
+ const size_t expected{size - size / 2}; // Expect half the candidates will be protected.
+ ProtectEvictionCandidatesByRatio(candidates);
+ BOOST_CHECK_EQUAL(candidates.size(), expected);
+
+ size_t unprotected_count{0};
+ for (const NodeEvictionCandidate& candidate : candidates) {
+ if (protected_peer_ids.count(candidate.id)) {
+ // this peer should have been removed from the eviction candidates
+ BOOST_TEST_MESSAGE(strprintf("expected candidate to be protected: %d", candidate.id));
+ return false;
+ }
+ if (unprotected_peer_ids.count(candidate.id)) {
+ // this peer remains in the eviction candidates, as expected
+ ++unprotected_count;
+ }
+ }
+
+ const bool is_protected{unprotected_count == unprotected_peer_ids.size()};
+ if (!is_protected) {
+ BOOST_TEST_MESSAGE(strprintf("unprotected: expected %d, actual %d",
+ unprotected_peer_ids.size(), unprotected_count));
+ }
+ return is_protected;
+}
+
+BOOST_AUTO_TEST_CASE(peer_protection_test)
+{
+ FastRandomContext random_context{true};
+ int num_peers{12};
+
+ // Expect half of the peers with greatest uptime (the lowest nTimeConnected)
+ // to be protected from eviction.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_onion = c.m_is_local = false;
+ },
+ /* protected_peer_ids */ {0, 1, 2, 3, 4, 5},
+ /* unprotected_peer_ids */ {6, 7, 8, 9, 10, 11},
+ random_context));
+
+ // Verify in the opposite direction.
+ BOOST_CHECK(IsProtected(
+ num_peers, [num_peers](NodeEvictionCandidate& c) {
+ c.nTimeConnected = num_peers - c.id;
+ c.m_is_onion = c.m_is_local = false;
+ },
+ /* protected_peer_ids */ {6, 7, 8, 9, 10, 11},
+ /* unprotected_peer_ids */ {0, 1, 2, 3, 4, 5},
+ random_context));
+
+ // Test protection of onion and localhost peers...
+
+ // Expect 1/4 onion peers to be protected from eviction,
+ // independently of other characteristics.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.m_is_onion = (c.id == 3 || c.id == 8 || c.id == 9);
+ },
+ /* protected_peer_ids */ {3, 8, 9},
+ /* unprotected_peer_ids */ {},
+ random_context));
+
+ // Expect 1/4 onion peers and 1/4 of the others to be protected
+ // from eviction, sorted by longest uptime (lowest nTimeConnected).
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_local = false;
+ c.m_is_onion = (c.id == 3 || c.id > 7);
+ },
+ /* protected_peer_ids */ {0, 1, 2, 3, 8, 9},
+ /* unprotected_peer_ids */ {4, 5, 6, 7, 10, 11},
+ random_context));
+
+ // Expect 1/4 localhost peers to be protected from eviction,
+ // if no onion peers.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.m_is_onion = false;
+ c.m_is_local = (c.id == 1 || c.id == 9 || c.id == 11);
+ },
+ /* protected_peer_ids */ {1, 9, 11},
+ /* unprotected_peer_ids */ {},
+ random_context));
+
+ // Expect 1/4 localhost peers and 1/4 of the other peers to be protected,
+ // sorted by longest uptime (lowest nTimeConnected), if no onion peers.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_onion = false;
+ c.m_is_local = (c.id > 6);
+ },
+ /* protected_peer_ids */ {0, 1, 2, 7, 8, 9},
+ /* unprotected_peer_ids */ {3, 4, 5, 6, 10, 11},
+ random_context));
+
+ // Combined test: expect 1/4 onion and 2 localhost peers to be protected
+ // from eviction, sorted by longest uptime.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_onion = (c.id == 0 || c.id == 5 || c.id == 10);
+ c.m_is_local = (c.id == 1 || c.id == 9 || c.id == 11);
+ },
+ /* protected_peer_ids */ {0, 1, 2, 5, 9, 10},
+ /* unprotected_peer_ids */ {3, 4, 6, 7, 8, 11},
+ random_context));
+
+ // Combined test: expect having only 1 onion to allow allocating the
+ // remaining 2 of the 1/4 to localhost peers, sorted by longest uptime.
+ BOOST_CHECK(IsProtected(
+ num_peers + 4, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_onion = (c.id == 15);
+ c.m_is_local = (c.id > 6 && c.id < 11);
+ },
+ /* protected_peer_ids */ {0, 1, 2, 3, 7, 8, 9, 15},
+ /* unprotected_peer_ids */ {4, 5, 6, 10, 11, 12, 13, 14},
+ random_context));
+
+ // Combined test: expect 2 onions (< 1/4) to allow allocating the minimum 2
+ // localhost peers, sorted by longest uptime.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_onion = (c.id == 7 || c.id == 9);
+ c.m_is_local = (c.id == 6 || c.id == 11);
+ },
+ /* protected_peer_ids */ {0, 1, 6, 7, 9, 11},
+ /* unprotected_peer_ids */ {2, 3, 4, 5, 8, 10},
+ random_context));
+
+ // Combined test: when > 1/4, expect max 1/4 onion and 2 localhost peers
+ // to be protected from eviction, sorted by longest uptime.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_onion = (c.id > 3 && c.id < 8);
+ c.m_is_local = (c.id > 7);
+ },
+ /* protected_peer_ids */ {0, 4, 5, 6, 8, 9},
+ /* unprotected_peer_ids */ {1, 2, 3, 7, 10, 11},
+ random_context));
+
+ // Combined test: idem > 1/4 with only 8 peers: expect 2 onion and 2
+ // localhost peers (1/4 + 2) to be protected, sorted by longest uptime.
+ BOOST_CHECK(IsProtected(
+ 8, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_onion = (c.id > 1 && c.id < 5);
+ c.m_is_local = (c.id > 4);
+ },
+ /* protected_peer_ids */ {2, 3, 5, 6},
+ /* unprotected_peer_ids */ {0, 1, 4, 7},
+ random_context));
+
+ // Combined test: idem > 1/4 with only 6 peers: expect 1 onion peer and no
+ // localhost peers (1/4 + 0) to be protected, sorted by longest uptime.
+ BOOST_CHECK(IsProtected(
+ 6, [](NodeEvictionCandidate& c) {
+ c.nTimeConnected = c.id;
+ c.m_is_onion = (c.id == 4 || c.id == 5);
+ c.m_is_local = (c.id == 3);
+ },
+ /* protected_peer_ids */ {0, 1, 4},
+ /* unprotected_peer_ids */ {2, 3, 5},
+ random_context));
+}
+
+// Returns true if any of the node ids in node_ids are selected for eviction.
+bool IsEvicted(std::vector<NodeEvictionCandidate> candidates, const std::unordered_set<NodeId>& node_ids, FastRandomContext& random_context)
+{
+ Shuffle(candidates.begin(), candidates.end(), random_context);
+ const std::optional<NodeId> evicted_node_id = SelectNodeToEvict(std::move(candidates));
+ if (!evicted_node_id) {
+ return false;
+ }
+ return node_ids.count(*evicted_node_id);
+}
+
+// Create number_of_nodes random nodes, apply setup function candidate_setup_fn,
+// apply eviction logic and then return true if any of the node ids in node_ids
+// are selected for eviction.
+bool IsEvicted(const int number_of_nodes, std::function<void(NodeEvictionCandidate&)> candidate_setup_fn, const std::unordered_set<NodeId>& node_ids, FastRandomContext& random_context)
+{
+ std::vector<NodeEvictionCandidate> candidates = GetRandomNodeEvictionCandidates(number_of_nodes, random_context);
+ for (NodeEvictionCandidate& candidate : candidates) {
+ candidate_setup_fn(candidate);
+ }
+ return IsEvicted(candidates, node_ids, random_context);
+}
+
+BOOST_AUTO_TEST_CASE(peer_eviction_test)
+{
+ FastRandomContext random_context{true};
+
+ for (int i = 0; i < NODE_EVICTION_TEST_ROUNDS; ++i) {
+ for (int number_of_nodes = 0; number_of_nodes < NODE_EVICTION_TEST_UP_TO_N_NODES; ++number_of_nodes) {
+ // Four nodes with the highest keyed netgroup values should be
+ // protected from eviction.
+ BOOST_CHECK(!IsEvicted(
+ number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
+ candidate.nKeyedNetGroup = number_of_nodes - candidate.id;
+ },
+ {0, 1, 2, 3}, random_context));
+
+ // Eight nodes with the lowest minimum ping time should be protected
+ // from eviction.
+ BOOST_CHECK(!IsEvicted(
+ number_of_nodes, [](NodeEvictionCandidate& candidate) {
+ candidate.m_min_ping_time = std::chrono::microseconds{candidate.id};
+ },
+ {0, 1, 2, 3, 4, 5, 6, 7}, random_context));
+
+ // Four nodes that most recently sent us novel transactions accepted
+ // into our mempool should be protected from eviction.
+ BOOST_CHECK(!IsEvicted(
+ number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
+ candidate.nLastTXTime = number_of_nodes - candidate.id;
+ },
+ {0, 1, 2, 3}, random_context));
+
+ // Up to eight non-tx-relay peers that most recently sent us novel
+ // blocks should be protected from eviction.
+ BOOST_CHECK(!IsEvicted(
+ number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
+ candidate.nLastBlockTime = number_of_nodes - candidate.id;
+ if (candidate.id <= 7) {
+ candidate.fRelayTxes = false;
+ candidate.fRelevantServices = true;
+ }
+ },
+ {0, 1, 2, 3, 4, 5, 6, 7}, random_context));
+
+ // Four peers that most recently sent us novel blocks should be
+ // protected from eviction.
+ BOOST_CHECK(!IsEvicted(
+ number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
+ candidate.nLastBlockTime = number_of_nodes - candidate.id;
+ },
+ {0, 1, 2, 3}, random_context));
+
+ // Combination of the previous two tests.
+ BOOST_CHECK(!IsEvicted(
+ number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
+ candidate.nLastBlockTime = number_of_nodes - candidate.id;
+ if (candidate.id <= 7) {
+ candidate.fRelayTxes = false;
+ candidate.fRelevantServices = true;
+ }
+ },
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, random_context));
+
+ // Combination of all tests above.
+ BOOST_CHECK(!IsEvicted(
+ number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
+ candidate.nKeyedNetGroup = number_of_nodes - candidate.id; // 4 protected
+ candidate.m_min_ping_time = std::chrono::microseconds{candidate.id}; // 8 protected
+ candidate.nLastTXTime = number_of_nodes - candidate.id; // 4 protected
+ candidate.nLastBlockTime = number_of_nodes - candidate.id; // 4 protected
+ },
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, random_context));
+
+ // An eviction is expected given >= 29 random eviction candidates. The eviction logic protects at most
+ // four peers by net group, eight by lowest ping time, four by last time of novel tx, up to eight non-tx-relay
+ // peers by last novel block time, and four more peers by last novel block time.
+ if (number_of_nodes >= 29) {
+ BOOST_CHECK(SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context)));
+ }
+
+ // No eviction is expected given <= 20 random eviction candidates. The eviction logic protects at least
+ // four peers by net group, eight by lowest ping time, four by last time of novel tx and four peers by last
+ // novel block time.
+ if (number_of_nodes <= 20) {
+ BOOST_CHECK(!SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context)));
+ }
+
+ // Cases left to test:
+ // * "If any remaining peers are preferred for eviction consider only them. [...]"
+ // * "Identify the network group with the most connections and youngest member. [...]"
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 858b90b8b2..8eab26f3d5 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -857,147 +857,4 @@ BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle)
BOOST_CHECK_EQUAL(IsLocal(addr), false);
}
-std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(const int n_candidates, FastRandomContext& random_context)
-{
- std::vector<NodeEvictionCandidate> candidates;
- for (int id = 0; id < n_candidates; ++id) {
- candidates.push_back({
- /* id */ id,
- /* nTimeConnected */ static_cast<int64_t>(random_context.randrange(100)),
- /* m_min_ping_time */ std::chrono::microseconds{random_context.randrange(100)},
- /* nLastBlockTime */ static_cast<int64_t>(random_context.randrange(100)),
- /* nLastTXTime */ static_cast<int64_t>(random_context.randrange(100)),
- /* fRelevantServices */ random_context.randbool(),
- /* fRelayTxes */ random_context.randbool(),
- /* fBloomFilter */ random_context.randbool(),
- /* nKeyedNetGroup */ random_context.randrange(100),
- /* prefer_evict */ random_context.randbool(),
- /* m_is_local */ random_context.randbool(),
- });
- }
- return candidates;
-}
-
-// Returns true if any of the node ids in node_ids are selected for eviction.
-bool IsEvicted(std::vector<NodeEvictionCandidate> candidates, const std::vector<NodeId>& node_ids, FastRandomContext& random_context)
-{
- Shuffle(candidates.begin(), candidates.end(), random_context);
- const std::optional<NodeId> evicted_node_id = SelectNodeToEvict(std::move(candidates));
- if (!evicted_node_id) {
- return false;
- }
- return std::find(node_ids.begin(), node_ids.end(), *evicted_node_id) != node_ids.end();
-}
-
-// Create number_of_nodes random nodes, apply setup function candidate_setup_fn,
-// apply eviction logic and then return true if any of the node ids in node_ids
-// are selected for eviction.
-bool IsEvicted(const int number_of_nodes, std::function<void(NodeEvictionCandidate&)> candidate_setup_fn, const std::vector<NodeId>& node_ids, FastRandomContext& random_context)
-{
- std::vector<NodeEvictionCandidate> candidates = GetRandomNodeEvictionCandidates(number_of_nodes, random_context);
- for (NodeEvictionCandidate& candidate : candidates) {
- candidate_setup_fn(candidate);
- }
- return IsEvicted(candidates, node_ids, random_context);
-}
-
-namespace {
-constexpr int NODE_EVICTION_TEST_ROUNDS{10};
-constexpr int NODE_EVICTION_TEST_UP_TO_N_NODES{200};
-} // namespace
-
-BOOST_AUTO_TEST_CASE(node_eviction_test)
-{
- FastRandomContext random_context{true};
-
- for (int i = 0; i < NODE_EVICTION_TEST_ROUNDS; ++i) {
- for (int number_of_nodes = 0; number_of_nodes < NODE_EVICTION_TEST_UP_TO_N_NODES; ++number_of_nodes) {
- // Four nodes with the highest keyed netgroup values should be
- // protected from eviction.
- BOOST_CHECK(!IsEvicted(
- number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
- candidate.nKeyedNetGroup = number_of_nodes - candidate.id;
- },
- {0, 1, 2, 3}, random_context));
-
- // Eight nodes with the lowest minimum ping time should be protected
- // from eviction.
- BOOST_CHECK(!IsEvicted(
- number_of_nodes, [](NodeEvictionCandidate& candidate) {
- candidate.m_min_ping_time = std::chrono::microseconds{candidate.id};
- },
- {0, 1, 2, 3, 4, 5, 6, 7}, random_context));
-
- // Four nodes that most recently sent us novel transactions accepted
- // into our mempool should be protected from eviction.
- BOOST_CHECK(!IsEvicted(
- number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
- candidate.nLastTXTime = number_of_nodes - candidate.id;
- },
- {0, 1, 2, 3}, random_context));
-
- // Up to eight non-tx-relay peers that most recently sent us novel
- // blocks should be protected from eviction.
- BOOST_CHECK(!IsEvicted(
- number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
- candidate.nLastBlockTime = number_of_nodes - candidate.id;
- if (candidate.id <= 7) {
- candidate.fRelayTxes = false;
- candidate.fRelevantServices = true;
- }
- },
- {0, 1, 2, 3, 4, 5, 6, 7}, random_context));
-
- // Four peers that most recently sent us novel blocks should be
- // protected from eviction.
- BOOST_CHECK(!IsEvicted(
- number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
- candidate.nLastBlockTime = number_of_nodes - candidate.id;
- },
- {0, 1, 2, 3}, random_context));
-
- // Combination of the previous two tests.
- BOOST_CHECK(!IsEvicted(
- number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
- candidate.nLastBlockTime = number_of_nodes - candidate.id;
- if (candidate.id <= 7) {
- candidate.fRelayTxes = false;
- candidate.fRelevantServices = true;
- }
- },
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, random_context));
-
- // Combination of all tests above.
- BOOST_CHECK(!IsEvicted(
- number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
- candidate.nKeyedNetGroup = number_of_nodes - candidate.id; // 4 protected
- candidate.m_min_ping_time = std::chrono::microseconds{candidate.id}; // 8 protected
- candidate.nLastTXTime = number_of_nodes - candidate.id; // 4 protected
- candidate.nLastBlockTime = number_of_nodes - candidate.id; // 4 protected
- },
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, random_context));
-
- // An eviction is expected given >= 29 random eviction candidates. The eviction logic protects at most
- // four peers by net group, eight by lowest ping time, four by last time of novel tx, up to eight non-tx-relay
- // peers by last novel block time, and four more peers by last novel block time.
- if (number_of_nodes >= 29) {
- BOOST_CHECK(SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context)));
- }
-
- // No eviction is expected given <= 20 random eviction candidates. The eviction logic protects at least
- // four peers by net group, eight by lowest ping time, four by last time of novel tx and four peers by last
- // novel block time.
- if (number_of_nodes <= 20) {
- BOOST_CHECK(!SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context)));
- }
-
- // Cases left to test:
- // * "Protect the half of the remaining nodes which have been connected the longest. [...]"
- // * "Pick out up to 1/4 peers that are localhost, sorted by longest uptime. [...]"
- // * "If any remaining peers are preferred for eviction consider only them. [...]"
- // * "Identify the network group with the most connections and youngest member. [...]"
- }
- }
-}
-
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/ref_tests.cpp b/src/test/ref_tests.cpp
deleted file mode 100644
index 0ec0799fbc..0000000000
--- a/src/test/ref_tests.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2020 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <util/ref.h>
-
-#include <boost/test/unit_test.hpp>
-
-BOOST_AUTO_TEST_SUITE(ref_tests)
-
-BOOST_AUTO_TEST_CASE(ref_test)
-{
- util::Ref ref;
- BOOST_CHECK(!ref.Has<int>());
- BOOST_CHECK_THROW(ref.Get<int>(), NonFatalCheckError);
- int value = 5;
- ref.Set(value);
- BOOST_CHECK(ref.Has<int>());
- BOOST_CHECK_EQUAL(ref.Get<int>(), 5);
- ++ref.Get<int>();
- BOOST_CHECK_EQUAL(ref.Get<int>(), 6);
- BOOST_CHECK_EQUAL(value, 6);
- ++value;
- BOOST_CHECK_EQUAL(value, 7);
- BOOST_CHECK_EQUAL(ref.Get<int>(), 7);
- BOOST_CHECK(!ref.Has<bool>());
- BOOST_CHECK_THROW(ref.Get<bool>(), NonFatalCheckError);
- ref.Clear();
- BOOST_CHECK(!ref.Has<int>());
- BOOST_CHECK_THROW(ref.Get<int>(), NonFatalCheckError);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 2e0fc7e48f..67e70b3bc3 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -10,9 +10,10 @@
#include <interfaces/chain.h>
#include <node/context.h>
#include <test/util/setup_common.h>
-#include <util/ref.h>
#include <util/time.h>
+#include <any>
+
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
@@ -32,7 +33,7 @@ UniValue RPCTestingSetup::CallRPC(std::string args)
boost::split(vArgs, args, boost::is_any_of(" \t"));
std::string strMethod = vArgs[0];
vArgs.erase(vArgs.begin());
- util::Ref context{m_node};
+ std::any context{&m_node};
JSONRPCRequest request(context);
request.strMethod = strMethod;
request.params = RPCConvertValues(strMethod, vArgs);
diff --git a/src/test/util/net.h b/src/test/util/net.h
index e25036be26..2b7988413f 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -5,7 +5,13 @@
#ifndef BITCOIN_TEST_UTIL_NET_H
#define BITCOIN_TEST_UTIL_NET_H
+#include <compat.h>
#include <net.h>
+#include <util/sock.h>
+
+#include <cassert>
+#include <cstring>
+#include <string>
struct ConnmanTestMsg : public CConnman {
using CConnman::CConnman;
@@ -61,4 +67,67 @@ constexpr ConnectionType ALL_CONNECTION_TYPES[]{
ConnectionType::ADDR_FETCH,
};
+/**
+ * A mocked Sock alternative that returns a statically contained data upon read and succeeds
+ * and ignores all writes. The data to be returned is given to the constructor and when it is
+ * exhausted an EOF is returned by further reads.
+ */
+class StaticContentsSock : public Sock
+{
+public:
+ explicit StaticContentsSock(const std::string& contents) : m_contents{contents}, m_consumed{0}
+ {
+ // Just a dummy number that is not INVALID_SOCKET.
+ static_assert(INVALID_SOCKET != 1000);
+ m_socket = 1000;
+ }
+
+ ~StaticContentsSock() override { Reset(); }
+
+ StaticContentsSock& operator=(Sock&& other) override
+ {
+ assert(false && "Move of Sock into MockSock not allowed.");
+ return *this;
+ }
+
+ void Reset() override
+ {
+ m_socket = INVALID_SOCKET;
+ }
+
+ ssize_t Send(const void*, size_t len, int) const override { return len; }
+
+ ssize_t Recv(void* buf, size_t len, int flags) const override
+ {
+ const size_t consume_bytes{std::min(len, m_contents.size() - m_consumed)};
+ std::memcpy(buf, m_contents.data() + m_consumed, consume_bytes);
+ if ((flags & MSG_PEEK) == 0) {
+ m_consumed += consume_bytes;
+ }
+ return consume_bytes;
+ }
+
+ int Connect(const sockaddr*, socklen_t) const override { return 0; }
+
+ int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override
+ {
+ std::memset(opt_val, 0x0, *opt_len);
+ return 0;
+ }
+
+ bool Wait(std::chrono::milliseconds timeout,
+ Event requested,
+ Event* occurred = nullptr) const override
+ {
+ if (occurred != nullptr) {
+ *occurred = requested;
+ }
+ return true;
+ }
+
+private:
+ const std::string m_contents;
+ mutable size_t m_consumed;
+};
+
#endif // BITCOIN_TEST_UTIL_NET_H
diff --git a/src/test/util/script.cpp b/src/test/util/script.cpp
new file mode 100644
index 0000000000..a5852daa60
--- /dev/null
+++ b/src/test/util/script.cpp
@@ -0,0 +1,13 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <script/interpreter.h>
+#include <test/util/script.h>
+
+bool IsValidFlagCombination(unsigned flags)
+{
+ if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
+ if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
+ return true;
+}
diff --git a/src/test/util/script.h b/src/test/util/script.h
index abd14c2067..428b3e10b3 100644
--- a/src/test/util/script.h
+++ b/src/test/util/script.h
@@ -18,4 +18,7 @@ static const CScript P2WSH_OP_TRUE{
return hash;
}())};
+/** Flags that are not forbidden by an assert in script validation */
+bool IsValidFlagCombination(unsigned flags);
+
#endif // BITCOIN_TEST_UTIL_SCRIPT_H
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index f866c2a1f9..bfb3466dcf 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -4,6 +4,7 @@
#include <test/util/setup_common.h>
+#include <addrman.h>
#include <banman.h>
#include <chainparams.h>
#include <consensus/consensus.h>
@@ -155,6 +156,7 @@ ChainTestingSetup::~ChainTestingSetup()
GetMainSignals().UnregisterBackgroundSignalScheduler();
m_node.connman.reset();
m_node.banman.reset();
+ m_node.addrman.reset();
m_node.args = nullptr;
UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman);
m_node.mempool.reset();
@@ -187,11 +189,12 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
}
+ m_node.addrman = std::make_unique<CAddrMan>();
m_node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
- m_node.peerman = PeerManager::make(chainparams, *m_node.connman, m_node.banman.get(),
- *m_node.scheduler, *m_node.chainman, *m_node.mempool,
- false);
+ m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
+ m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,
+ m_node.banman.get(), *m_node.scheduler, *m_node.chainman,
+ *m_node.mempool, false);
{
CConnman::Options options;
options.m_msgproc = m_node.peerman.get();
diff --git a/src/util/ref.h b/src/util/ref.h
deleted file mode 100644
index 9685ea9fec..0000000000
--- a/src/util/ref.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2020 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_UTIL_REF_H
-#define BITCOIN_UTIL_REF_H
-
-#include <util/check.h>
-
-#include <typeindex>
-
-namespace util {
-
-/**
- * Type-safe dynamic reference.
- *
- * This implements a small subset of the functionality in C++17's std::any
- * class, and can be dropped when the project updates to C++17
- * (https://github.com/bitcoin/bitcoin/issues/16684)
- */
-class Ref
-{
-public:
- Ref() = default;
- template<typename T> Ref(T& value) { Set(value); }
- template<typename T> T& Get() const { CHECK_NONFATAL(Has<T>()); return *static_cast<T*>(m_value); }
- template<typename T> void Set(T& value) { m_value = &value; m_type = std::type_index(typeid(T)); }
- template<typename T> bool Has() const { return m_value && m_type == std::type_index(typeid(T)); }
- void Clear() { m_value = nullptr; m_type = std::type_index(typeid(void)); }
-
-private:
- void* m_value = nullptr;
- std::type_index m_type = std::type_index(typeid(void));
-};
-
-} // namespace util
-
-#endif // BITCOIN_UTIL_REF_H
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index f9ecfef5d4..0bc9795db3 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -66,6 +66,16 @@ ssize_t Sock::Recv(void* buf, size_t len, int flags) const
return recv(m_socket, static_cast<char*>(buf), len, flags);
}
+int Sock::Connect(const sockaddr* addr, socklen_t addr_len) const
+{
+ return connect(m_socket, addr, addr_len);
+}
+
+int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
+{
+ return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len);
+}
+
bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
{
#ifdef USE_POLL
diff --git a/src/util/sock.h b/src/util/sock.h
index 4b0618dcff..c4ad0cbc43 100644
--- a/src/util/sock.h
+++ b/src/util/sock.h
@@ -80,16 +80,29 @@ public:
/**
* send(2) wrapper. Equivalent to `send(this->Get(), data, len, flags);`. Code that uses this
- * wrapper can be unit-tested if this method is overridden by a mock Sock implementation.
+ * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
*/
virtual ssize_t Send(const void* data, size_t len, int flags) const;
/**
* recv(2) wrapper. Equivalent to `recv(this->Get(), buf, len, flags);`. Code that uses this
- * wrapper can be unit-tested if this method is overridden by a mock Sock implementation.
+ * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
*/
virtual ssize_t Recv(void* buf, size_t len, int flags) const;
+ /**
+ * connect(2) wrapper. Equivalent to `connect(this->Get(), addr, addrlen)`. Code that uses this
+ * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
+ */
+ virtual int Connect(const sockaddr* addr, socklen_t addr_len) const;
+
+ /**
+ * getsockopt(2) wrapper. Equivalent to
+ * `getsockopt(this->Get(), level, opt_name, opt_val, opt_len)`. Code that uses this
+ * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
+ */
+ virtual int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const;
+
using Event = uint8_t;
/**
@@ -153,7 +166,7 @@ public:
*/
virtual bool IsConnected(std::string& errmsg) const;
-private:
+protected:
/**
* Contained socket. `INVALID_SOCKET` designates the object is empty.
*/
diff --git a/src/util/system.h b/src/util/system.h
index 291f3f5541..29657e56e2 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -25,6 +25,7 @@
#include <util/threadnames.h>
#include <util/time.h>
+#include <any>
#include <exception>
#include <map>
#include <optional>
@@ -500,6 +501,18 @@ inline void insert(std::set<TsetT>& dst, const Tsrc& src) {
dst.insert(src.begin(), src.end());
}
+/**
+ * Helper function to access the contained object of a std::any instance.
+ * Returns a pointer to the object if passed instance has a value and the type
+ * matches, nullptr otherwise.
+ */
+template<typename T>
+T* AnyPtr(const std::any& any) noexcept
+{
+ T* const* ptr = std::any_cast<T*>(&any);
+ return ptr ? *ptr : nullptr;
+}
+
#ifdef WIN32
class WinCmdLineArgs
{
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index ada586119a..da5b84ce83 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -15,7 +15,6 @@
#include <sync.h>
#include <uint256.h>
#include <util/check.h>
-#include <util/ref.h>
#include <util/system.h>
#include <util/ui_change_type.h>
#include <wallet/context.h>
@@ -515,7 +514,7 @@ public:
{
for (const CRPCCommand& command : GetWalletRPCCommands()) {
m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
- return command.actor({request, m_context}, result, last_handler);
+ return command.actor({request, &m_context}, result, last_handler);
}, command.argNames, command.unique_id);
m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back()));
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 6dc8d1de42..ce8ce4342a 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -22,7 +22,6 @@
#include <util/fees.h>
#include <util/message.h> // For MessageSign()
#include <util/moneystr.h>
-#include <util/ref.h>
#include <util/string.h>
#include <util/system.h>
#include <util/translation.h>
@@ -124,12 +123,13 @@ void EnsureWalletIsUnlocked(const CWallet& wallet)
}
}
-WalletContext& EnsureWalletContext(const util::Ref& context)
+WalletContext& EnsureWalletContext(const std::any& context)
{
- if (!context.Has<WalletContext>()) {
+ auto wallet_context = util::AnyPtr<WalletContext>(context);
+ if (!wallet_context) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
}
- return context.Get<WalletContext>();
+ return *wallet_context;
}
// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
@@ -1741,7 +1741,7 @@ static RPCHelpMan gettransaction()
if (verbose) {
UniValue decoded(UniValue::VOBJ);
- TxToUniv(*wtx.tx, uint256(), decoded, false);
+ TxToUniv(*wtx.tx, uint256(), pwallet->chain().rpcEnableDeprecated("addresses"), decoded, false);
entry.pushKV("decoded", decoded);
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index b82fe1ec76..8b88ffe8ed 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -7,6 +7,7 @@
#include <span.h>
+#include <any>
#include <memory>
#include <string>
#include <vector>
@@ -31,7 +32,7 @@ Span<const CRPCCommand> GetWalletRPCCommands();
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
void EnsureWalletIsUnlocked(const CWallet&);
-WalletContext& EnsureWalletContext(const util::Ref& context);
+WalletContext& EnsureWalletContext(const std::any& context);
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);
RPCHelpMan getaddressinfo();
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 30cc452065..ba2e17d62a 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -4,6 +4,7 @@
#include <wallet/wallet.h>
+#include <any>
#include <future>
#include <memory>
#include <stdint.h>
@@ -15,7 +16,6 @@
#include <rpc/server.h>
#include <test/util/logging.h>
#include <test/util/setup_common.h>
-#include <util/ref.h>
#include <util/translation.h>
#include <validation.h>
#include <wallet/coincontrol.h>
@@ -213,7 +213,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1);
key.pushKV("internal", UniValue(true));
keys.push_back(key);
- util::Ref context;
+ std::any context;
JSONRPCRequest request(context);
request.params.setArray();
request.params.push_back(keys);
@@ -265,7 +265,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
AddWallet(wallet);
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
}
- util::Ref context;
+ std::any context;
JSONRPCRequest request(context);
request.params.setArray();
request.params.push_back(backup_file);
@@ -281,7 +281,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
LOCK(wallet->cs_wallet);
wallet->SetupLegacyScriptPubKeyMan();
- util::Ref context;
+ std::any context;
JSONRPCRequest request(context);
request.params.setArray();
request.params.push_back(backup_file);
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index c6f55c62b4..945880cc3b 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -33,12 +33,7 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT):
txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN))
tx1 = node.getrawtransaction(txid, 1)
txid = int(txid, 16)
- i = None
-
- for i, txout in enumerate(tx1['vout']):
- if txout['scriptPubKey']['addresses'] == [new_addr]:
- break
- assert i is not None
+ i, _ = next(filter(lambda vout: new_addr == vout[1]['scriptPubKey']['address'], enumerate(tx1['vout'])))
tx2 = CTransaction()
tx2.vin = [CTxIn(COutPoint(txid, i))]
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 7bd2fc7847..ad8767556b 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -523,7 +523,7 @@ class SegWitTest(BitcoinTestFramework):
v1_addr = program_to_witness(1, [3, 5])
v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])], {v1_addr: 1})
v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)
- assert_equal(v1_decoded['vout'][0]['scriptPubKey']['addresses'][0], v1_addr)
+ assert_equal(v1_decoded['vout'][0]['scriptPubKey']['address'], v1_addr)
assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], "51020305")
# Check that spendable outputs are really spendable
diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py
index a9e2b000fb..884a2fef11 100755
--- a/test/functional/mempool_package_onemore.py
+++ b/test/functional/mempool_package_onemore.py
@@ -80,7 +80,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
self.chain_transaction(self.nodes[0], [second_chain], [0], second_chain_value, fee, 1)
# Make sure we can RBF the chain which used our carve-out rule
- second_tx_outputs = {self.nodes[0].getrawtransaction(replacable_txid, True)["vout"][0]['scriptPubKey']['addresses'][0]: replacable_orig_value - (Decimal(1) / Decimal(100))}
+ second_tx_outputs = {self.nodes[0].getrawtransaction(replacable_txid, True)["vout"][0]['scriptPubKey']['address']: replacable_orig_value - (Decimal(1) / Decimal(100))}
second_tx = self.nodes[0].createrawtransaction([{'txid': chain[0][0], 'vout': 1}], second_tx_outputs)
signed_second_tx = self.nodes[0].signrawtransactionwithwallet(second_tx)
self.nodes[0].sendrawtransaction(signed_second_tx['hex'])
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index a2a122b352..52dc4de3bd 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -61,6 +61,7 @@ class FeeFilterTest(BitcoinTestFramework):
def run_test(self):
self.test_feefilter_forcerelay()
self.test_feefilter()
+ self.test_feefilter_blocksonly()
def test_feefilter_forcerelay(self):
self.log.info('Check that peers without forcerelay permission (default) get a feefilter message')
@@ -119,6 +120,19 @@ class FeeFilterTest(BitcoinTestFramework):
conn.wait_for_invs_to_match(txids)
conn.clear_invs()
+ def test_feefilter_blocksonly(self):
+ """Test that we don't send fee filters to block-relay-only peers and when we're in blocksonly mode."""
+ self.log.info("Check that we don't send fee filters to block-relay-only peers.")
+ feefilter_peer = self.nodes[0].add_outbound_p2p_connection(FeefilterConn(), p2p_idx=0, connection_type="block-relay-only")
+ feefilter_peer.sync_with_ping()
+ feefilter_peer.assert_feefilter_received(False)
+
+ self.log.info("Check that we don't send fee filters when in blocksonly mode.")
+ self.restart_node(0, ["-blocksonly"])
+ feefilter_peer = self.nodes[0].add_p2p_connection(FeefilterConn())
+ feefilter_peer.sync_with_ping()
+ feefilter_peer.assert_feefilter_received(False)
+
if __name__ == '__main__':
FeeFilterTest().main()
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index 8f64419138..4bee33f825 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -130,7 +130,7 @@ class FilterTest(BitcoinTestFramework):
filter_peer = P2PBloomFilter()
self.log.debug("Create a tx relevant to the peer before connecting")
- filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['addresses'][0]
+ filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address']
txid = self.nodes[0].sendtoaddress(filter_address, 90)
self.log.debug("Send a mempool msg after connecting and check that the tx is received")
@@ -142,7 +142,7 @@ class FilterTest(BitcoinTestFramework):
def test_frelay_false(self, filter_peer):
self.log.info("Check that a node with fRelay set to false does not receive invs until the filter is set")
filter_peer.tx_received = False
- filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['addresses'][0]
+ filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address']
self.nodes[0].sendtoaddress(filter_address, 90)
# Sync to make sure the reason filter_peer doesn't receive the tx is not p2p delays
filter_peer.sync_with_ping()
@@ -156,7 +156,7 @@ class FilterTest(BitcoinTestFramework):
filter_peer.send_and_ping(filter_peer.watch_filter_init)
# If fRelay is not already True, sending filterload sets it to True
assert self.nodes[0].getpeerinfo()[0]['relaytxes']
- filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['addresses'][0]
+ filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address']
self.log.info('Check that we receive merkleblock and tx if the filter matches a tx in a block')
block_hash = self.nodes[0].generatetoaddress(1, filter_address)[0]
diff --git a/test/functional/rpc_addresses_deprecation.py b/test/functional/rpc_addresses_deprecation.py
new file mode 100644
index 0000000000..bc0559f3b5
--- /dev/null
+++ b/test/functional/rpc_addresses_deprecation.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test deprecation of reqSigs and addresses RPC fields."""
+
+from io import BytesIO
+
+from test_framework.messages import CTransaction
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ hex_str_to_bytes
+)
+
+
+class AddressesDeprecationTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+ self.extra_args = [[], ["-deprecatedrpc=addresses"]]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ self.test_addresses_deprecation()
+
+ def test_addresses_deprecation(self):
+ node = self.nodes[0]
+ coin = node.listunspent().pop()
+
+ inputs = [{'txid': coin['txid'], 'vout': coin['vout']}]
+ outputs = {node.getnewaddress(): 0.99}
+ raw = node.createrawtransaction(inputs, outputs)
+ signed = node.signrawtransactionwithwallet(raw)['hex']
+
+ # This transaction is derived from test/util/data/txcreatemultisig1.json
+ tx = CTransaction()
+ tx.deserialize(BytesIO(hex_str_to_bytes(signed)))
+ tx.vout[0].scriptPubKey = hex_str_to_bytes("522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae")
+ tx_signed = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
+ txid = node.sendrawtransaction(hexstring=tx_signed, maxfeerate=0)
+
+ self.log.info("Test RPCResult scriptPubKey no longer returns the fields addresses or reqSigs by default")
+ hash = node.generateblock(output=node.getnewaddress(), transactions=[txid])['hash']
+ # Ensure both nodes have the newly generated block on disk.
+ self.sync_blocks()
+ script_pub_key = node.getblock(blockhash=hash, verbose=2)['tx'][-1]['vout'][0]['scriptPubKey']
+ assert 'addresses' not in script_pub_key and 'reqSigs' not in script_pub_key
+
+ self.log.info("Test RPCResult scriptPubKey returns the addresses field with -deprecatedrpc=addresses")
+ script_pub_key = self.nodes[1].getblock(blockhash=hash, verbose=2)['tx'][-1]['vout'][0]['scriptPubKey']
+ assert_equal(script_pub_key['addresses'], ['mvKDK6D54HU8wQumJBLHY95eq5iHFqXSBz', 'mv3rHCQSwKp2BLSuMHD8uCS32LW5xiNAA5', 'mirrsyhAQYzo5CwVhcaYJKwUJu1WJRCRJe'])
+ assert_equal(script_pub_key['reqSigs'], 2)
+
+
+if __name__ == "__main__":
+ AddressesDeprecationTest().main()
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 31baeba582..19f0d5765a 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -165,7 +165,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
txid = node0.sendtoaddress(madd, 40)
tx = node0.getrawtransaction(txid, True)
- vout = [v["n"] for v in tx["vout"] if madd in v["scriptPubKey"].get("addresses", [])]
+ vout = [v["n"] for v in tx["vout"] if madd == v["scriptPubKey"]["address"]]
assert len(vout) == 1
vout = vout[0]
scriptPubKey = tx["vout"][vout]["scriptPubKey"]["hex"]
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 8c9755cc8c..5129ecb895 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -248,7 +248,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0})
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
out = dec_tx['vout'][0]
- assert_equal(change, out['scriptPubKey']['addresses'][0])
+ assert_equal(change, out['scriptPubKey']['address'])
def test_change_type(self):
self.log.info("Test fundrawtxn with a provided change type")
@@ -288,7 +288,7 @@ class RawTransactionsTest(BitcoinTestFramework):
matchingOuts = 0
for i, out in enumerate(dec_tx['vout']):
totalOut += out['value']
- if out['scriptPubKey']['addresses'][0] in outputs:
+ if out['scriptPubKey']['address'] in outputs:
matchingOuts+=1
else:
assert_equal(i, rawtxfund['changepos'])
@@ -319,7 +319,7 @@ class RawTransactionsTest(BitcoinTestFramework):
matchingOuts = 0
for out in dec_tx['vout']:
totalOut += out['value']
- if out['scriptPubKey']['addresses'][0] in outputs:
+ if out['scriptPubKey']['address'] in outputs:
matchingOuts+=1
assert_equal(matchingOuts, 1)
@@ -353,7 +353,7 @@ class RawTransactionsTest(BitcoinTestFramework):
matchingOuts = 0
for out in dec_tx['vout']:
totalOut += out['value']
- if out['scriptPubKey']['addresses'][0] in outputs:
+ if out['scriptPubKey']['address'] in outputs:
matchingOuts+=1
assert_equal(matchingOuts, 2)
@@ -802,7 +802,7 @@ class RawTransactionsTest(BitcoinTestFramework):
changeaddress = ""
for out in res_dec['vout']:
if out['value'] > 1.0:
- changeaddress += out['scriptPubKey']['addresses'][0]
+ changeaddress += out['scriptPubKey']['address']
assert changeaddress != ""
nextaddr = self.nodes[3].getnewaddress()
# Now the change address key should be removed from the keypool.
diff --git a/test/functional/rpc_generateblock.py b/test/functional/rpc_generateblock.py
index 08ff0fba50..7424416484 100755
--- a/test/functional/rpc_generateblock.py
+++ b/test/functional/rpc_generateblock.py
@@ -27,13 +27,13 @@ class GenerateBlockTest(BitcoinTestFramework):
hash = node.generateblock(output=address, transactions=[])['hash']
block = node.getblock(blockhash=hash, verbose=2)
assert_equal(len(block['tx']), 1)
- assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['addresses'][0], address)
+ assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], address)
self.log.info('Generate an empty block to a descriptor')
hash = node.generateblock('addr(' + address + ')', [])['hash']
block = node.getblock(blockhash=hash, verbosity=2)
assert_equal(len(block['tx']), 1)
- assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['addresses'][0], address)
+ assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], address)
self.log.info('Generate an empty block to a combo descriptor with compressed pubkey')
combo_key = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'
@@ -41,7 +41,7 @@ class GenerateBlockTest(BitcoinTestFramework):
hash = node.generateblock('combo(' + combo_key + ')', [])['hash']
block = node.getblock(hash, 2)
assert_equal(len(block['tx']), 1)
- assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['addresses'][0], combo_address)
+ assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], combo_address)
self.log.info('Generate an empty block to a combo descriptor with uncompressed pubkey')
combo_key = '0408ef68c46d20596cc3f6ddf7c8794f71913add807f1dc55949fa805d764d191c0b7ce6894c126fce0babc6663042f3dde9b0cf76467ea315514e5a6731149c67'
@@ -49,7 +49,7 @@ class GenerateBlockTest(BitcoinTestFramework):
hash = node.generateblock('combo(' + combo_key + ')', [])['hash']
block = node.getblock(hash, 2)
assert_equal(len(block['tx']), 1)
- assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['addresses'][0], combo_address)
+ assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], combo_address)
# Generate 110 blocks to spend
node.generatetoaddress(110, address)
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index ed6abaed78..079a3bd3ba 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -158,17 +158,17 @@ class PSBTTest(BitcoinTestFramework):
p2sh_p2wpkh_pos = -1
decoded = self.nodes[0].decoderawtransaction(signed_tx)
for out in decoded['vout']:
- if out['scriptPubKey']['addresses'][0] == p2sh:
+ if out['scriptPubKey']['address'] == p2sh:
p2sh_pos = out['n']
- elif out['scriptPubKey']['addresses'][0] == p2wsh:
+ elif out['scriptPubKey']['address'] == p2wsh:
p2wsh_pos = out['n']
- elif out['scriptPubKey']['addresses'][0] == p2wpkh:
+ elif out['scriptPubKey']['address'] == p2wpkh:
p2wpkh_pos = out['n']
- elif out['scriptPubKey']['addresses'][0] == p2sh_p2wsh:
+ elif out['scriptPubKey']['address'] == p2sh_p2wsh:
p2sh_p2wsh_pos = out['n']
- elif out['scriptPubKey']['addresses'][0] == p2sh_p2wpkh:
+ elif out['scriptPubKey']['address'] == p2sh_p2wpkh:
p2sh_p2wpkh_pos = out['n']
- elif out['scriptPubKey']['addresses'][0] == p2pkh:
+ elif out['scriptPubKey']['address'] == p2pkh:
p2pkh_pos = out['n']
inputs = [{"txid": txid, "vout": p2wpkh_pos}, {"txid": txid, "vout": p2sh_p2wpkh_pos}, {"txid": txid, "vout": p2pkh_pos}]
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index d335d4ea79..5c774934be 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -543,7 +543,7 @@ def find_vout_for_address(node, txid, addr):
"""
tx = node.getrawtransaction(txid, True)
for i in range(len(tx["vout"])):
- if any([addr == a for a in tx["vout"][i]["scriptPubKey"]["addresses"]]):
+ if addr == tx["vout"][i]["scriptPubKey"]["address"]:
return i
raise RuntimeError("Vout not found for address: txid=%s, addr=%s" % (txid, addr))
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 28d3518715..001d161612 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -287,6 +287,7 @@ BASE_SCRIPTS = [
'feature_config_args.py',
'feature_settings.py',
'rpc_getdescriptorinfo.py',
+ 'rpc_addresses_deprecation.py',
'rpc_help.py',
'feature_help.py',
'feature_shutdown.py',
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index 2db5eae33b..b3bee1876d 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -210,7 +210,7 @@ class AddressTypeTest(BitcoinTestFramework):
assert_equal(len(tx["vout"]), len(destinations) + 1)
# Make sure the destinations are included, and remove them:
- output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]]
+ output_addresses = [vout['scriptPubKey']['address'] for vout in tx["vout"]]
change_addresses = [d for d in output_addresses if d not in destinations]
assert_equal(len(change_addresses), 1)
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
index bc4fa90e83..1d3736d9b1 100755
--- a/test/functional/wallet_avoidreuse.py
+++ b/test/functional/wallet_avoidreuse.py
@@ -253,7 +253,7 @@ class AvoidReuseTest(BitcoinTestFramework):
if second_addr_type == "p2sh-segwit":
new_fundaddr = fund_decoded["segwit"]["p2sh-segwit"]
elif second_addr_type == "bech32":
- new_fundaddr = fund_decoded["segwit"]["addresses"][0]
+ new_fundaddr = fund_decoded["segwit"]["address"]
else:
new_fundaddr = fundaddr
assert_equal(second_addr_type, "legacy")
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 4a589f0393..dc6f8ed9c4 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -600,7 +600,7 @@ class WalletTest(BitcoinTestFramework):
destination = self.nodes[1].getnewaddress()
txid = self.nodes[0].sendtoaddress(destination, 0.123)
tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
- output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]]
+ output_addresses = [vout['scriptPubKey']['address'] for vout in tx["vout"]]
assert len(output_addresses) > 1
for address in output_addresses:
ischange = self.nodes[0].getaddressinfo(address)['ischange']
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 5fc8438e8f..0d1b6c54ce 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -535,7 +535,7 @@ def test_change_script_match(self, rbf_node, dest_address):
def get_change_address(tx):
tx_details = rbf_node.getrawtransaction(tx, 1)
- txout_addresses = [txout['scriptPubKey']['addresses'][0] for txout in tx_details["vout"]]
+ txout_addresses = [txout['scriptPubKey']['address'] for txout in tx_details["vout"]]
return [address for address in txout_addresses if rbf_node.getaddressinfo(address)["ischange"]]
# Check that there is only one change output
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index d45cf05689..23d132df41 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -132,7 +132,7 @@ class WalletHDTest(BitcoinTestFramework):
keypath = ""
for out in outs:
if out['value'] != 1:
- keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['addresses'][0])['hdkeypath']
+ keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['address'])['hdkeypath']
if self.options.descriptors:
assert_equal(keypath[0:14], "m/84'/1'/0'/1/")
diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py
index 880341fdd9..53553dcd80 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -389,10 +389,10 @@ class WalletSendTest(BitcoinTestFramework):
assert res["complete"]
res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, add_to_wallet=False, change_address=change_address, change_position=0)
assert res["complete"]
- assert_equal(self.nodes[0].decodepsbt(res["psbt"])["tx"]["vout"][0]["scriptPubKey"]["addresses"], [change_address])
+ assert_equal(self.nodes[0].decodepsbt(res["psbt"])["tx"]["vout"][0]["scriptPubKey"]["address"], change_address)
res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, add_to_wallet=False, change_type="legacy", change_position=0)
assert res["complete"]
- change_address = self.nodes[0].decodepsbt(res["psbt"])["tx"]["vout"][0]["scriptPubKey"]["addresses"][0]
+ change_address = self.nodes[0].decodepsbt(res["psbt"])["tx"]["vout"][0]["scriptPubKey"]["address"]
assert change_address[0] == "m" or change_address[0] == "n"
self.log.info("Set lock time...")
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index 6fc1d13c53..84ff9ad772 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -65,8 +65,8 @@ class TxnMallTest(BitcoinTestFramework):
# Construct a clone of tx1, to be malleated
rawtx1 = self.nodes[0].getrawtransaction(txid1, 1)
clone_inputs = [{"txid": rawtx1["vin"][0]["txid"], "vout": rawtx1["vin"][0]["vout"], "sequence": rawtx1["vin"][0]["sequence"]}]
- clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][0]["value"],
- rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][1]["value"]}
+ clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["address"]: rawtx1["vout"][0]["value"],
+ rawtx1["vout"][1]["scriptPubKey"]["address"]: rawtx1["vout"][1]["value"]}
clone_locktime = rawtx1["locktime"]
clone_raw = self.nodes[0].createrawtransaction(clone_inputs, clone_outputs, clone_locktime)
diff --git a/test/lint/extended-lint-cppcheck.sh b/test/lint/extended-lint-cppcheck.sh
index b2ed811cda..0ab6aad50c 100755
--- a/test/lint/extended-lint-cppcheck.sh
+++ b/test/lint/extended-lint-cppcheck.sh
@@ -57,7 +57,6 @@ IGNORED_WARNINGS=(
"src/test/checkqueue_tests.cpp:.* Struct 'UniqueCheck' has a constructor with 1 argument that is not explicit."
"src/test/fuzz/util.h:.* Class 'FuzzedFileProvider' has a constructor with 1 argument that is not explicit."
"src/test/fuzz/util.h:.* Class 'FuzzedAutoFileProvider' has a constructor with 1 argument that is not explicit."
- "src/util/ref.h:.* Class 'Ref' has a constructor with 1 argument that is not explicit."
"src/wallet/db.h:.* Class 'BerkeleyEnvironment' has a constructor with 1 argument that is not explicit."
)
diff --git a/test/util/data/tt-delin1-out.json b/test/util/data/tt-delin1-out.json
index 9fc2ddc376..c5b9f6df01 100644
--- a/test/util/data/tt-delin1-out.json
+++ b/test/util/data/tt-delin1-out.json
@@ -195,11 +195,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o"
- ]
+ "address": "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o",
+ "type": "pubkeyhash"
}
},
{
@@ -208,11 +205,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb"
- ]
+ "address": "1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb",
+ "type": "pubkeyhash"
}
}
],
diff --git a/test/util/data/tt-delout1-out.json b/test/util/data/tt-delout1-out.json
index 922d048900..3863416430 100644
--- a/test/util/data/tt-delout1-out.json
+++ b/test/util/data/tt-delout1-out.json
@@ -204,11 +204,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o"
- ]
+ "address": "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o",
+ "type": "pubkeyhash"
}
}
],
diff --git a/test/util/data/tt-locktime317000-out.json b/test/util/data/tt-locktime317000-out.json
index c97206f1ea..62e785f7d0 100644
--- a/test/util/data/tt-locktime317000-out.json
+++ b/test/util/data/tt-locktime317000-out.json
@@ -204,11 +204,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o"
- ]
+ "address": "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o",
+ "type": "pubkeyhash"
}
},
{
@@ -217,11 +214,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb"
- ]
+ "address": "1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb",
+ "type": "pubkeyhash"
}
}
],
diff --git a/test/util/data/txcreate1.json b/test/util/data/txcreate1.json
index ca9eacd546..96d77ef273 100644
--- a/test/util/data/txcreate1.json
+++ b/test/util/data/txcreate1.json
@@ -42,11 +42,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
+ "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
+ "type": "pubkeyhash"
}
},
{
@@ -55,11 +52,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 f2d4db28cad6502226ee484ae24505c2885cb12d OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"
- ]
+ "address": "1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46",
+ "type": "pubkeyhash"
}
}
],
diff --git a/test/util/data/txcreatedata1.json b/test/util/data/txcreatedata1.json
index 39909c2e3f..87fc7e9cf7 100644
--- a/test/util/data/txcreatedata1.json
+++ b/test/util/data/txcreatedata1.json
@@ -24,11 +24,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
+ "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
+ "type": "pubkeyhash"
}
},
{
diff --git a/test/util/data/txcreatedata2.json b/test/util/data/txcreatedata2.json
index 2958006e58..d03b1c8244 100644
--- a/test/util/data/txcreatedata2.json
+++ b/test/util/data/txcreatedata2.json
@@ -24,11 +24,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
+ "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
+ "type": "pubkeyhash"
}
},
{
diff --git a/test/util/data/txcreatedata_seq0.json b/test/util/data/txcreatedata_seq0.json
index a6656b5ad5..8a123f1ba8 100644
--- a/test/util/data/txcreatedata_seq0.json
+++ b/test/util/data/txcreatedata_seq0.json
@@ -24,11 +24,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
+ "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
+ "type": "pubkeyhash"
}
}
],
diff --git a/test/util/data/txcreatedata_seq1.json b/test/util/data/txcreatedata_seq1.json
index e5980427b1..006fd7259f 100644
--- a/test/util/data/txcreatedata_seq1.json
+++ b/test/util/data/txcreatedata_seq1.json
@@ -33,11 +33,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
+ "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
+ "type": "pubkeyhash"
}
}
],
diff --git a/test/util/data/txcreatemultisig1.json b/test/util/data/txcreatemultisig1.json
index c32e755db1..baa290c2b1 100644
--- a/test/util/data/txcreatemultisig1.json
+++ b/test/util/data/txcreatemultisig1.json
@@ -15,13 +15,7 @@
"scriptPubKey": {
"asm": "2 02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397 021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d 02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485 3 OP_CHECKMULTISIG",
"hex": "522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae",
- "reqSigs": 2,
- "type": "multisig",
- "addresses": [
- "1FoG2386FG2tAJS9acMuiDsKy67aGg9MKz",
- "1FXtz9KU8JNmQDyHdiEm5HDiALuP3zdHvV",
- "14LuavcBbXZYJ6Tsz3cAUQj9SuQoL2xCQX"
- ]
+ "type": "multisig"
}
}
],
diff --git a/test/util/data/txcreatemultisig2.json b/test/util/data/txcreatemultisig2.json
index f97d265894..6685512587 100644
--- a/test/util/data/txcreatemultisig2.json
+++ b/test/util/data/txcreatemultisig2.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "OP_HASH160 1c6fbaf46d64221e80cbae182c33ddf81b9294ac OP_EQUAL",
"hex": "a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac87",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "34HNh57oBCRKkxNyjTuWAJkTbuGh6jg2Ms"
- ]
+ "address": "34HNh57oBCRKkxNyjTuWAJkTbuGh6jg2Ms",
+ "type": "scripthash"
}
}
],
diff --git a/test/util/data/txcreatemultisig3.json b/test/util/data/txcreatemultisig3.json
index b355d7b191..be96f4c704 100644
--- a/test/util/data/txcreatemultisig3.json
+++ b/test/util/data/txcreatemultisig3.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "0 e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05",
"hex": "0020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05",
- "reqSigs": 1,
- "type": "witness_v0_scripthash",
- "addresses": [
- "bc1qu9dgdg330r6r84g5mw7wqshg04exv2uttmw2elfwx74h5tgntuzs44gyfg"
- ]
+ "address": "bc1qu9dgdg330r6r84g5mw7wqshg04exv2uttmw2elfwx74h5tgntuzs44gyfg",
+ "type": "witness_v0_scripthash"
}
}
],
diff --git a/test/util/data/txcreatemultisig4.json b/test/util/data/txcreatemultisig4.json
index a00dbe3f5d..08831ecdca 100644
--- a/test/util/data/txcreatemultisig4.json
+++ b/test/util/data/txcreatemultisig4.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "OP_HASH160 6edf12858999f0dae74f9c692e6694ee3621b2ac OP_EQUAL",
"hex": "a9146edf12858999f0dae74f9c692e6694ee3621b2ac87",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3BoFUz1StqcNcgUTZE5cC1eFhuYFzj3fGH"
- ]
+ "address": "3BoFUz1StqcNcgUTZE5cC1eFhuYFzj3fGH",
+ "type": "scripthash"
}
}
],
diff --git a/test/util/data/txcreatemultisig5.json b/test/util/data/txcreatemultisig5.json
index ea07822ddd..93048cf261 100644
--- a/test/util/data/txcreatemultisig5.json
+++ b/test/util/data/txcreatemultisig5.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "OP_HASH160 a4051c02398868af83f28f083208fae99a769263 OP_EQUAL",
"hex": "a914a4051c02398868af83f28f083208fae99a76926387",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3GeGs1eHUxPz5YyuFe9WPpXid2UsUb5Jos"
- ]
+ "address": "3GeGs1eHUxPz5YyuFe9WPpXid2UsUb5Jos",
+ "type": "scripthash"
}
}
],
diff --git a/test/util/data/txcreateoutpubkey2.json b/test/util/data/txcreateoutpubkey2.json
index c0ee181ede..52168a889b 100644
--- a/test/util/data/txcreateoutpubkey2.json
+++ b/test/util/data/txcreateoutpubkey2.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "0 a2516e770582864a6a56ed21a102044e388c62e3",
"hex": "0014a2516e770582864a6a56ed21a102044e388c62e3",
- "reqSigs": 1,
- "type": "witness_v0_keyhash",
- "addresses": [
- "bc1q5fgkuac9s2ry56jka5s6zqsyfcugcchry5cwu0"
- ]
+ "address": "bc1q5fgkuac9s2ry56jka5s6zqsyfcugcchry5cwu0",
+ "type": "witness_v0_keyhash"
}
}
],
diff --git a/test/util/data/txcreateoutpubkey3.json b/test/util/data/txcreateoutpubkey3.json
index 4d904df3c8..fce210f8a3 100644
--- a/test/util/data/txcreateoutpubkey3.json
+++ b/test/util/data/txcreateoutpubkey3.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "OP_HASH160 a5ab14c9804d0d8bf02f1aea4e82780733ad0a83 OP_EQUAL",
"hex": "a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a8387",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3GnzN8FqgvYGYdhj8NW6UNxxVv3Uj1ApQn"
- ]
+ "address": "3GnzN8FqgvYGYdhj8NW6UNxxVv3Uj1ApQn",
+ "type": "scripthash"
}
}
],
diff --git a/test/util/data/txcreatescript2.json b/test/util/data/txcreatescript2.json
index 32dd644579..2cde70fdf7 100644
--- a/test/util/data/txcreatescript2.json
+++ b/test/util/data/txcreatescript2.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "OP_HASH160 71ed53322d470bb96657deb786b94f97dd46fb15 OP_EQUAL",
"hex": "a91471ed53322d470bb96657deb786b94f97dd46fb1587",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3C5QarEGh9feKbDJ3QbMf2YNjnMoiPDhNp"
- ]
+ "address": "3C5QarEGh9feKbDJ3QbMf2YNjnMoiPDhNp",
+ "type": "scripthash"
}
}
],
diff --git a/test/util/data/txcreatescript3.json b/test/util/data/txcreatescript3.json
index b9192d9a82..7a282faf4f 100644
--- a/test/util/data/txcreatescript3.json
+++ b/test/util/data/txcreatescript3.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "0 0bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6",
"hex": "00200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6",
- "reqSigs": 1,
- "type": "witness_v0_scripthash",
- "addresses": [
- "bc1qp0lfxhnscvsu0j36l36uurgv5tuck4pzuqytkvwqp3kh78cupttqyf705v"
- ]
+ "address": "bc1qp0lfxhnscvsu0j36l36uurgv5tuck4pzuqytkvwqp3kh78cupttqyf705v",
+ "type": "witness_v0_scripthash"
}
}
],
diff --git a/test/util/data/txcreatescript4.json b/test/util/data/txcreatescript4.json
index 2271ecfa0a..298b37bb4a 100644
--- a/test/util/data/txcreatescript4.json
+++ b/test/util/data/txcreatescript4.json
@@ -15,11 +15,8 @@
"scriptPubKey": {
"asm": "OP_HASH160 6a2c482f4985f57e702f325816c90e3723ca81ae OP_EQUAL",
"hex": "a9146a2c482f4985f57e702f325816c90e3723ca81ae87",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3BNQbeFeJJGMAyDxPwWPuqxPMrjsFLjk3f"
- ]
+ "address": "3BNQbeFeJJGMAyDxPwWPuqxPMrjsFLjk3f",
+ "type": "scripthash"
}
}
],
diff --git a/test/util/data/txcreatesignv1.json b/test/util/data/txcreatesignv1.json
index 7a06aa9ffe..ca5e003110 100644
--- a/test/util/data/txcreatesignv1.json
+++ b/test/util/data/txcreatesignv1.json
@@ -24,11 +24,8 @@
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 5834479edbbe0539b31ffd3a8f8ebadc2165ed01 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"
- ]
+ "address": "193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7",
+ "type": "pubkeyhash"
}
}
],