aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am20
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/Makefile.qttest.include2
-rw-r--r--src/Makefile.test.include311
-rw-r--r--src/bench/coin_selection.cpp4
-rw-r--r--src/bench/crypto_hash.cpp11
-rw-r--r--src/bench/wallet_balance.cpp2
-rw-r--r--src/bitcoin-cli.cpp219
-rw-r--r--src/chainparams.cpp105
-rw-r--r--src/chainparams.h5
-rw-r--r--src/chainparamsbase.cpp16
-rw-r--r--src/chainparamsbase.h1
-rw-r--r--src/consensus/params.h7
-rw-r--r--src/consensus/validation.h27
-rw-r--r--src/core_write.cpp5
-rw-r--r--src/crypto/sha3.cpp161
-rw-r--r--src/crypto/sha3.h41
-rw-r--r--src/crypto/siphash.cpp2
-rw-r--r--src/crypto/siphash.h2
-rw-r--r--src/dummywallet.cpp1
-rw-r--r--src/init.cpp65
-rw-r--r--src/interfaces/chain.cpp28
-rw-r--r--src/interfaces/wallet.cpp28
-rw-r--r--src/interfaces/wallet.h5
-rw-r--r--src/miner.h2
-rw-r--r--src/net.cpp185
-rw-r--r--src/net.h120
-rw-r--r--src/net_processing.cpp435
-rw-r--r--src/net_processing.h72
-rw-r--r--src/node/context.cpp1
-rw-r--r--src/node/context.h6
-rw-r--r--src/node/transaction.cpp6
-rw-r--r--src/policy/rbf.cpp6
-rw-r--r--src/policy/rbf.h22
-rw-r--r--src/protocol.cpp6
-rw-r--r--src/protocol.h24
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/bitcoingui.cpp5
-rw-r--r--src/qt/bitcoingui.h1
-rw-r--r--src/qt/clientmodel.cpp4
-rw-r--r--src/qt/guiconstants.h1
-rw-r--r--src/qt/networkstyle.cpp3
-rw-r--r--src/qt/rpcconsole.cpp4
-rw-r--r--src/qt/test/addressbooktests.cpp4
-rw-r--r--src/qt/test/wallettests.cpp4
-rw-r--r--src/qt/walletcontroller.cpp9
-rw-r--r--src/qt/walletframe.cpp25
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/rest.cpp4
-rw-r--r--src/rpc/blockchain.cpp6
-rw-r--r--src/rpc/client.cpp3
-rw-r--r--src/rpc/net.cpp10
-rw-r--r--src/rpc/rawtransaction.cpp22
-rw-r--r--src/rpc/rawtransaction_util.cpp11
-rw-r--r--src/secp256k1/.gitignore4
-rw-r--r--src/secp256k1/.travis.yml26
-rw-r--r--src/secp256k1/Makefile.am12
-rw-r--r--src/secp256k1/TODO3
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m45
-rw-r--r--src/secp256k1/configure.ac135
-rw-r--r--src/secp256k1/contrib/lax_der_parsing.c1
-rwxr-xr-xsrc/secp256k1/contrib/travis.sh10
-rw-r--r--src/secp256k1/include/secp256k1.h2
-rw-r--r--src/secp256k1/include/secp256k1_extrakeys.h236
-rw-r--r--src/secp256k1/include/secp256k1_schnorrsig.h111
-rw-r--r--src/secp256k1/src/assumptions.h74
-rw-r--r--src/secp256k1/src/basic-config.h9
-rw-r--r--src/secp256k1/src/bench_internal.c174
-rw-r--r--src/secp256k1/src/bench_schnorrsig.c102
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h16
-rw-r--r--src/secp256k1/src/field.h12
-rw-r--r--src/secp256k1/src/field_5x52.h6
-rw-r--r--src/secp256k1/src/field_impl.h8
-rw-r--r--src/secp256k1/src/gen_context.c1
-rw-r--r--src/secp256k1/src/group.h4
-rw-r--r--src/secp256k1/src/group_impl.h13
-rw-r--r--src/secp256k1/src/hash_impl.h18
-rw-r--r--src/secp256k1/src/modules/extrakeys/Makefile.am.include3
-rw-r--r--src/secp256k1/src/modules/extrakeys/main_impl.h248
-rw-r--r--src/secp256k1/src/modules/extrakeys/tests_impl.h524
-rw-r--r--src/secp256k1/src/modules/schnorrsig/Makefile.am.include8
-rw-r--r--src/secp256k1/src/modules/schnorrsig/main_impl.h238
-rw-r--r--src/secp256k1/src/modules/schnorrsig/tests_impl.h806
-rw-r--r--src/secp256k1/src/scalar.h7
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h20
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h20
-rw-r--r--src/secp256k1/src/scalar_impl.h6
-rw-r--r--src/secp256k1/src/scratch_impl.h15
-rw-r--r--src/secp256k1/src/secp256k1.c78
-rw-r--r--src/secp256k1/src/selftest.h32
-rw-r--r--src/secp256k1/src/testrand.h3
-rw-r--r--src/secp256k1/src/testrand_impl.h4
-rw-r--r--src/secp256k1/src/tests.c113
-rw-r--r--src/secp256k1/src/tests_exhaustive.c7
-rw-r--r--src/secp256k1/src/util.h58
-rw-r--r--src/secp256k1/src/valgrind_ctime_test.c40
-rw-r--r--src/signet.cpp149
-rw-r--r--src/signet.h42
-rw-r--r--src/sync.cpp5
-rw-r--r--src/sync.h10
-rw-r--r--src/test/crypto_tests.cpp107
-rw-r--r--src/test/denialofservice_tests.cpp52
-rw-r--r--src/test/fuzz/crypto.cpp18
-rw-r--r--src/test/fuzz/net.cpp29
-rw-r--r--src/test/fuzz/process_message.cpp11
-rw-r--r--src/test/fuzz/process_messages.cpp6
-rw-r--r--src/test/fuzz/signet.cpp34
-rw-r--r--src/test/key_io_tests.cpp2
-rw-r--r--src/test/net_tests.cpp14
-rw-r--r--src/test/pow_tests.cpp47
-rw-r--r--src/test/util/setup_common.cpp10
-rw-r--r--src/test/util_tests.cpp8
-rw-r--r--src/txmempool.cpp191
-rw-r--r--src/txmempool.h80
-rw-r--r--src/util/system.cpp10
-rw-r--r--src/validation.cpp75
-rw-r--r--src/validation.h16
-rw-r--r--src/wallet/bdb.cpp45
-rw-r--r--src/wallet/bdb.h16
-rw-r--r--src/wallet/db.cpp8
-rw-r--r--src/wallet/db.h40
-rw-r--r--src/wallet/init.cpp33
-rw-r--r--src/wallet/load.cpp70
-rw-r--r--src/wallet/load.h10
-rw-r--r--src/wallet/rpcwallet.cpp293
-rw-r--r--src/wallet/salvage.cpp18
-rw-r--r--src/wallet/scriptpubkeyman.h2
-rw-r--r--src/wallet/test/coinselector_tests.cpp4
-rw-r--r--src/wallet/test/init_test_fixture.cpp2
-rw-r--r--src/wallet/test/ismine_tests.cpp40
-rw-r--r--src/wallet/test/scriptpubkeyman_tests.cpp2
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp2
-rw-r--r--src/wallet/test/wallet_test_fixture.h2
-rw-r--r--src/wallet/test/wallet_tests.cpp31
-rw-r--r--src/wallet/wallet.cpp217
-rw-r--r--src/wallet/wallet.h44
-rw-r--r--src/wallet/walletdb.cpp70
-rw-r--r--src/wallet/walletdb.h12
-rw-r--r--src/wallet/wallettool.cpp43
-rw-r--r--src/wallet/wallettool.h2
-rw-r--r--src/wallet/walletutil.cpp18
-rw-r--r--src/wallet/walletutil.h20
-rw-r--r--src/zmq/zmqabstractnotifier.cpp2
-rw-r--r--src/zmq/zmqabstractnotifier.h12
-rw-r--r--src/zmq/zmqconfig.h22
-rw-r--r--src/zmq/zmqnotificationinterface.cpp114
-rw-r--r--src/zmq/zmqnotificationinterface.h3
-rw-r--r--src/zmq/zmqpublishnotifier.cpp34
-rw-r--r--src/zmq/zmqpublishnotifier.h2
-rw-r--r--src/zmq/zmqutil.cpp14
-rw-r--r--src/zmq/zmqutil.h10
152 files changed, 5743 insertions, 1719 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 175501d4a6..aa63b5f516 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,10 +4,11 @@
DIST_SUBDIRS = secp256k1 univalue
-AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
+AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS)
AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS)
AM_LIBTOOLFLAGS = --preserve-dup-deps
+PTHREAD_FLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
EXTRA_LIBRARIES =
if EMBEDDED_UNIVALUE
@@ -201,6 +202,7 @@ BITCOIN_CORE_H = \
script/signingprovider.h \
script/standard.h \
shutdown.h \
+ signet.h \
streams.h \
support/allocators/secure.h \
support/allocators/zeroafterfree.h \
@@ -262,10 +264,10 @@ BITCOIN_CORE_H = \
walletinitinterface.h \
warnings.h \
zmq/zmqabstractnotifier.h \
- zmq/zmqconfig.h\
zmq/zmqnotificationinterface.h \
zmq/zmqpublishnotifier.h \
- zmq/zmqrpc.h
+ zmq/zmqrpc.h \
+ zmq/zmqutil.h
obj/build.h: FORCE
@@ -321,6 +323,7 @@ libbitcoin_server_a_SOURCES = \
rpc/server.cpp \
script/sigcache.cpp \
shutdown.cpp \
+ signet.cpp \
timedata.cpp \
torcontrol.cpp \
txdb.cpp \
@@ -344,7 +347,8 @@ libbitcoin_zmq_a_SOURCES = \
zmq/zmqabstractnotifier.cpp \
zmq/zmqnotificationinterface.cpp \
zmq/zmqpublishnotifier.cpp \
- zmq/zmqrpc.cpp
+ zmq/zmqrpc.cpp \
+ zmq/zmqutil.cpp
endif
@@ -403,6 +407,8 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/sha1.h \
crypto/sha256.cpp \
crypto/sha256.h \
+ crypto/sha3.cpp \
+ crypto/sha3.h \
crypto/sha512.cpp \
crypto/sha512.h \
crypto/siphash.cpp \
@@ -564,7 +570,7 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
bitcoin_daemon_sources = bitcoind.cpp
bitcoin_bin_cppflags = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
bitcoin_bin_cxxflags = $(AM_CXXFLAGS) $(PIE_FLAGS)
-bitcoin_bin_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+bitcoin_bin_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
if TARGET_WINDOWS
bitcoin_daemon_sources += bitcoind-res.rc
@@ -601,7 +607,7 @@ bitcoin_node_LDADD = $(LIBBITCOIN_SERVER) $(bitcoin_bin_ldadd)
bitcoin_cli_SOURCES = bitcoin-cli.cpp
bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
bitcoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
if TARGET_WINDOWS
bitcoin_cli_SOURCES += bitcoin-cli-res.rc
@@ -620,7 +626,7 @@ bitcoin_cli_LDADD += $(BOOST_LIBS) $(EVENT_LIBS)
bitcoin_tx_SOURCES = bitcoin-tx.cpp
bitcoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
bitcoin_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
if TARGET_WINDOWS
bitcoin_tx_SOURCES += bitcoin-tx-res.rc
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index c224ca7bf6..bd9143a381 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -75,7 +75,7 @@ bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp
endif
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS)
-bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 848053e841..69ff0f0251 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -322,7 +322,7 @@ endif
bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
-bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX
qt_bitcoin_qt_CPPFLAGS = $(bitcoin_qt_cppflags)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 8c47fabad9..d300398b25 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -57,7 +57,7 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBIT
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
-qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 91cdecad40..06dde87ddd 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -137,6 +137,7 @@ FUZZ_TARGETS = \
test/fuzz/secp256k1_ecdsa_signature_parse_der_lax \
test/fuzz/service_deserialize \
test/fuzz/signature_checker \
+ test/fuzz/signet \
test/fuzz/snapshotmetadata_deserialize \
test/fuzz/span \
test/fuzz/spanparsing \
@@ -315,7 +316,7 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS)
-test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
+test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -static
if ENABLE_ZMQ
test_test_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
@@ -323,904 +324,912 @@ endif
if ENABLE_FUZZ
+FUZZ_SUITE_LDFLAGS_COMMON = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
+
test_fuzz_addition_overflow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_addition_overflow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_addition_overflow_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_addition_overflow_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_addition_overflow_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_addition_overflow_SOURCES = test/fuzz/addition_overflow.cpp
test_fuzz_addr_info_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDR_INFO_DESERIALIZE=1
test_fuzz_addr_info_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_addr_info_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_addr_info_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_addr_info_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_addr_info_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_addrdb_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_addrdb_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_addrdb_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_addrdb_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_addrdb_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_addrdb_SOURCES = test/fuzz/addrdb.cpp
test_fuzz_address_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRESS_DESERIALIZE=1
test_fuzz_address_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_address_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_address_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_address_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_address_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_addrman_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRMAN_DESERIALIZE=1
test_fuzz_addrman_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_addrman_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_addrman_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_addrman_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_addrman_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_asmap_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_asmap_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_asmap_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_asmap_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_asmap_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_asmap_SOURCES = test/fuzz/asmap.cpp
test_fuzz_asmap_direct_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_asmap_direct_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_asmap_direct_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_asmap_direct_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_asmap_direct_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_asmap_direct_SOURCES = test/fuzz/asmap_direct.cpp
test_fuzz_autofile_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_autofile_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_autofile_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_autofile_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_autofile_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_autofile_SOURCES = test/fuzz/autofile.cpp
test_fuzz_banentry_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBANENTRY_DESERIALIZE=1
test_fuzz_banentry_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_banentry_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_banentry_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_banentry_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_banentry_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_banman_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_banman_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_banman_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_banman_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_banman_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_banman_SOURCES = test/fuzz/banman.cpp
test_fuzz_base_encode_decode_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_base_encode_decode_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_base_encode_decode_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_base_encode_decode_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_base_encode_decode_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_base_encode_decode_SOURCES = test/fuzz/base_encode_decode.cpp
test_fuzz_bech32_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_bech32_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_bech32_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_bech32_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_bech32_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_bech32_SOURCES = test/fuzz/bech32.cpp
test_fuzz_block_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_block_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_block_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_block_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_block_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_block_SOURCES = test/fuzz/block.cpp
test_fuzz_block_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_DESERIALIZE=1
test_fuzz_block_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_block_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_block_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_block_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_block_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_block_file_info_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_FILE_INFO_DESERIALIZE=1
test_fuzz_block_file_info_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_block_file_info_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_block_file_info_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_block_file_info_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_block_file_info_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_block_filter_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_FILTER_DESERIALIZE=1
test_fuzz_block_filter_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_block_filter_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_block_filter_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_block_filter_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_block_filter_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_block_header_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_block_header_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_block_header_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_block_header_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_block_header_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_block_header_SOURCES = test/fuzz/block_header.cpp
test_fuzz_block_header_and_short_txids_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE=1
test_fuzz_block_header_and_short_txids_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_block_header_and_short_txids_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_block_header_and_short_txids_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_block_header_and_short_txids_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_block_header_and_short_txids_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_blockfilter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_blockfilter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blockfilter_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_blockfilter_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blockfilter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_blockfilter_SOURCES = test/fuzz/blockfilter.cpp
test_fuzz_blockheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKHEADER_DESERIALIZE=1
test_fuzz_blockheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blockheader_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_blockheader_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blockheader_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_blockheader_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_blocklocator_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKLOCATOR_DESERIALIZE=1
test_fuzz_blocklocator_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blocklocator_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_blocklocator_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blocklocator_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_blocklocator_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_blockmerkleroot_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKMERKLEROOT=1
test_fuzz_blockmerkleroot_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blockmerkleroot_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_blockmerkleroot_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blockmerkleroot_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_blockmerkleroot_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_blocktransactions_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONS_DESERIALIZE=1
test_fuzz_blocktransactions_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blocktransactions_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_blocktransactions_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blocktransactions_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_blocktransactions_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_blocktransactionsrequest_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONSREQUEST_DESERIALIZE=1
test_fuzz_blocktransactionsrequest_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blocktransactionsrequest_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_blocktransactionsrequest_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blocktransactionsrequest_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_blocktransactionsrequest_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_blockundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKUNDO_DESERIALIZE=1
test_fuzz_blockundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blockundo_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_blockundo_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blockundo_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_blockundo_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_bloom_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_bloom_filter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_bloom_filter_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_bloom_filter_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_bloom_filter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_bloom_filter_SOURCES = test/fuzz/bloom_filter.cpp
test_fuzz_bloomfilter_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOOMFILTER_DESERIALIZE=1
test_fuzz_bloomfilter_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_bloomfilter_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_bloomfilter_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_bloomfilter_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_bloomfilter_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_buffered_file_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_buffered_file_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_buffered_file_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_buffered_file_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_buffered_file_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_buffered_file_SOURCES = test/fuzz/buffered_file.cpp
test_fuzz_chain_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_chain_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_chain_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_chain_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_chain_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_chain_SOURCES = test/fuzz/chain.cpp
test_fuzz_checkqueue_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_checkqueue_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_checkqueue_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_checkqueue_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_checkqueue_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_checkqueue_SOURCES = test/fuzz/checkqueue.cpp
test_fuzz_coins_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DCOINS_DESERIALIZE=1
test_fuzz_coins_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_coins_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_coins_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_coins_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_coins_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_coins_view_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_coins_view_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_coins_view_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_coins_view_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_coins_view_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_coins_view_SOURCES = test/fuzz/coins_view.cpp
test_fuzz_crypto_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_crypto_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_crypto_SOURCES = test/fuzz/crypto.cpp
test_fuzz_crypto_aes256_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_aes256_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_aes256_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_crypto_aes256_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_aes256_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_crypto_aes256_SOURCES = test/fuzz/crypto_aes256.cpp
test_fuzz_crypto_aes256cbc_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_aes256cbc_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_aes256cbc_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_crypto_aes256cbc_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_aes256cbc_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_crypto_aes256cbc_SOURCES = test/fuzz/crypto_aes256cbc.cpp
test_fuzz_crypto_chacha20_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_chacha20_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_chacha20_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_crypto_chacha20_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_chacha20_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_crypto_chacha20_SOURCES = test/fuzz/crypto_chacha20.cpp
test_fuzz_crypto_chacha20_poly1305_aead_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_chacha20_poly1305_aead_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_chacha20_poly1305_aead_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_crypto_chacha20_poly1305_aead_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_chacha20_poly1305_aead_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_crypto_chacha20_poly1305_aead_SOURCES = test/fuzz/crypto_chacha20_poly1305_aead.cpp
test_fuzz_crypto_common_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_common_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_common_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_crypto_common_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_common_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_crypto_common_SOURCES = test/fuzz/crypto_common.cpp
test_fuzz_crypto_hkdf_hmac_sha256_l32_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_hkdf_hmac_sha256_l32_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_hkdf_hmac_sha256_l32_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_crypto_hkdf_hmac_sha256_l32_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_hkdf_hmac_sha256_l32_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_crypto_hkdf_hmac_sha256_l32_SOURCES = test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp
test_fuzz_crypto_poly1305_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_poly1305_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_poly1305_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_crypto_poly1305_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_poly1305_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_crypto_poly1305_SOURCES = test/fuzz/crypto_poly1305.cpp
test_fuzz_cuckoocache_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_cuckoocache_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_cuckoocache_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_cuckoocache_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_cuckoocache_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_cuckoocache_SOURCES = test/fuzz/cuckoocache.cpp
test_fuzz_decode_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_decode_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_decode_tx_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_decode_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_decode_tx_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_decode_tx_SOURCES = test/fuzz/decode_tx.cpp
test_fuzz_descriptor_parse_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_descriptor_parse_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_descriptor_parse_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_descriptor_parse_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_descriptor_parse_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_descriptor_parse_SOURCES = test/fuzz/descriptor_parse.cpp
test_fuzz_diskblockindex_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DDISKBLOCKINDEX_DESERIALIZE=1
test_fuzz_diskblockindex_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_diskblockindex_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_diskblockindex_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_diskblockindex_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_diskblockindex_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_eval_script_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_eval_script_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_eval_script_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_eval_script_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_eval_script_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_eval_script_SOURCES = test/fuzz/eval_script.cpp
test_fuzz_fee_rate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_fee_rate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_fee_rate_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_fee_rate_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_fee_rate_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_fee_rate_SOURCES = test/fuzz/fee_rate.cpp
test_fuzz_fee_rate_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DFEE_RATE_DESERIALIZE=1
test_fuzz_fee_rate_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_fee_rate_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_fee_rate_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_fee_rate_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_fee_rate_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_fees_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_fees_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_fees_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_fees_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_fees_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_fees_SOURCES = test/fuzz/fees.cpp
test_fuzz_flat_file_pos_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DFLAT_FILE_POS_DESERIALIZE=1
test_fuzz_flat_file_pos_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_flat_file_pos_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_flat_file_pos_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_flat_file_pos_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_flat_file_pos_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_flatfile_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_flatfile_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_flatfile_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_flatfile_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_flatfile_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_flatfile_SOURCES = test/fuzz/flatfile.cpp
test_fuzz_float_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_float_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_float_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_float_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_float_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_float_SOURCES = test/fuzz/float.cpp
test_fuzz_golomb_rice_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_golomb_rice_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_golomb_rice_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_golomb_rice_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_golomb_rice_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_golomb_rice_SOURCES = test/fuzz/golomb_rice.cpp
test_fuzz_hex_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_hex_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_hex_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_hex_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_hex_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_hex_SOURCES = test/fuzz/hex.cpp
test_fuzz_http_request_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_http_request_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_http_request_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_http_request_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_http_request_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_http_request_SOURCES = test/fuzz/http_request.cpp
test_fuzz_integer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_integer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_integer_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_integer_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_integer_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_integer_SOURCES = test/fuzz/integer.cpp
test_fuzz_inv_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DINV_DESERIALIZE=1
test_fuzz_inv_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_inv_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_inv_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_inv_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_inv_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_key_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_key_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_key_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_key_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_key_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_key_SOURCES = test/fuzz/key.cpp
test_fuzz_key_io_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_key_io_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_key_io_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_key_io_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_key_io_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_key_io_SOURCES = test/fuzz/key_io.cpp
test_fuzz_key_origin_info_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DKEY_ORIGIN_INFO_DESERIALIZE=1
test_fuzz_key_origin_info_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_key_origin_info_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_key_origin_info_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_key_origin_info_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_key_origin_info_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_kitchen_sink_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_kitchen_sink_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_kitchen_sink_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_kitchen_sink_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_kitchen_sink_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_kitchen_sink_SOURCES = test/fuzz/kitchen_sink.cpp
test_fuzz_load_external_block_file_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_load_external_block_file_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_load_external_block_file_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_load_external_block_file_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_load_external_block_file_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_load_external_block_file_SOURCES = test/fuzz/load_external_block_file.cpp
test_fuzz_locale_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_locale_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_locale_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_locale_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_locale_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_locale_SOURCES = test/fuzz/locale.cpp
test_fuzz_merkle_block_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMERKLE_BLOCK_DESERIALIZE=1
test_fuzz_merkle_block_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_merkle_block_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_merkle_block_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_merkle_block_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_merkle_block_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_merkleblock_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_merkleblock_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_merkleblock_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_merkleblock_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_merkleblock_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_merkleblock_SOURCES = test/fuzz/merkleblock.cpp
test_fuzz_message_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_message_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_message_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_message_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_message_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_message_SOURCES = test/fuzz/message.cpp
test_fuzz_messageheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGEHEADER_DESERIALIZE=1
test_fuzz_messageheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_messageheader_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_messageheader_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_messageheader_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_messageheader_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_multiplication_overflow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_multiplication_overflow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_multiplication_overflow_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_multiplication_overflow_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_multiplication_overflow_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_multiplication_overflow_SOURCES = test/fuzz/multiplication_overflow.cpp
test_fuzz_net_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_net_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_net_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_net_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_net_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_net_SOURCES = test/fuzz/net.cpp
test_fuzz_net_permissions_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_net_permissions_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_net_permissions_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_net_permissions_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_net_permissions_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_net_permissions_SOURCES = test/fuzz/net_permissions.cpp
test_fuzz_netaddr_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DNETADDR_DESERIALIZE=1
test_fuzz_netaddr_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_netaddr_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_netaddr_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_netaddr_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_netaddr_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_netaddress_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_netaddress_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_netaddress_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_netaddress_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_netaddress_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_netaddress_SOURCES = test/fuzz/netaddress.cpp
test_fuzz_out_point_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DOUT_POINT_DESERIALIZE=1
test_fuzz_out_point_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_out_point_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_out_point_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_out_point_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_out_point_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_p2p_transport_deserializer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_p2p_transport_deserializer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_p2p_transport_deserializer_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_p2p_transport_deserializer_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_p2p_transport_deserializer_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_p2p_transport_deserializer_SOURCES = test/fuzz/p2p_transport_deserializer.cpp
test_fuzz_parse_hd_keypath_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_parse_hd_keypath_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_parse_hd_keypath_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_parse_hd_keypath_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_parse_hd_keypath_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_parse_hd_keypath_SOURCES = test/fuzz/parse_hd_keypath.cpp
test_fuzz_parse_iso8601_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_parse_iso8601_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_parse_iso8601_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_parse_iso8601_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_parse_iso8601_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_parse_iso8601_SOURCES = test/fuzz/parse_iso8601.cpp
test_fuzz_parse_numbers_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_parse_numbers_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_parse_numbers_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_parse_numbers_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_parse_numbers_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_parse_numbers_SOURCES = test/fuzz/parse_numbers.cpp
test_fuzz_parse_script_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_parse_script_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_parse_script_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_parse_script_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_parse_script_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_parse_script_SOURCES = test/fuzz/parse_script.cpp
test_fuzz_parse_univalue_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_parse_univalue_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_parse_univalue_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_parse_univalue_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_parse_univalue_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_parse_univalue_SOURCES = test/fuzz/parse_univalue.cpp
test_fuzz_prevector_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_prevector_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_prevector_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_prevector_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_prevector_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_prevector_SOURCES = test/fuzz/prevector.cpp
test_fuzz_partial_merkle_tree_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPARTIAL_MERKLE_TREE_DESERIALIZE=1
test_fuzz_partial_merkle_tree_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_partial_merkle_tree_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_partial_merkle_tree_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_partial_merkle_tree_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_partial_merkle_tree_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_partially_signed_transaction_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPARTIALLY_SIGNED_TRANSACTION_DESERIALIZE=1
test_fuzz_partially_signed_transaction_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_partially_signed_transaction_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_partially_signed_transaction_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_partially_signed_transaction_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_partially_signed_transaction_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_policy_estimator_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_policy_estimator_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_policy_estimator_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_policy_estimator_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_policy_estimator_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_policy_estimator_SOURCES = test/fuzz/policy_estimator.cpp
test_fuzz_policy_estimator_io_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_policy_estimator_io_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_policy_estimator_io_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_policy_estimator_io_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_policy_estimator_io_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_policy_estimator_io_SOURCES = test/fuzz/policy_estimator_io.cpp
test_fuzz_pow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_pow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_pow_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_pow_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_pow_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_pow_SOURCES = test/fuzz/pow.cpp
test_fuzz_prefilled_transaction_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPREFILLED_TRANSACTION_DESERIALIZE=1
test_fuzz_prefilled_transaction_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_prefilled_transaction_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_prefilled_transaction_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_prefilled_transaction_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_prefilled_transaction_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_primitives_transaction_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_primitives_transaction_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_primitives_transaction_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_primitives_transaction_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_primitives_transaction_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_primitives_transaction_SOURCES = test/fuzz/primitives_transaction.cpp
test_fuzz_process_messages_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_process_messages_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_messages_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_messages_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_messages_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_messages_SOURCES = test/fuzz/process_messages.cpp
test_fuzz_process_message_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_process_message_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_addr_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=addr
test_fuzz_process_message_addr_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_addr_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_addr_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_addr_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_addr_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_block_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=block
test_fuzz_process_message_block_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_block_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_block_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_block_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_block_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_blocktxn_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=blocktxn
test_fuzz_process_message_blocktxn_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_blocktxn_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_blocktxn_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_blocktxn_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_blocktxn_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_cmpctblock_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=cmpctblock
test_fuzz_process_message_cmpctblock_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_cmpctblock_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_cmpctblock_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_cmpctblock_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_cmpctblock_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_feefilter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=feefilter
test_fuzz_process_message_feefilter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_feefilter_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_feefilter_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_feefilter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_feefilter_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_filteradd_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=filteradd
test_fuzz_process_message_filteradd_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_filteradd_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_filteradd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_filteradd_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_filteradd_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_filterclear_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=filterclear
test_fuzz_process_message_filterclear_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_filterclear_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_filterclear_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_filterclear_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_filterclear_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_filterload_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=filterload
test_fuzz_process_message_filterload_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_filterload_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_filterload_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_filterload_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_filterload_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_getaddr_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getaddr
test_fuzz_process_message_getaddr_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_getaddr_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_getaddr_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_getaddr_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_getaddr_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_getblocks_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getblocks
test_fuzz_process_message_getblocks_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_getblocks_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_getblocks_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_getblocks_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_getblocks_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_getblocktxn_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getblocktxn
test_fuzz_process_message_getblocktxn_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_getblocktxn_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_getblocktxn_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_getblocktxn_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_getblocktxn_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_getdata_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getdata
test_fuzz_process_message_getdata_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_getdata_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_getdata_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_getdata_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_getdata_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_getheaders_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getheaders
test_fuzz_process_message_getheaders_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_getheaders_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_getheaders_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_getheaders_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_getheaders_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_headers_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=headers
test_fuzz_process_message_headers_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_headers_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_headers_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_headers_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_headers_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_inv_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=inv
test_fuzz_process_message_inv_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_inv_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_inv_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_inv_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_inv_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_mempool_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=mempool
test_fuzz_process_message_mempool_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_mempool_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_mempool_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_mempool_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_mempool_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_notfound_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=notfound
test_fuzz_process_message_notfound_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_notfound_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_notfound_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_notfound_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_notfound_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_ping_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=ping
test_fuzz_process_message_ping_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_ping_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_ping_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_ping_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_ping_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_pong_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=pong
test_fuzz_process_message_pong_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_pong_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_pong_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_pong_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_pong_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_sendcmpct_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=sendcmpct
test_fuzz_process_message_sendcmpct_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_sendcmpct_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_sendcmpct_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_sendcmpct_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_sendcmpct_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_sendheaders_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=sendheaders
test_fuzz_process_message_sendheaders_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_sendheaders_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_sendheaders_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_sendheaders_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_sendheaders_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=tx
test_fuzz_process_message_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_tx_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_tx_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_tx_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_verack_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=verack
test_fuzz_process_message_verack_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_verack_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_verack_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_verack_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_verack_SOURCES = test/fuzz/process_message.cpp
test_fuzz_process_message_version_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=version
test_fuzz_process_message_version_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_process_message_version_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_process_message_version_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_process_message_version_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_process_message_version_SOURCES = test/fuzz/process_message.cpp
test_fuzz_protocol_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_protocol_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_protocol_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_protocol_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_protocol_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_protocol_SOURCES = test/fuzz/protocol.cpp
test_fuzz_psbt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_psbt_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_psbt_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_psbt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_psbt_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_psbt_SOURCES = test/fuzz/psbt.cpp
test_fuzz_psbt_input_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPSBT_INPUT_DESERIALIZE=1
test_fuzz_psbt_input_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_psbt_input_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_psbt_input_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_psbt_input_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_psbt_input_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_psbt_output_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPSBT_OUTPUT_DESERIALIZE=1
test_fuzz_psbt_output_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_psbt_output_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_psbt_output_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_psbt_output_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_psbt_output_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_pub_key_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPUB_KEY_DESERIALIZE=1
test_fuzz_pub_key_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_pub_key_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_pub_key_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_pub_key_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_pub_key_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_random_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_random_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_random_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_random_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_random_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_random_SOURCES = test/fuzz/random.cpp
test_fuzz_rbf_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_rbf_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_rbf_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_rbf_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_rbf_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_rbf_SOURCES = test/fuzz/rbf.cpp
test_fuzz_rolling_bloom_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_rolling_bloom_filter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_rolling_bloom_filter_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_rolling_bloom_filter_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_rolling_bloom_filter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_rolling_bloom_filter_SOURCES = test/fuzz/rolling_bloom_filter.cpp
test_fuzz_script_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_SOURCES = test/fuzz/script.cpp
test_fuzz_script_bitcoin_consensus_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_bitcoin_consensus_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_bitcoin_consensus_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_bitcoin_consensus_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_bitcoin_consensus_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_bitcoin_consensus_SOURCES = test/fuzz/script_bitcoin_consensus.cpp
test_fuzz_script_descriptor_cache_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_descriptor_cache_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_descriptor_cache_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_descriptor_cache_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_descriptor_cache_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_descriptor_cache_SOURCES = test/fuzz/script_descriptor_cache.cpp
test_fuzz_script_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSCRIPT_DESERIALIZE=1
test_fuzz_script_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_script_flags_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_flags_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_flags_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_flags_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_flags_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_flags_SOURCES = test/fuzz/script_flags.cpp
test_fuzz_script_interpreter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_interpreter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_interpreter_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_interpreter_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_interpreter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_interpreter_SOURCES = test/fuzz/script_interpreter.cpp
test_fuzz_script_ops_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_ops_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_ops_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_ops_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_ops_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_ops_SOURCES = test/fuzz/script_ops.cpp
test_fuzz_script_sigcache_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_sigcache_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_sigcache_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_sigcache_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_sigcache_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_sigcache_SOURCES = test/fuzz/script_sigcache.cpp
test_fuzz_script_sign_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_sign_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_sign_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_sign_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_sign_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_sign_SOURCES = test/fuzz/script_sign.cpp
test_fuzz_scriptnum_ops_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_scriptnum_ops_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_scriptnum_ops_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_scriptnum_ops_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_scriptnum_ops_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_scriptnum_ops_SOURCES = test/fuzz/scriptnum_ops.cpp
test_fuzz_secp256k1_ec_seckey_import_export_der_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_secp256k1_ec_seckey_import_export_der_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_secp256k1_ec_seckey_import_export_der_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_secp256k1_ec_seckey_import_export_der_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_secp256k1_ec_seckey_import_export_der_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_secp256k1_ec_seckey_import_export_der_SOURCES = test/fuzz/secp256k1_ec_seckey_import_export_der.cpp
test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_SOURCES = test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp
test_fuzz_service_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSERVICE_DESERIALIZE=1
test_fuzz_service_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_service_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_service_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_service_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_service_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_signature_checker_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_signature_checker_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_signature_checker_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_signature_checker_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_signature_checker_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_signature_checker_SOURCES = test/fuzz/signature_checker.cpp
+test_fuzz_signet_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_signet_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_signet_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_signet_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_signet_SOURCES = test/fuzz/signet.cpp
+
test_fuzz_snapshotmetadata_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSNAPSHOTMETADATA_DESERIALIZE=1
test_fuzz_snapshotmetadata_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_snapshotmetadata_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_snapshotmetadata_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_snapshotmetadata_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_snapshotmetadata_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_span_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_span_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_span_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_span_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_span_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_span_SOURCES = test/fuzz/span.cpp
test_fuzz_spanparsing_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_spanparsing_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_spanparsing_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_spanparsing_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_spanparsing_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_spanparsing_SOURCES = test/fuzz/spanparsing.cpp
test_fuzz_string_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_string_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_string_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_string_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_string_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_string_SOURCES = test/fuzz/string.cpp
test_fuzz_strprintf_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_strprintf_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_strprintf_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_strprintf_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_strprintf_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_strprintf_SOURCES = test/fuzz/strprintf.cpp
test_fuzz_sub_net_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSUB_NET_DESERIALIZE=1
test_fuzz_sub_net_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_sub_net_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_sub_net_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_sub_net_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_sub_net_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_system_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_system_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_system_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_system_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_system_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_system_SOURCES = test/fuzz/system.cpp
test_fuzz_timedata_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_timedata_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_timedata_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_timedata_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_timedata_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_timedata_SOURCES = test/fuzz/timedata.cpp
test_fuzz_transaction_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_transaction_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_transaction_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_transaction_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_transaction_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_transaction_SOURCES = test/fuzz/transaction.cpp
test_fuzz_tx_in_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_tx_in_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_tx_in_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_tx_in_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_tx_in_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_tx_in_SOURCES = test/fuzz/tx_in.cpp
test_fuzz_tx_in_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTX_IN_DESERIALIZE=1
test_fuzz_tx_in_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_tx_in_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_tx_in_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_tx_in_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_tx_in_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_tx_out_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_tx_out_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_tx_out_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_tx_out_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_tx_out_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_tx_out_SOURCES = test/fuzz/tx_out.cpp
test_fuzz_txoutcompressor_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXOUTCOMPRESSOR_DESERIALIZE=1
test_fuzz_txoutcompressor_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_txoutcompressor_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_txoutcompressor_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_txoutcompressor_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_txoutcompressor_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_txundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXUNDO_DESERIALIZE=1
test_fuzz_txundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_txundo_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_txundo_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_txundo_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_txundo_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_uint160_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DUINT160_DESERIALIZE=1
test_fuzz_uint160_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_uint160_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_uint160_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_uint160_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_uint160_deserialize_SOURCES = test/fuzz/deserialize.cpp
test_fuzz_uint256_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DUINT256_DESERIALIZE=1
test_fuzz_uint256_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_uint256_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_uint256_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_uint256_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_uint256_deserialize_SOURCES = test/fuzz/deserialize.cpp
endif # ENABLE_FUZZ
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 3a71a6ca03..99aafd8dfc 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -31,7 +31,7 @@ static void CoinSelection(benchmark::Bench& bench)
{
NodeContext node;
auto chain = interfaces::MakeChain(node);
- CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
wallet.SetupLegacyScriptPubKeyMan();
std::vector<std::unique_ptr<CWalletTx>> wtxs;
LOCK(wallet.cs_wallet);
@@ -65,7 +65,7 @@ static void CoinSelection(benchmark::Bench& bench)
typedef std::set<CInputCoin> CoinSet;
static NodeContext testNode;
static auto testChain = interfaces::MakeChain(testNode);
-static CWallet testWallet(testChain.get(), WalletLocation(), CreateDummyWalletDatabase());
+static CWallet testWallet(testChain.get(), "", CreateDummyWalletDatabase());
std::vector<std::unique_ptr<CWalletTx>> wtxn;
// Copied from src/wallet/test/coinselector_tests.cpp
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 36be86bcc8..65d16d47d8 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -7,6 +7,7 @@
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
+#include <crypto/sha3.h>
#include <crypto/sha512.h>
#include <crypto/siphash.h>
#include <hash.h>
@@ -43,6 +44,15 @@ static void SHA256(benchmark::Bench& bench)
});
}
+static void SHA3_256_1M(benchmark::Bench& bench)
+{
+ uint8_t hash[SHA3_256::OUTPUT_SIZE];
+ std::vector<uint8_t> in(BUFFER_SIZE,0);
+ bench.batch(in.size()).unit("byte").run([&] {
+ SHA3_256().Write(in).Finalize(hash);
+ });
+}
+
static void SHA256_32b(benchmark::Bench& bench)
{
std::vector<uint8_t> in(32,0);
@@ -99,6 +109,7 @@ BENCHMARK(RIPEMD160);
BENCHMARK(SHA1);
BENCHMARK(SHA256);
BENCHMARK(SHA512);
+BENCHMARK(SHA3_256_1M);
BENCHMARK(SHA256_32b);
BENCHMARK(SipHash_32b);
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
index e16182b48e..b3b73284d8 100644
--- a/src/bench/wallet_balance.cpp
+++ b/src/bench/wallet_balance.cpp
@@ -26,7 +26,7 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
NodeContext node;
std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node);
- CWallet wallet{chain.get(), WalletLocation(), CreateMockWalletDatabase()};
+ CWallet wallet{chain.get(), "", CreateMockWalletDatabase()};
{
wallet.SetupLegacyScriptPubKeyMan();
bool first_run;
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index cf52b710cb..198cd5eb52 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -39,6 +39,8 @@ static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const bool DEFAULT_NAMED=false;
static const int CONTINUE_EXECUTION=-1;
+static const std::string ONION{".onion"};
+static const size_t ONION_LEN{ONION.size()};
/** Default number of blocks to generate for RPC generatetoaddress. */
static const std::string DEFAULT_NBLOCKS = "1";
@@ -56,6 +58,8 @@ static void SetupCliArgs(ArgsManager& argsman)
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC generatenewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0).", ArgsManager::ALLOW_INT, OptionsCategory::OPTIONS);
+
SetupChainParamsBaseOptions(argsman);
argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-rpcclienttimeout=<n>", strprintf("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -271,7 +275,13 @@ public:
result.pushKV("headers", batch[ID_BLOCKCHAININFO]["result"]["headers"]);
result.pushKV("verificationprogress", batch[ID_BLOCKCHAININFO]["result"]["verificationprogress"]);
result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]);
- result.pushKV("connections", batch[ID_NETWORKINFO]["result"]["connections"]);
+
+ UniValue connections(UniValue::VOBJ);
+ connections.pushKV("in", batch[ID_NETWORKINFO]["result"]["connections_in"]);
+ connections.pushKV("out", batch[ID_NETWORKINFO]["result"]["connections_out"]);
+ connections.pushKV("total", batch[ID_NETWORKINFO]["result"]["connections"]);
+ result.pushKV("connections", connections);
+
result.pushKV("proxy", batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]);
result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
result.pushKV("chain", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"]));
@@ -291,6 +301,211 @@ public:
}
};
+/** Process netinfo requests */
+class NetinfoRequestHandler : public BaseRequestHandler
+{
+private:
+ bool IsAddrIPv6(const std::string& addr) const
+ {
+ return !addr.empty() && addr.front() == '[';
+ }
+ bool IsInboundOnion(const std::string& addr_local, int mapped_as) const
+ {
+ return mapped_as == 0 && addr_local.find(ONION) != std::string::npos;
+ }
+ bool IsOutboundOnion(const std::string& addr, int mapped_as) const
+ {
+ const size_t addr_len{addr.size()};
+ const size_t onion_pos{addr.rfind(ONION)};
+ return mapped_as == 0 && onion_pos != std::string::npos && addr_len > ONION_LEN &&
+ (onion_pos == addr_len - ONION_LEN || onion_pos == addr.find_last_of(":") - ONION_LEN);
+ }
+ uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level
+ bool DetailsRequested() const { return m_details_level > 0 && m_details_level < 5; }
+ bool IsAddressSelected() const { return m_details_level == 2 || m_details_level == 4; }
+ bool IsVersionSelected() const { return m_details_level == 3 || m_details_level == 4; }
+ enum struct NetType {
+ ipv4,
+ ipv6,
+ onion,
+ };
+ struct Peer {
+ int id;
+ int mapped_as;
+ int version;
+ int64_t conn_time;
+ int64_t last_blck;
+ int64_t last_recv;
+ int64_t last_send;
+ int64_t last_trxn;
+ double min_ping;
+ double ping;
+ std::string addr;
+ std::string sub_version;
+ NetType net_type;
+ bool is_block_relay;
+ bool is_outbound;
+ bool operator<(const Peer& rhs) const { return std::tie(is_outbound, min_ping) < std::tie(rhs.is_outbound, rhs.min_ping); }
+ };
+ std::string NetTypeEnumToString(NetType t)
+ {
+ switch (t) {
+ case NetType::ipv4: return "ipv4";
+ case NetType::ipv6: return "ipv6";
+ case NetType::onion: return "onion";
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+ }
+ std::string ChainToString() const
+ {
+ if (gArgs.GetChainName() == CBaseChainParams::TESTNET) return " testnet";
+ if (gArgs.GetChainName() == CBaseChainParams::REGTEST) return " regtest";
+ return "";
+ }
+public:
+ const int ID_PEERINFO = 0;
+ const int ID_NETWORKINFO = 1;
+
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ if (!args.empty()) {
+ uint8_t n{0};
+ if (ParseUInt8(args.at(0), &n)) {
+ m_details_level = n;
+ }
+ }
+ UniValue result(UniValue::VARR);
+ result.push_back(JSONRPCRequestObj("getpeerinfo", NullUniValue, ID_PEERINFO));
+ result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
+ return result;
+ }
+
+ UniValue ProcessReply(const UniValue& batch_in) override
+ {
+ const std::vector<UniValue> batch{JSONRPCProcessBatchReply(batch_in)};
+ if (!batch[ID_PEERINFO]["error"].isNull()) return batch[ID_PEERINFO];
+ if (!batch[ID_NETWORKINFO]["error"].isNull()) return batch[ID_NETWORKINFO];
+
+ const UniValue& networkinfo{batch[ID_NETWORKINFO]["result"]};
+ if (networkinfo["version"].get_int() < 209900) {
+ throw std::runtime_error("-netinfo requires bitcoind server to be running v0.21.0 and up");
+ }
+
+ // Count peer connection totals, and if DetailsRequested(), store peer data in a vector of structs.
+ const int64_t time_now{GetSystemTimeInSeconds()};
+ int ipv4_i{0}, ipv6_i{0}, onion_i{0}, block_relay_i{0}, total_i{0}; // inbound conn counters
+ int ipv4_o{0}, ipv6_o{0}, onion_o{0}, block_relay_o{0}, total_o{0}; // outbound conn counters
+ size_t max_peer_id_length{2}, max_addr_length{0};
+ bool is_asmap_on{false};
+ std::vector<Peer> peers;
+ const UniValue& getpeerinfo{batch[ID_PEERINFO]["result"]};
+
+ for (const UniValue& peer : getpeerinfo.getValues()) {
+ const std::string addr{peer["addr"].get_str()};
+ const std::string addr_local{peer["addrlocal"].isNull() ? "" : peer["addrlocal"].get_str()};
+ const int mapped_as{peer["mapped_as"].isNull() ? 0 : peer["mapped_as"].get_int()};
+ const bool is_block_relay{!peer["relaytxes"].get_bool()};
+ const bool is_inbound{peer["inbound"].get_bool()};
+ NetType net_type{NetType::ipv4};
+ if (is_inbound) {
+ if (IsAddrIPv6(addr)) {
+ net_type = NetType::ipv6;
+ ++ipv6_i;
+ } else if (IsInboundOnion(addr_local, mapped_as)) {
+ net_type = NetType::onion;
+ ++onion_i;
+ } else {
+ ++ipv4_i;
+ }
+ if (is_block_relay) ++block_relay_i;
+ } else {
+ if (IsAddrIPv6(addr)) {
+ net_type = NetType::ipv6;
+ ++ipv6_o;
+ } else if (IsOutboundOnion(addr, mapped_as)) {
+ net_type = NetType::onion;
+ ++onion_o;
+ } else {
+ ++ipv4_o;
+ }
+ if (is_block_relay) ++block_relay_o;
+ }
+ if (DetailsRequested()) {
+ // Push data for this peer to the peers vector.
+ const int peer_id{peer["id"].get_int()};
+ const int version{peer["version"].get_int()};
+ const std::string sub_version{peer["subver"].get_str()};
+ const int64_t conn_time{peer["conntime"].get_int64()};
+ const int64_t last_blck{peer["last_block"].get_int64()};
+ const int64_t last_recv{peer["lastrecv"].get_int64()};
+ const int64_t last_send{peer["lastsend"].get_int64()};
+ const int64_t last_trxn{peer["last_transaction"].get_int64()};
+ const double min_ping{peer["minping"].isNull() ? -1 : peer["minping"].get_real()};
+ const double ping{peer["pingtime"].isNull() ? -1 : peer["pingtime"].get_real()};
+ peers.push_back({peer_id, mapped_as, version, conn_time, last_blck, last_recv, last_send, last_trxn, min_ping, ping, addr, sub_version, net_type, is_block_relay, !is_inbound});
+ max_peer_id_length = std::max(ToString(peer_id).length(), max_peer_id_length);
+ max_addr_length = std::max(addr.length() + 1, max_addr_length);
+ is_asmap_on |= (mapped_as != 0);
+ }
+ }
+
+ // Generate report header.
+ std::string result{strprintf("%s %s%s - %i%s\n\n", PACKAGE_NAME, FormatFullVersion(), ChainToString(), networkinfo["protocolversion"].get_int(), networkinfo["subversion"].get_str())};
+
+ // Report detailed peer connections list sorted by direction and minimum ping time.
+ if (DetailsRequested() && !peers.empty()) {
+ std::sort(peers.begin(), peers.end());
+ result += "Peer connections sorted by direction and min ping\n<-> relay net mping ping send recv txn blk uptime ";
+ if (is_asmap_on) result += " asmap ";
+ result += strprintf("%*s %-*s%s\n", max_peer_id_length, "id", IsAddressSelected() ? max_addr_length : 0, IsAddressSelected() ? "address" : "", IsVersionSelected() ? "version" : "");
+ for (const Peer& peer : peers) {
+ std::string version{ToString(peer.version) + peer.sub_version};
+ result += strprintf(
+ "%3s %5s %5s%6s%7s%5s%5s%5s%5s%7s%*i %*s %-*s%s\n",
+ peer.is_outbound ? "out" : "in",
+ peer.is_block_relay ? "block" : "full",
+ NetTypeEnumToString(peer.net_type),
+ peer.min_ping == -1 ? "" : ToString(round(1000 * peer.min_ping)),
+ peer.ping == -1 ? "" : ToString(round(1000 * peer.ping)),
+ peer.last_send == 0 ? "" : ToString(time_now - peer.last_send),
+ peer.last_recv == 0 ? "" : ToString(time_now - peer.last_recv),
+ peer.last_trxn == 0 ? "" : ToString((time_now - peer.last_trxn) / 60),
+ peer.last_blck == 0 ? "" : ToString((time_now - peer.last_blck) / 60),
+ peer.conn_time == 0 ? "" : ToString((time_now - peer.conn_time) / 60),
+ is_asmap_on ? 7 : 0, // variable spacing
+ is_asmap_on && peer.mapped_as != 0 ? ToString(peer.mapped_as) : "",
+ max_peer_id_length, // variable spacing
+ peer.id,
+ IsAddressSelected() ? max_addr_length : 0, // variable spacing
+ IsAddressSelected() ? peer.addr : "",
+ IsVersionSelected() && version != "0" ? version : "");
+ }
+ result += " ms ms sec sec min min min\n\n";
+ }
+
+ // Report peer connection totals by type.
+ total_i = ipv4_i + ipv6_i + onion_i;
+ total_o = ipv4_o + ipv6_o + onion_o;
+ result += " ipv4 ipv6 onion total block-relay\n";
+ result += strprintf("in %5i %5i %5i %5i %5i\n", ipv4_i, ipv6_i, onion_i, total_i, block_relay_i);
+ result += strprintf("out %5i %5i %5i %5i %5i\n", ipv4_o, ipv6_o, onion_o, total_o, block_relay_o);
+ result += strprintf("total %5i %5i %5i %5i %5i\n", ipv4_i + ipv4_o, ipv6_i + ipv6_o, onion_i + onion_o, total_i + total_o, block_relay_i + block_relay_o);
+
+ // Report local addresses, ports, and scores.
+ result += "\nLocal addresses";
+ const UniValue& local_addrs{networkinfo["localaddresses"]};
+ if (local_addrs.empty()) {
+ result += ": n/a\n";
+ } else {
+ for (const UniValue& addr : local_addrs.getValues()) {
+ result += strprintf("\n%-40i port %5i score %6i", addr["address"].get_str(), addr["port"].get_int(), addr["score"].get_int());
+ }
+ }
+
+ return JSONRPCReplyObj(UniValue{result}, NullUniValue, 1);
+ }
+};
+
/** Process RPC generatetoaddress request. */
class GenerateToAddressRequestHandler : public BaseRequestHandler
{
@@ -618,6 +833,8 @@ static int CommandLineRPC(int argc, char *argv[])
std::string method;
if (gArgs.IsArgSet("-getinfo")) {
rh.reset(new GetinfoRequestHandler());
+ } else if (gArgs.GetBoolArg("-netinfo", false)) {
+ rh.reset(new NetinfoRequestHandler());
} else if (gArgs.GetBoolArg("-generate", false)) {
const UniValue getnewaddress{GetNewAddress()};
const UniValue& error{find_value(getnewaddress, "error")};
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index ffd2076c9a..d7f7888ef3 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -7,6 +7,7 @@
#include <chainparamsseeds.h>
#include <consensus/merkle.h>
+#include <hash.h> // for signet block challenge hash
#include <tinyformat.h>
#include <util/system.h>
#include <util/strencodings.h>
@@ -63,6 +64,8 @@ class CMainParams : public CChainParams {
public:
CMainParams() {
strNetworkID = CBaseChainParams::MAIN;
+ consensus.signet_blocks = false;
+ consensus.signet_challenge.clear();
consensus.nSubsidyHalvingInterval = 210000;
consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
consensus.BIP34Height = 227931;
@@ -172,6 +175,8 @@ class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
strNetworkID = CBaseChainParams::TESTNET;
+ consensus.signet_blocks = false;
+ consensus.signet_challenge.clear();
consensus.nSubsidyHalvingInterval = 210000;
consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
consensus.BIP34Height = 21111;
@@ -251,12 +256,103 @@ public:
};
/**
+ * Signet
+ */
+class SigNetParams : public CChainParams {
+public:
+ explicit SigNetParams(const ArgsManager& args) {
+ std::vector<uint8_t> bin;
+ vSeeds.clear();
+
+ if (!args.IsArgSet("-signetchallenge")) {
+ LogPrintf("Using default signet network\n");
+ bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
+ vSeeds.emplace_back("178.128.221.177");
+ vSeeds.emplace_back("2a01:7c8:d005:390::5");
+ vSeeds.emplace_back("ntv3mtqw5wt63red.onion:38333");
+ } else {
+ const auto signet_challenge = args.GetArgs("-signetchallenge");
+ if (signet_challenge.size() != 1) {
+ throw std::runtime_error(strprintf("%s: -signetchallenge cannot be multiple values.", __func__));
+ }
+ bin = ParseHex(signet_challenge[0]);
+
+ LogPrintf("Signet with challenge %s\n", signet_challenge[0]);
+ }
+
+ if (args.IsArgSet("-signetseednode")) {
+ vSeeds = args.GetArgs("-signetseednode");
+ }
+
+ strNetworkID = CBaseChainParams::SIGNET;
+ consensus.signet_blocks = true;
+ consensus.signet_challenge.assign(bin.begin(), bin.end());
+ consensus.nSubsidyHalvingInterval = 210000;
+ consensus.BIP34Height = 1;
+ consensus.BIP65Height = 1;
+ consensus.BIP66Height = 1;
+ consensus.CSVHeight = 1;
+ consensus.SegwitHeight = 1;
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
+ consensus.fPowAllowMinDifficultyBlocks = false;
+ consensus.fPowNoRetargeting = false;
+ consensus.nRuleChangeActivationThreshold = 1916;
+ consensus.nMinerConfirmationWindow = 2016;
+ consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
+
+ // message start is defined as the first 4 bytes of the sha256d of the block script
+ CHashWriter h(SER_DISK, 0);
+ h << consensus.signet_challenge;
+ uint256 hash = h.GetHash();
+ memcpy(pchMessageStart, hash.begin(), 4);
+ LogPrintf("Signet derived magic (message start): %s\n", HexStr({pchMessageStart, pchMessageStart + 4}));
+
+ nDefaultPort = 38333;
+ nPruneAfterHeight = 1000;
+ m_assumed_blockchain_size = 0;
+ m_assumed_chain_state_size = 0;
+
+ genesis = CreateGenesisBlock(1598918400, 52613770, 0x1e0377ae, 1, 50 * COIN);
+ consensus.hashGenesisBlock = genesis.GetHash();
+ assert(consensus.hashGenesisBlock == uint256S("0x00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+
+ vFixedSeeds.clear();
+
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
+ base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
+ base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
+
+ bech32_hrp = "tb";
+
+ fDefaultConsistencyChecks = false;
+ fRequireStandard = true;
+ m_is_test_chain = true;
+ m_is_mockable_chain = false;
+
+ chainTxData = ChainTxData{
+ 0,
+ 0,
+ 0
+ };
+ }
+};
+
+/**
* Regression test
*/
class CRegTestParams : public CChainParams {
public:
explicit CRegTestParams(const ArgsManager& args) {
strNetworkID = CBaseChainParams::REGTEST;
+ consensus.signet_blocks = false;
+ consensus.signet_challenge.clear();
consensus.nSubsidyHalvingInterval = 150;
consensus.BIP16Exception = uint256();
consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests)
@@ -391,12 +487,15 @@ const CChainParams &Params() {
std::unique_ptr<const CChainParams> CreateChainParams(const std::string& chain)
{
- if (chain == CBaseChainParams::MAIN)
+ if (chain == CBaseChainParams::MAIN) {
return std::unique_ptr<CChainParams>(new CMainParams());
- else if (chain == CBaseChainParams::TESTNET)
+ } else if (chain == CBaseChainParams::TESTNET) {
return std::unique_ptr<CChainParams>(new CTestNetParams());
- else if (chain == CBaseChainParams::REGTEST)
+ } else if (chain == CBaseChainParams::SIGNET) {
+ return std::unique_ptr<CChainParams>(new SigNetParams(gArgs));
+ } else if (chain == CBaseChainParams::REGTEST) {
return std::unique_ptr<CChainParams>(new CRegTestParams(gArgs));
+ }
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
diff --git a/src/chainparams.h b/src/chainparams.h
index 542ef329da..7aa999fb75 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -23,6 +23,11 @@ typedef std::map<int, uint256> MapCheckpoints;
struct CCheckpointData {
MapCheckpoints mapCheckpoints;
+
+ int GetHeight() const {
+ const auto& final_checkpoint = mapCheckpoints.rbegin();
+ return final_checkpoint->first /* height */;
+ }
};
/**
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 1825ced640..034e897ca6 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -13,6 +13,7 @@
const std::string CBaseChainParams::MAIN = "main";
const std::string CBaseChainParams::TESTNET = "test";
+const std::string CBaseChainParams::SIGNET = "signet";
const std::string CBaseChainParams::REGTEST = "regtest";
void SetupChainParamsBaseOptions(ArgsManager& argsman)
@@ -23,6 +24,9 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
argsman.AddArg("-segwitheight=<n>", "Set the activation height of segwit. -1 to disable. (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
+ argsman.AddArg("-signet", "Use the signet chain. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
+ argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_STRING, OptionsCategory::CHAINPARAMS);
+ argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_STRING, OptionsCategory::CHAINPARAMS);
}
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
@@ -35,14 +39,16 @@ const CBaseChainParams& BaseParams()
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
{
- if (chain == CBaseChainParams::MAIN)
+ if (chain == CBaseChainParams::MAIN) {
return MakeUnique<CBaseChainParams>("", 8332);
- else if (chain == CBaseChainParams::TESTNET)
+ } else if (chain == CBaseChainParams::TESTNET) {
return MakeUnique<CBaseChainParams>("testnet3", 18332);
- else if (chain == CBaseChainParams::REGTEST)
+ } else if (chain == CBaseChainParams::SIGNET) {
+ return MakeUnique<CBaseChainParams>("signet", 38332);
+ } else if (chain == CBaseChainParams::REGTEST) {
return MakeUnique<CBaseChainParams>("regtest", 18443);
- else
- throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
+ }
+ throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
void SelectBaseParams(const std::string& chain)
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index 1c52d0ea97..9852446b3c 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -21,6 +21,7 @@ public:
/** Chain name strings */
static const std::string MAIN;
static const std::string TESTNET;
+ static const std::string SIGNET;
static const std::string REGTEST;
///@}
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 61b1fbc2e5..85ab3f61ef 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -80,6 +80,13 @@ struct Params {
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
uint256 nMinimumChainWork;
uint256 defaultAssumeValid;
+
+ /**
+ * If true, witness commitments contain a payload equal to a Bitcoin Script solution
+ * to the signet challenge. See BIP325.
+ */
+ bool signet_blocks{false};
+ std::vector<uint8_t> signet_challenge;
};
} // namespace Consensus
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 2a93a090d6..e007c481df 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -12,6 +12,12 @@
#include <primitives/transaction.h>
#include <primitives/block.h>
+/** Index marker for when no witness commitment is present in a coinbase transaction. */
+static constexpr int NO_WITNESS_COMMITMENT{-1};
+
+/** Minimum size of a witness commitment structure. Defined in BIP 141. **/
+static constexpr size_t MINIMUM_WITNESS_COMMITMENT{38};
+
/** A "reason" why a transaction was invalid, suitable for determining whether the
* provider of the transaction should be banned/ignored/disconnected/etc.
*/
@@ -151,4 +157,25 @@ static inline int64_t GetTransactionInputWeight(const CTxIn& txin)
return ::GetSerializeSize(txin, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(txin, PROTOCOL_VERSION) + ::GetSerializeSize(txin.scriptWitness.stack, PROTOCOL_VERSION);
}
+/** Compute at which vout of the block's coinbase transaction the witness commitment occurs, or -1 if not found */
+inline int GetWitnessCommitmentIndex(const CBlock& block)
+{
+ int commitpos = NO_WITNESS_COMMITMENT;
+ if (!block.vtx.empty()) {
+ for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
+ const CTxOut& vout = block.vtx[0]->vout[o];
+ if (vout.scriptPubKey.size() >= MINIMUM_WITNESS_COMMITMENT &&
+ vout.scriptPubKey[0] == OP_RETURN &&
+ vout.scriptPubKey[1] == 0x24 &&
+ vout.scriptPubKey[2] == 0xaa &&
+ vout.scriptPubKey[3] == 0x21 &&
+ vout.scriptPubKey[4] == 0xa9 &&
+ vout.scriptPubKey[5] == 0xed) {
+ commitpos = o;
+ }
+ }
+ }
+ return commitpos;
+}
+
#endif // BITCOIN_CONSENSUS_VALIDATION_H
diff --git a/src/core_write.cpp b/src/core_write.cpp
index f9d918cb6d..3980d8cb2e 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -111,8 +111,9 @@ std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDeco
// checks in CheckSignatureEncoding.
if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, nullptr)) {
const unsigned char chSigHashType = vch.back();
- if (mapSigHashTypes.count(chSigHashType)) {
- strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]";
+ const auto it = mapSigHashTypes.find(chSigHashType);
+ if (it != mapSigHashTypes.end()) {
+ strSigHashDecode = "[" + it->second + "]";
vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode.
}
}
diff --git a/src/crypto/sha3.cpp b/src/crypto/sha3.cpp
new file mode 100644
index 0000000000..9c0c42fa77
--- /dev/null
+++ b/src/crypto/sha3.cpp
@@ -0,0 +1,161 @@
+// 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.
+
+// Based on https://github.com/mjosaarinen/tiny_sha3/blob/master/sha3.c
+// by Markku-Juhani O. Saarinen <mjos@iki.fi>
+
+#include <crypto/sha3.h>
+#include <crypto/common.h>
+#include <span.h>
+
+#include <algorithm>
+#include <array> // For std::begin and std::end.
+
+#include <stdint.h>
+
+// Internal implementation code.
+namespace
+{
+uint64_t Rotl(uint64_t x, int n) { return (x << n) | (x >> (64 - n)); }
+} // namespace
+
+void KeccakF(uint64_t (&st)[25])
+{
+ static constexpr uint64_t RNDC[24] = {
+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000,
+ 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
+ 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
+ 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003,
+ 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
+ 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
+ };
+ static constexpr int ROUNDS = 24;
+
+ for (int round = 0; round < ROUNDS; ++round) {
+ uint64_t bc0, bc1, bc2, bc3, bc4, t;
+
+ // Theta
+ bc0 = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
+ bc1 = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
+ bc2 = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
+ bc3 = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
+ bc4 = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
+ t = bc4 ^ Rotl(bc1, 1); st[0] ^= t; st[5] ^= t; st[10] ^= t; st[15] ^= t; st[20] ^= t;
+ t = bc0 ^ Rotl(bc2, 1); st[1] ^= t; st[6] ^= t; st[11] ^= t; st[16] ^= t; st[21] ^= t;
+ t = bc1 ^ Rotl(bc3, 1); st[2] ^= t; st[7] ^= t; st[12] ^= t; st[17] ^= t; st[22] ^= t;
+ t = bc2 ^ Rotl(bc4, 1); st[3] ^= t; st[8] ^= t; st[13] ^= t; st[18] ^= t; st[23] ^= t;
+ t = bc3 ^ Rotl(bc0, 1); st[4] ^= t; st[9] ^= t; st[14] ^= t; st[19] ^= t; st[24] ^= t;
+
+ // Rho Pi
+ t = st[1];
+ bc0 = st[10]; st[10] = Rotl(t, 1); t = bc0;
+ bc0 = st[7]; st[7] = Rotl(t, 3); t = bc0;
+ bc0 = st[11]; st[11] = Rotl(t, 6); t = bc0;
+ bc0 = st[17]; st[17] = Rotl(t, 10); t = bc0;
+ bc0 = st[18]; st[18] = Rotl(t, 15); t = bc0;
+ bc0 = st[3]; st[3] = Rotl(t, 21); t = bc0;
+ bc0 = st[5]; st[5] = Rotl(t, 28); t = bc0;
+ bc0 = st[16]; st[16] = Rotl(t, 36); t = bc0;
+ bc0 = st[8]; st[8] = Rotl(t, 45); t = bc0;
+ bc0 = st[21]; st[21] = Rotl(t, 55); t = bc0;
+ bc0 = st[24]; st[24] = Rotl(t, 2); t = bc0;
+ bc0 = st[4]; st[4] = Rotl(t, 14); t = bc0;
+ bc0 = st[15]; st[15] = Rotl(t, 27); t = bc0;
+ bc0 = st[23]; st[23] = Rotl(t, 41); t = bc0;
+ bc0 = st[19]; st[19] = Rotl(t, 56); t = bc0;
+ bc0 = st[13]; st[13] = Rotl(t, 8); t = bc0;
+ bc0 = st[12]; st[12] = Rotl(t, 25); t = bc0;
+ bc0 = st[2]; st[2] = Rotl(t, 43); t = bc0;
+ bc0 = st[20]; st[20] = Rotl(t, 62); t = bc0;
+ bc0 = st[14]; st[14] = Rotl(t, 18); t = bc0;
+ bc0 = st[22]; st[22] = Rotl(t, 39); t = bc0;
+ bc0 = st[9]; st[9] = Rotl(t, 61); t = bc0;
+ bc0 = st[6]; st[6] = Rotl(t, 20); t = bc0;
+ st[1] = Rotl(t, 44);
+
+ // Chi Iota
+ bc0 = st[0]; bc1 = st[1]; bc2 = st[2]; bc3 = st[3]; bc4 = st[4];
+ st[0] = bc0 ^ (~bc1 & bc2) ^ RNDC[round];
+ st[1] = bc1 ^ (~bc2 & bc3);
+ st[2] = bc2 ^ (~bc3 & bc4);
+ st[3] = bc3 ^ (~bc4 & bc0);
+ st[4] = bc4 ^ (~bc0 & bc1);
+ bc0 = st[5]; bc1 = st[6]; bc2 = st[7]; bc3 = st[8]; bc4 = st[9];
+ st[5] = bc0 ^ (~bc1 & bc2);
+ st[6] = bc1 ^ (~bc2 & bc3);
+ st[7] = bc2 ^ (~bc3 & bc4);
+ st[8] = bc3 ^ (~bc4 & bc0);
+ st[9] = bc4 ^ (~bc0 & bc1);
+ bc0 = st[10]; bc1 = st[11]; bc2 = st[12]; bc3 = st[13]; bc4 = st[14];
+ st[10] = bc0 ^ (~bc1 & bc2);
+ st[11] = bc1 ^ (~bc2 & bc3);
+ st[12] = bc2 ^ (~bc3 & bc4);
+ st[13] = bc3 ^ (~bc4 & bc0);
+ st[14] = bc4 ^ (~bc0 & bc1);
+ bc0 = st[15]; bc1 = st[16]; bc2 = st[17]; bc3 = st[18]; bc4 = st[19];
+ st[15] = bc0 ^ (~bc1 & bc2);
+ st[16] = bc1 ^ (~bc2 & bc3);
+ st[17] = bc2 ^ (~bc3 & bc4);
+ st[18] = bc3 ^ (~bc4 & bc0);
+ st[19] = bc4 ^ (~bc0 & bc1);
+ bc0 = st[20]; bc1 = st[21]; bc2 = st[22]; bc3 = st[23]; bc4 = st[24];
+ st[20] = bc0 ^ (~bc1 & bc2);
+ st[21] = bc1 ^ (~bc2 & bc3);
+ st[22] = bc2 ^ (~bc3 & bc4);
+ st[23] = bc3 ^ (~bc4 & bc0);
+ st[24] = bc4 ^ (~bc0 & bc1);
+ }
+}
+
+SHA3_256& SHA3_256::Write(Span<const unsigned char> data)
+{
+ if (m_bufsize && m_bufsize + data.size() >= sizeof(m_buffer)) {
+ // Fill the buffer and process it.
+ std::copy(data.begin(), data.begin() + sizeof(m_buffer) - m_bufsize, m_buffer + m_bufsize);
+ data = data.subspan(sizeof(m_buffer) - m_bufsize);
+ m_state[m_pos++] ^= ReadLE64(m_buffer);
+ m_bufsize = 0;
+ if (m_pos == RATE_BUFFERS) {
+ KeccakF(m_state);
+ m_pos = 0;
+ }
+ }
+ while (data.size() >= sizeof(m_buffer)) {
+ // Process chunks directly from the buffer.
+ m_state[m_pos++] ^= ReadLE64(data.data());
+ data = data.subspan(8);
+ if (m_pos == RATE_BUFFERS) {
+ KeccakF(m_state);
+ m_pos = 0;
+ }
+ }
+ if (data.size()) {
+ // Keep the remainder in the buffer.
+ std::copy(data.begin(), data.end(), m_buffer + m_bufsize);
+ m_bufsize += data.size();
+ }
+ return *this;
+}
+
+SHA3_256& SHA3_256::Finalize(Span<unsigned char> output)
+{
+ assert(output.size() == OUTPUT_SIZE);
+ std::fill(m_buffer + m_bufsize, m_buffer + sizeof(m_buffer), 0);
+ m_buffer[m_bufsize] ^= 0x06;
+ m_state[m_pos] ^= ReadLE64(m_buffer);
+ m_state[RATE_BUFFERS - 1] ^= 0x8000000000000000;
+ KeccakF(m_state);
+ for (unsigned i = 0; i < 4; ++i) {
+ WriteLE64(output.data() + 8 * i, m_state[i]);
+ }
+ return *this;
+}
+
+SHA3_256& SHA3_256::Reset()
+{
+ m_bufsize = 0;
+ m_pos = 0;
+ std::fill(std::begin(m_state), std::end(m_state), 0);
+ return *this;
+}
diff --git a/src/crypto/sha3.h b/src/crypto/sha3.h
new file mode 100644
index 0000000000..88d8c1204d
--- /dev/null
+++ b/src/crypto/sha3.h
@@ -0,0 +1,41 @@
+// 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_CRYPTO_SHA3_H
+#define BITCOIN_CRYPTO_SHA3_H
+
+#include <span.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+
+//! The Keccak-f[1600] transform.
+void KeccakF(uint64_t (&st)[25]);
+
+class SHA3_256
+{
+private:
+ uint64_t m_state[25] = {0};
+ unsigned char m_buffer[8];
+ unsigned m_bufsize = 0;
+ unsigned m_pos = 0;
+
+ //! Sponge rate in bits.
+ static constexpr unsigned RATE_BITS = 1088;
+
+ //! Sponge rate expressed as a multiple of the buffer size.
+ static constexpr unsigned RATE_BUFFERS = RATE_BITS / (8 * sizeof(m_buffer));
+
+ static_assert(RATE_BITS % (8 * sizeof(m_buffer)) == 0, "Rate must be a multiple of 8 bytes");
+
+public:
+ static constexpr size_t OUTPUT_SIZE = 32;
+
+ SHA3_256() {}
+ SHA3_256& Write(Span<const unsigned char> data);
+ SHA3_256& Finalize(Span<unsigned char> output);
+ SHA3_256& Reset();
+};
+
+#endif // BITCOIN_CRYPTO_SHA3_H
diff --git a/src/crypto/siphash.cpp b/src/crypto/siphash.cpp
index e81957111a..2e0106b165 100644
--- a/src/crypto/siphash.cpp
+++ b/src/crypto/siphash.cpp
@@ -49,7 +49,7 @@ CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)
{
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
uint64_t t = tmp;
- int c = count;
+ uint8_t c = count;
while (size--) {
t |= ((uint64_t)(*(data++))) << (8 * (c % 8));
diff --git a/src/crypto/siphash.h b/src/crypto/siphash.h
index b312f913f9..6b38950f8e 100644
--- a/src/crypto/siphash.h
+++ b/src/crypto/siphash.h
@@ -15,7 +15,7 @@ class CSipHasher
private:
uint64_t v[4];
uint64_t tmp;
- int count;
+ uint8_t count; // Only the low 8 bits of the input size matter.
public:
/** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */
diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp
index e54c2daaeb..8d2dcd0279 100644
--- a/src/dummywallet.cpp
+++ b/src/dummywallet.cpp
@@ -46,7 +46,6 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const
"-walletdir=<dir>",
"-walletnotify=<cmd>",
"-walletrbf",
- "-zapwallettxes=<mode>",
"-dblogsize=<n>",
"-flushwallet",
"-privdb",
diff --git a/src/init.cpp b/src/init.cpp
index 4b689d6153..023aa9aba5 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -187,7 +187,7 @@ void Shutdown(NodeContext& node)
/// Be sure that anything that writes files or flushes caches only does this if the respective
/// module was initialized.
util::ThreadRename("shutoff");
- mempool.AddTransactionsUpdated(1);
+ if (node.mempool) node.mempool->AddTransactionsUpdated(1);
StopHTTPRPC();
StopREST();
@@ -200,7 +200,7 @@ void Shutdown(NodeContext& node)
// Because these depend on each-other, we make sure that neither can be
// using the other before destroying them.
- if (node.peer_logic) UnregisterValidationInterface(node.peer_logic.get());
+ if (node.peerman) UnregisterValidationInterface(node.peerman.get());
// Follow the lock order requirements:
// * CheckForStaleTipAndEvictPeers locks cs_main before indirectly calling GetExtraOutboundCount
// which locks cs_vNodes.
@@ -227,12 +227,12 @@ void Shutdown(NodeContext& node)
// After the threads that potentially access these pointers have been stopped,
// destruct and reset all to nullptr.
- node.peer_logic.reset();
+ node.peerman.reset();
node.connman.reset();
node.banman.reset();
- if (::mempool.IsLoaded() && node.args->GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
- DumpMempool(::mempool);
+ if (node.mempool && node.mempool->IsLoaded() && node.args->GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
+ DumpMempool(*node.mempool);
}
if (fFeeEstimatesInitialized)
@@ -302,7 +302,7 @@ void Shutdown(NodeContext& node)
GetMainSignals().UnregisterBackgroundSignalScheduler();
globalVerifyHandle.reset();
ECC_Stop();
- node.mempool = nullptr;
+ node.mempool.reset();
node.chainman = nullptr;
node.scheduler.reset();
@@ -507,7 +507,7 @@ void SetupServerArgs(NodeContext& node)
argsman.AddArg("-checklevel=<n>", strprintf("How thorough the block verification of -checkblocks is: %s (0-4, default: %u)", Join(CHECKLEVEL_DOC, ", "), DEFAULT_CHECKLEVEL), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-checkblockindex", strprintf("Do a consistency check for the block tree, chainstate, and other validation data structures occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
- argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block 295000 (default: %u)", DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
+ argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
@@ -738,10 +738,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp
return;
}
} // End scope of CImportingNow
- if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
- LoadMempool(::mempool);
- }
- ::mempool.SetIsLoaded(!ShutdownRequested());
+ chainman.ActiveChainstate().LoadMempool(args);
}
/** Sanity checks
@@ -1054,11 +1051,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
}
}
- // Checkmempool and checkblockindex default to true in regtest mode
- int ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
- if (ratio != 0) {
- mempool.setSanityCheck(1.0 / ratio);
- }
fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
@@ -1368,16 +1360,24 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman);
node.connman = MakeUnique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), args.GetBoolArg("-networkactive", true));
+
// Make mempool generally available in the node context. For example the connection manager, wallet, or RPC threads,
// which are all started after this, may use it from the node context.
assert(!node.mempool);
- node.mempool = &::mempool;
+ node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator);
+ if (node.mempool) {
+ int ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
+ if (ratio != 0) {
+ node.mempool->setSanityCheck(1.0 / ratio);
+ }
+ }
+
assert(!node.chainman);
node.chainman = &g_chainman;
ChainstateManager& chainman = *Assert(node.chainman);
- node.peer_logic.reset(new PeerLogicValidation(*node.connman, node.banman.get(), *node.scheduler, chainman, *node.mempool));
- RegisterValidationInterface(node.peer_logic.get());
+ node.peerman.reset(new PeerManager(chainparams, *node.connman, node.banman.get(), *node.scheduler, chainman, *node.mempool));
+ RegisterValidationInterface(node.peerman.get());
// sanitize comments per BIP-0014, format user agent and check total size
std::vector<std::string> uacomments;
@@ -1559,7 +1559,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
chainman.m_total_coinstip_cache = nCoinCacheUsage;
chainman.m_total_coinsdb_cache = nCoinDBCache;
- UnloadBlockIndex(node.mempool);
+ UnloadBlockIndex(node.mempool.get());
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
@@ -1833,20 +1833,15 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
#if HAVE_SYSTEM
- if (args.IsArgSet("-blocknotify")) {
- const std::string block_notify = args.GetArg("-blocknotify", "");
- const auto BlockNotifyCallback = [block_notify](SynchronizationState sync_state, const CBlockIndex* pBlockIndex) {
- if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex)
- return;
-
- std::string strCmd = block_notify;
- if (!strCmd.empty()) {
- boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
- std::thread t(runCommand, strCmd);
- t.detach(); // thread runs free
- }
- };
- uiInterface.NotifyBlockTip_connect(BlockNotifyCallback);
+ const std::string block_notify = args.GetArg("-blocknotify", "");
+ if (!block_notify.empty()) {
+ uiInterface.NotifyBlockTip_connect([block_notify](SynchronizationState sync_state, const CBlockIndex* pBlockIndex) {
+ if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex) return;
+ std::string command = block_notify;
+ boost::replace_all(command, "%s", pBlockIndex->GetBlockHash().GetHex());
+ std::thread t(runCommand, command);
+ t.detach(); // thread runs free
+ });
}
#endif
@@ -1916,7 +1911,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
connOptions.nBestHeight = chain_active_height;
connOptions.uiInterface = &uiInterface;
connOptions.m_banman = node.banman.get();
- connOptions.m_msgproc = node.peer_logic.get();
+ connOptions.m_msgproc = node.peerman.get();
connOptions.nSendBufferMaxSize = 1000 * args.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
connOptions.nReceiveFloodSize = 1000 * args.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
connOptions.m_added_nodes = args.GetArgs("-addnode");
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index 313c1265de..13d885a20d 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -276,13 +276,15 @@ public:
}
RBFTransactionState isRBFOptIn(const CTransaction& tx) override
{
- LOCK(::mempool.cs);
- return IsRBFOptIn(tx, ::mempool);
+ if (!m_node.mempool) return IsRBFOptInEmptyMempool(tx);
+ LOCK(m_node.mempool->cs);
+ return IsRBFOptIn(tx, *m_node.mempool);
}
bool hasDescendantsInMempool(const uint256& txid) override
{
- LOCK(::mempool.cs);
- auto it = ::mempool.GetIter(txid);
+ if (!m_node.mempool) return false;
+ LOCK(m_node.mempool->cs);
+ auto it = m_node.mempool->GetIter(txid);
return it && (*it)->GetCountWithDescendants() > 1;
}
bool broadcastTransaction(const CTransactionRef& tx,
@@ -298,7 +300,9 @@ public:
}
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override
{
- ::mempool.GetTransactionAncestry(txid, ancestors, descendants);
+ ancestors = descendants = 0;
+ if (!m_node.mempool) return;
+ m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants);
}
void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
{
@@ -307,6 +311,7 @@ public:
}
bool checkChainLimits(const CTransactionRef& tx) override
{
+ if (!m_node.mempool) return true;
LockPoints lp;
CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
CTxMemPool::setEntries ancestors;
@@ -315,8 +320,9 @@ public:
auto limit_descendant_count = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
auto limit_descendant_size = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000;
std::string unused_error_string;
- LOCK(::mempool.cs);
- return ::mempool.CalculateMemPoolAncestors(entry, ancestors, limit_ancestor_count, limit_ancestor_size,
+ LOCK(m_node.mempool->cs);
+ return m_node.mempool->CalculateMemPoolAncestors(
+ entry, ancestors, limit_ancestor_count, limit_ancestor_size,
limit_descendant_count, limit_descendant_size, unused_error_string);
}
CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
@@ -329,7 +335,8 @@ public:
}
CFeeRate mempoolMinFee() override
{
- return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
+ if (!m_node.mempool) return {};
+ return m_node.mempool->GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
}
CFeeRate relayMinFee() override { return ::minRelayTxFee; }
CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
@@ -395,8 +402,9 @@ public:
}
void requestMempoolTransactions(Notifications& notifications) override
{
- LOCK2(::cs_main, ::mempool.cs);
- for (const CTxMemPoolEntry& entry : ::mempool.mapTx) {
+ if (!m_node.mempool) return;
+ LOCK2(::cs_main, m_node.mempool->cs);
+ for (const CTxMemPoolEntry& entry : m_node.mempool->mapTx) {
notifications.transactionAddedToMempool(entry.GetSharedTx());
}
}
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 63c109658e..94c63da84e 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -446,7 +446,7 @@ public:
CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
void remove() override
{
- RemoveWallet(m_wallet);
+ RemoveWallet(m_wallet, false /* load_on_start */);
}
bool isLegacy() override { return m_wallet->IsLegacy(); }
std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
@@ -488,8 +488,7 @@ public:
class WalletClientImpl : public WalletClient
{
public:
- WalletClientImpl(Chain& chain, ArgsManager& args, std::vector<std::string> wallet_filenames)
- : m_wallet_filenames(std::move(wallet_filenames))
+ WalletClientImpl(Chain& chain, ArgsManager& args)
{
m_context.chain = &chain;
m_context.args = &args;
@@ -506,23 +505,30 @@ public:
m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back()));
}
}
- bool verify() override { return VerifyWallets(*m_context.chain, m_wallet_filenames); }
- bool load() override { return LoadWallets(*m_context.chain, m_wallet_filenames); }
+ bool verify() override { return VerifyWallets(*m_context.chain); }
+ bool load() override { return LoadWallets(*m_context.chain); }
void start(CScheduler& scheduler) override { return StartWallets(scheduler, *Assert(m_context.args)); }
void flush() override { return FlushWallets(); }
void stop() override { return StopWallets(); }
void setMockTime(int64_t time) override { return SetMockTime(time); }
//! WalletClient methods
- std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, WalletCreationStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) override
+ std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
std::shared_ptr<CWallet> wallet;
- status = CreateWallet(*m_context.chain, passphrase, wallet_creation_flags, name, error, warnings, wallet);
- return MakeWallet(std::move(wallet));
+ DatabaseOptions options;
+ DatabaseStatus status;
+ options.require_create = true;
+ options.create_flags = wallet_creation_flags;
+ options.create_passphrase = passphrase;
+ return MakeWallet(CreateWallet(*m_context.chain, name, true /* load_on_start */, options, status, error, warnings));
}
std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
- return MakeWallet(LoadWallet(*m_context.chain, WalletLocation(name), error, warnings));
+ DatabaseOptions options;
+ DatabaseStatus status;
+ options.require_existing = true;
+ return MakeWallet(LoadWallet(*m_context.chain, name, true /* load_on_start */, options, status, error, warnings));
}
std::string getWalletDir() override
{
@@ -559,9 +565,9 @@ public:
std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; }
-std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args, std::vector<std::string> wallet_filenames)
+std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args)
{
- return MakeUnique<WalletClientImpl>(chain, args, std::move(wallet_filenames));
+ return MakeUnique<WalletClientImpl>(chain, args);
}
} // namespace interfaces
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 186f5d81a5..6ccfd7fc20 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -29,7 +29,6 @@ class CWallet;
enum class FeeReason;
enum class OutputType;
enum class TransactionError;
-enum class WalletCreationStatus;
enum isminetype : unsigned int;
struct CRecipient;
struct PartiallySignedTransaction;
@@ -311,7 +310,7 @@ class WalletClient : public ChainClient
{
public:
//! Create new wallet.
- virtual std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, WalletCreationStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
+ virtual std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
//! Load existing wallet.
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
@@ -412,7 +411,7 @@ std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet);
//! Return implementation of ChainClient interface for a wallet client. This
//! function will be undefined in builds where ENABLE_WALLET is false.
-std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args, std::vector<std::string> wallet_filenames);
+std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args);
} // namespace interfaces
diff --git a/src/miner.h b/src/miner.h
index 096585dfe4..bb7a30b184 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -84,7 +84,7 @@ struct CompareTxIterByAncestorCount {
{
if (a->GetCountWithAncestors() != b->GetCountWithAncestors())
return a->GetCountWithAncestors() < b->GetCountWithAncestors();
- return CTxMemPool::CompareIteratorByHash()(a, b);
+ return CompareIteratorByHash()(a, b);
}
};
diff --git a/src/net.cpp b/src/net.cpp
index 883e57bdf0..e7d3a146ff 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -94,6 +94,7 @@ const std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
+static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8]
//
// Global state variables
//
@@ -621,32 +622,6 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
return true;
}
-void CNode::SetSendVersion(int nVersionIn)
-{
- // Send version may only be changed in the version message, and
- // only one version message is allowed per session. We can therefore
- // treat this value as const and even atomic as long as it's only used
- // once a version message has been successfully processed. Any attempt to
- // set this twice is an error.
- if (nSendVersion != 0) {
- error("Send version already set for node: %i. Refusing to change from %i to %i", id, nSendVersion, nVersionIn);
- } else {
- nSendVersion = nVersionIn;
- }
-}
-
-int CNode::GetSendVersion() const
-{
- // The send version should always be explicitly set to
- // INIT_PROTO_VERSION rather than using this value until SetSendVersion
- // has been called.
- if (nSendVersion == 0) {
- error("Requesting unset send version for node: %i. Using %i", id, INIT_PROTO_VERSION);
- return INIT_PROTO_VERSION;
- }
- return nSendVersion;
-}
-
int V1TransportDeserializer::readHeader(const char *pch, unsigned int nBytes)
{
// copy data to temporary parsing buffer
@@ -816,6 +791,7 @@ struct NodeEvictionCandidate
CAddress addr;
uint64_t nKeyedNetGroup;
bool prefer_evict;
+ bool m_is_local;
};
static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
@@ -828,6 +804,12 @@ static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, cons
return a.nTimeConnected > b.nTimeConnected;
}
+static bool CompareLocalHostTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
+{
+ if (a.m_is_local != b.m_is_local) return b.m_is_local;
+ return a.nTimeConnected > b.nTimeConnected;
+}
+
static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) {
return a.nKeyedNetGroup < b.nKeyedNetGroup;
}
@@ -849,6 +831,14 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction
return a.nTimeConnected > b.nTimeConnected;
}
+// Pick out the potential block-relay only peers, and sort them by last block time.
+static bool CompareNodeBlockRelayOnlyTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
+{
+ if (a.fRelayTxes != b.fRelayTxes) return a.fRelayTxes;
+ if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime;
+ if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;
+ return a.nTimeConnected > b.nTimeConnected;
+}
//! Sort an array by the specified comparator, then erase the last K elements.
template<typename T, typename Comparator>
@@ -891,7 +881,7 @@ bool CConnman::AttemptToEvictConnection()
node->nLastBlockTime, node->nLastTXTime,
HasAllDesirableServiceFlags(node->nServices),
peer_relay_txes, peer_filter_not_null, node->addr, node->nKeyedNetGroup,
- node->m_prefer_evict};
+ node->m_prefer_evict, node->addr.IsLocal()};
vEvictionCandidates.push_back(candidate);
}
}
@@ -904,15 +894,34 @@ bool CConnman::AttemptToEvictConnection()
// Protect the 8 nodes with the lowest minimum ping time.
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8);
- // Protect 4 nodes that most recently sent us transactions.
+ // Protect 4 nodes that most recently sent us novel transactions accepted into our mempool.
// An attacker cannot manipulate this metric without performing useful work.
EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
- // Protect 4 nodes that most recently sent us blocks.
+ // 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());
+
+ // 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.
- EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size() / 2);
+ // 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);
if (vEvictionCandidates.empty()) return false;
@@ -1159,7 +1168,7 @@ void CConnman::InactivityCheck(CNode *pnode)
LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
pnode->fDisconnect = true;
}
- else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
+ else if (nTime - pnode->nLastRecv > (pnode->GetCommonVersion() > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
{
LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
pnode->fDisconnect = true;
@@ -1843,41 +1852,45 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// but inbound and manual peers do not use our outbound slots. Inbound peers
// also have the added issue that they could be attacker controlled and used
// to prevent us from connecting to particular hosts if we used them here.
- switch(pnode->m_conn_type){
+ switch (pnode->m_conn_type) {
case ConnectionType::INBOUND:
case ConnectionType::MANUAL:
break;
- case ConnectionType::OUTBOUND:
+ case ConnectionType::OUTBOUND_FULL_RELAY:
case ConnectionType::BLOCK_RELAY:
case ConnectionType::ADDR_FETCH:
case ConnectionType::FEELER:
setConnected.insert(pnode->addr.GetGroup(addrman.m_asmap));
- }
+ } // no default case, so the compiler can warn about missing cases
}
}
- // Feeler Connections
- //
- // Design goals:
- // * Increase the number of connectable addresses in the tried table.
- //
- // Method:
- // * Choose a random address from new and attempt to connect to it if we can connect
- // successfully it is added to tried.
- // * Start attempting feeler connections only after node finishes making outbound
- // connections.
- // * Only make a feeler connection once every few minutes.
- //
+ ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
+ int64_t nTime = GetTimeMicros();
bool fFeeler = false;
- if (nOutboundFullRelay >= m_max_outbound_full_relay && nOutboundBlockRelay >= m_max_outbound_block_relay && !GetTryNewOutboundPeer()) {
- int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
- if (nTime > nNextFeeler) {
- nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
- fFeeler = true;
- } else {
- continue;
- }
+ // Determine what type of connection to open. Opening
+ // OUTBOUND_FULL_RELAY connections gets the highest priority until we
+ // meet our full-relay capacity. Then we open BLOCK_RELAY connection
+ // until we hit our block-relay-only peer limit.
+ // GetTryNewOutboundPeer() gets set when a stale tip is detected, so we
+ // try opening an additional OUTBOUND_FULL_RELAY connection. If none of
+ // these conditions are met, check the nNextFeeler timer to decide if
+ // we should open a FEELER.
+
+ if (nOutboundFullRelay < m_max_outbound_full_relay) {
+ // OUTBOUND_FULL_RELAY
+ } else if (nOutboundBlockRelay < m_max_outbound_block_relay) {
+ conn_type = ConnectionType::BLOCK_RELAY;
+ } else if (GetTryNewOutboundPeer()) {
+ // OUTBOUND_FULL_RELAY
+ } else if (nTime > nNextFeeler) {
+ nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
+ conn_type = ConnectionType::FEELER;
+ fFeeler = true;
+ } else {
+ // skip to next iteration of while loop
+ continue;
}
addrman.ResolveCollisions();
@@ -1944,23 +1957,6 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
}
- ConnectionType conn_type;
- // Determine what type of connection to open. If fFeeler is not
- // set, open OUTBOUND connections until we meet our full-relay
- // capacity. Then open BLOCK_RELAY connections until we hit our
- // block-relay peer limit. Otherwise, default to opening an
- // OUTBOUND connection.
- if (fFeeler) {
- conn_type = ConnectionType::FEELER;
- } else if (nOutboundFullRelay < m_max_outbound_full_relay) {
- conn_type = ConnectionType::OUTBOUND;
- } else if (nOutboundBlockRelay < m_max_outbound_block_relay) {
- conn_type = ConnectionType::BLOCK_RELAY;
- } else {
- // GetTryNewOutboundPeer() is true
- conn_type = ConnectionType::OUTBOUND;
- }
-
OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, conn_type);
}
}
@@ -2539,15 +2535,47 @@ std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pc
return addresses;
}
-std::vector<CAddress> CConnman::GetAddresses(Network requestor_network, size_t max_addresses, size_t max_pct)
+std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
{
+ SOCKET socket;
+ WITH_LOCK(requestor.cs_hSocket, socket = requestor.hSocket);
+ auto local_socket_bytes = GetBindAddress(socket).GetAddrBytes();
+ uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
+ .Write(requestor.addr.GetNetwork())
+ .Write(local_socket_bytes.data(), local_socket_bytes.size())
+ .Finalize();
const auto current_time = GetTime<std::chrono::microseconds>();
- if (m_addr_response_caches.find(requestor_network) == m_addr_response_caches.end() ||
- m_addr_response_caches[requestor_network].m_update_addr_response < current_time) {
- m_addr_response_caches[requestor_network].m_addrs_response_cache = GetAddresses(max_addresses, max_pct);
- m_addr_response_caches[requestor_network].m_update_addr_response = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6));
+ auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{});
+ CachedAddrResponse& cache_entry = r.first->second;
+ if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0.
+ cache_entry.m_addrs_response_cache = GetAddresses(max_addresses, max_pct);
+ // Choosing a proper cache lifetime is a trade-off between the privacy leak minimization
+ // and the usefulness of ADDR responses to honest users.
+ //
+ // Longer cache lifetime makes it more difficult for an attacker to scrape
+ // enough AddrMan data to maliciously infer something useful.
+ // By the time an attacker scraped enough AddrMan records, most of
+ // the records should be old enough to not leak topology info by
+ // e.g. analyzing real-time changes in timestamps.
+ //
+ // It takes only several hundred requests to scrape everything from an AddrMan containing 100,000 nodes,
+ // so ~24 hours of cache lifetime indeed makes the data less inferable by the time
+ // most of it could be scraped (considering that timestamps are updated via
+ // ADDR self-announcements and when nodes communicate).
+ // We also should be robust to those attacks which may not require scraping *full* victim's AddrMan
+ // (because even several timestamps of the same handful of nodes may leak privacy).
+ //
+ // On the other hand, longer cache lifetime makes ADDR responses
+ // outdated and less useful for an honest requestor, e.g. if most nodes
+ // in the ADDR response are no longer active.
+ //
+ // However, the churn in the network is known to be rather low. Since we consider
+ // nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days,
+ // max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference
+ // in terms of the freshness of the response.
+ cache_entry.m_cache_entry_expiration = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6));
}
- return m_addr_response_caches[requestor_network].m_addrs_response_cache;
+ return cache_entry.m_addrs_response_cache;
}
bool CConnman::AddNode(const std::string& strNode)
@@ -2784,6 +2812,9 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
hashContinue = uint256();
if (conn_type_in != ConnectionType::BLOCK_RELAY) {
m_tx_relay = MakeUnique<TxRelay>();
+ }
+
+ if (RelayAddrsWithConn()) {
m_addr_known = MakeUnique<CRollingBloomFilter>(5000, 0.001);
}
diff --git a/src/net.h b/src/net.h
index c72eada3ff..0366fa0f5b 100644
--- a/src/net.h
+++ b/src/net.h
@@ -118,12 +118,54 @@ struct CSerializedNetMsg
* information we have available at the time of opening or accepting the
* connection. Aside from INBOUND, all types are initiated by us. */
enum class ConnectionType {
- INBOUND, /**< peer initiated connections */
- OUTBOUND, /**< full relay connections (blocks, addrs, txns) made automatically. Addresses selected from AddrMan. */
- MANUAL, /**< connections to addresses added via addnode or the connect command line argument */
- FEELER, /**< short lived connections used to test address validity */
- BLOCK_RELAY, /**< only relay blocks to these automatic outbound connections. Addresses selected from AddrMan. */
- ADDR_FETCH, /**< short lived connections used to solicit addrs when starting the node without a populated AddrMan */
+ /**
+ * Inbound connections are those initiated by a peer. This is the only
+ * property we know at the time of connection, until P2P messages are
+ * exchanged.
+ */
+ INBOUND,
+
+ /**
+ * These are the default connections that we use to connect with the
+ * network. There is no restriction on what is relayed- by default we relay
+ * blocks, addresses & transactions. We automatically attempt to open
+ * MAX_OUTBOUND_FULL_RELAY_CONNECTIONS using addresses from our AddrMan.
+ */
+ OUTBOUND_FULL_RELAY,
+
+
+ /**
+ * We open manual connections to addresses that users explicitly inputted
+ * via the addnode RPC, or the -connect command line argument. Even if a
+ * manual connection is misbehaving, we do not automatically disconnect or
+ * add it to our discouragement filter.
+ */
+ MANUAL,
+
+ /**
+ * Feeler connections are short lived connections used to increase the
+ * number of connectable addresses in our AddrMan. Approximately every
+ * FEELER_INTERVAL, we attempt to connect to a random address from the new
+ * table. If successful, we add it to the tried table.
+ */
+ FEELER,
+
+ /**
+ * We use block-relay-only connections to help prevent against partition
+ * attacks. By not relaying transactions or addresses, these connections
+ * are harder to detect by a third party, thus helping obfuscate the
+ * network topology. We automatically attempt to open
+ * MAX_BLOCK_RELAY_ONLY_CONNECTIONS using addresses from our AddrMan.
+ */
+ BLOCK_RELAY,
+
+ /**
+ * AddrFetch connections are short lived connections used to solicit
+ * addresses from peers. These are initiated to addresses submitted via the
+ * -seednode command line argument, or under certain conditions when the
+ * AddrMan is empty.
+ */
+ ADDR_FETCH,
};
class NetEventsInterface;
@@ -209,7 +251,7 @@ public:
bool GetNetworkActive() const { return fNetworkActive; };
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
void SetNetworkActive(bool active);
- void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, ConnectionType conn_type = ConnectionType::OUTBOUND);
+ void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type);
bool CheckIncomingNonce(uint64_t nonce);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@@ -269,7 +311,7 @@ public:
* A non-malicious call (from RPC or a peer with addr permission) should
* call the function without a parameter to avoid using the cache.
*/
- std::vector<CAddress> GetAddresses(Network requestor_network, size_t max_addresses, size_t max_pct);
+ std::vector<CAddress> GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct);
// This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
// a peer that is better than all our current peers.
@@ -442,20 +484,24 @@ private:
*/
struct CachedAddrResponse {
std::vector<CAddress> m_addrs_response_cache;
- std::chrono::microseconds m_update_addr_response{0};
+ std::chrono::microseconds m_cache_entry_expiration{0};
};
/**
* Addr responses stored in different caches
- * per network prevent cross-network node identification.
+ * per (network, local socket) prevent cross-network node identification.
* If a node for example is multi-homed under Tor and IPv6,
* a single cache (or no cache at all) would let an attacker
* to easily detect that it is the same node by comparing responses.
- * The used memory equals to 1000 CAddress records (or around 32 bytes) per
+ * Indexing by local socket prevents leakage when a node has multiple
+ * listening addresses on the same network.
+ *
+ * The used memory equals to 1000 CAddress records (or around 40 bytes) per
* distinct Network (up to 5) we have/had an inbound peer from,
- * resulting in at most ~160 KB.
+ * resulting in at most ~196 KB. Every separate local socket may
+ * add up to ~196 KB extra.
*/
- std::map<Network, CachedAddrResponse> m_addr_response_caches;
+ std::map<uint64_t, CachedAddrResponse> m_addr_response_caches;
/**
* Services this instance offers.
@@ -785,7 +831,6 @@ public:
std::deque<CInv> vRecvGetData;
uint64_t nRecvBytes GUARDED_BY(cs_vRecv){0};
- std::atomic<int> nRecvVersion{INIT_PROTO_VERSION};
std::atomic<int64_t> nLastSend{0};
std::atomic<int64_t> nLastRecv{0};
@@ -823,8 +868,8 @@ public:
std::atomic_bool fPauseSend{false};
bool IsOutboundOrBlockRelayConn() const {
- switch(m_conn_type) {
- case ConnectionType::OUTBOUND:
+ switch (m_conn_type) {
+ case ConnectionType::OUTBOUND_FULL_RELAY:
case ConnectionType::BLOCK_RELAY:
return true;
case ConnectionType::INBOUND:
@@ -832,13 +877,13 @@ public:
case ConnectionType::ADDR_FETCH:
case ConnectionType::FEELER:
return false;
- }
+ } // no default case, so the compiler can warn about missing cases
assert(false);
}
bool IsFullOutboundConn() const {
- return m_conn_type == ConnectionType::OUTBOUND;
+ return m_conn_type == ConnectionType::OUTBOUND_FULL_RELAY;
}
bool IsManualConn() const {
@@ -861,17 +906,23 @@ public:
return m_conn_type == ConnectionType::INBOUND;
}
+ /* Whether we send addr messages over this connection */
+ bool RelayAddrsWithConn() const
+ {
+ return m_conn_type != ConnectionType::BLOCK_RELAY;
+ }
+
bool ExpectServicesFromConn() const {
- switch(m_conn_type) {
+ switch (m_conn_type) {
case ConnectionType::INBOUND:
case ConnectionType::MANUAL:
case ConnectionType::FEELER:
return false;
- case ConnectionType::OUTBOUND:
+ case ConnectionType::OUTBOUND_FULL_RELAY:
case ConnectionType::BLOCK_RELAY:
case ConnectionType::ADDR_FETCH:
return true;
- }
+ } // no default case, so the compiler can warn about missing cases
assert(false);
}
@@ -886,13 +937,11 @@ public:
// flood relay
std::vector<CAddress> vAddrToSend;
- std::unique_ptr<CRollingBloomFilter> m_addr_known = nullptr;
+ std::unique_ptr<CRollingBloomFilter> m_addr_known{nullptr};
bool fGetAddr{false};
std::chrono::microseconds m_next_addr_send GUARDED_BY(cs_sendProcessing){0};
std::chrono::microseconds m_next_local_addr_send GUARDED_BY(cs_sendProcessing){0};
- bool IsAddrRelayPeer() const { return m_addr_known != nullptr; }
-
// List of block ids we still have announce.
// There is no final sorting before sending, as they are always sent immediately
// and in the order requested.
@@ -932,8 +981,17 @@ public:
// Used for headers announcements - unfiltered blocks to relay
std::vector<uint256> vBlockHashesToAnnounce GUARDED_BY(cs_inventory);
- // Block and TXN accept times
+ /** UNIX epoch time of the last block received from this peer that we had
+ * not yet seen (e.g. not already received from another peer), that passed
+ * preliminary validity checks and was saved to disk, even if we don't
+ * connect the block or it eventually fails connection. Used as an inbound
+ * peer eviction criterium in CConnman::AttemptToEvictConnection. */
std::atomic<int64_t> nLastBlockTime{0};
+
+ /** UNIX epoch time of the last transaction received from this peer that we
+ * had not yet seen (e.g. not already received from another peer) and that
+ * was accepted into our mempool. Used as an inbound peer eviction criterium
+ * in CConnman::AttemptToEvictConnection. */
std::atomic<int64_t> nLastTXTime{0};
// Ping time measurement:
@@ -959,6 +1017,7 @@ private:
const NodeId id;
const uint64_t nLocalHostNonce;
const ConnectionType m_conn_type;
+ std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
//! Services offered to this peer.
//!
@@ -978,7 +1037,6 @@ private:
const ServiceFlags nLocalServices;
const int nMyStartingHeight;
- int nSendVersion{0};
NetPermissionFlags m_permissionFlags{ PF_NONE };
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
@@ -1010,16 +1068,14 @@ public:
bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete);
- void SetRecvVersion(int nVersionIn)
+ void SetCommonVersion(int greatest_common_version)
{
- nRecvVersion = nVersionIn;
+ m_greatest_common_version = greatest_common_version;
}
- int GetRecvVersion() const
+ int GetCommonVersion() const
{
- return nRecvVersion;
+ return m_greatest_common_version;
}
- void SetSendVersion(int nVersionIn);
- int GetSendVersion() const;
CService GetAddrLocal() const;
//! May not be called more than once
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index adad428413..690b59476b 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -663,19 +663,18 @@ static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connma
}
}
connman.ForNode(nodeid, [&connman](CNode* pfrom){
- AssertLockHeld(cs_main);
+ LockAssertion lock(::cs_main);
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, nCMPCTBLOCKVersion](CNode* pnodeStop){
- AssertLockHeld(cs_main);
- connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/false, nCMPCTBLOCKVersion));
+ connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/false, nCMPCTBLOCKVersion));
return true;
});
lNodesAnnouncingHeaderAndIDs.pop_front();
}
- connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/true, nCMPCTBLOCKVersion));
+ connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/true, nCMPCTBLOCKVersion));
lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
return true;
});
@@ -870,7 +869,7 @@ void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)
if (state) state->m_last_block_announcement = time_in_seconds;
}
-void PeerLogicValidation::InitializeNode(CNode *pnode) {
+void PeerManager::InitializeNode(CNode *pnode) {
CAddress addr = pnode->addr;
std::string addrName = pnode->GetAddrName();
NodeId nodeid = pnode->GetId();
@@ -883,21 +882,23 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) {
LOCK(g_peer_mutex);
g_peer_map.emplace_hint(g_peer_map.end(), nodeid, std::move(peer));
}
- if(!pnode->IsInboundConn())
+ if (!pnode->IsInboundConn()) {
PushNodeVersion(*pnode, m_connman, GetTime());
+ }
}
-void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
+void PeerManager::ReattemptInitialBroadcast(CScheduler& scheduler) const
{
- std::map<uint256, uint256> unbroadcast_txids = m_mempool.GetUnbroadcastTxs();
+ std::set<uint256> unbroadcast_txids = m_mempool.GetUnbroadcastTxs();
+
+ for (const auto& txid : unbroadcast_txids) {
+ CTransactionRef tx = m_mempool.get(txid);
- for (const auto& elem : unbroadcast_txids) {
- // Sanity check: all unbroadcast txns should exist in the mempool
- if (m_mempool.exists(elem.first)) {
+ if (tx != nullptr) {
LOCK(cs_main);
- RelayTransaction(elem.first, elem.second, m_connman);
+ RelayTransaction(txid, tx->GetWitnessHash(), m_connman);
} else {
- m_mempool.RemoveUnbroadcastTx(elem.first, true);
+ m_mempool.RemoveUnbroadcastTx(txid, true);
}
}
@@ -907,7 +908,7 @@ void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
}
-void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
+void PeerManager::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
fUpdateConnectionTime = false;
LOCK(cs_main);
int misbehavior{0};
@@ -1110,11 +1111,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
return nEvicted;
}
-/**
- * Increment peer's misbehavior score. If the new value >= DISCOURAGEMENT_THRESHOLD, mark the node
- * to be discouraged, meaning the peer might be disconnected and added to the discouragement filter.
- */
-void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message)
+void PeerManager::Misbehaving(const NodeId pnode, const int howmuch, const std::string& message)
{
assert(howmuch > 0);
@@ -1132,17 +1129,9 @@ void Misbehaving(const NodeId pnode, const int howmuch, const std::string& messa
}
}
-/**
- * Potentially mark a node discouraged based on the contents of a BlockValidationState object
- *
- * @param[in] via_compact_block this bool is passed in because net_processing should
- * punish peers differently depending on whether the data was provided in a compact
- * block message or not. If the compact block had a valid header, but contained invalid
- * txs, the peer should not be punished. See BIP 152.
- *
- * @return Returns true if the peer was punished (probably disconnected)
- */
-static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, bool via_compact_block, const std::string& message = "") {
+bool PeerManager::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
+ bool via_compact_block, const std::string& message)
+{
switch (state.GetResult()) {
case BlockValidationResult::BLOCK_RESULT_UNSET:
break;
@@ -1190,12 +1179,7 @@ static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& s
return false;
}
-/**
- * Potentially disconnect and discourage a node based on the contents of a TxValidationState object
- *
- * @return Returns true if the peer was punished (probably disconnected)
- */
-static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "")
+bool PeerManager::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message)
{
switch (state.GetResult()) {
case TxValidationResult::TX_RESULT_UNSET:
@@ -1241,8 +1225,10 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
}
-PeerLogicValidation::PeerLogicValidation(CConnman& connman, BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool)
- : m_connman(connman),
+PeerManager::PeerManager(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
+ CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool)
+ : m_chainparams(chainparams),
+ m_connman(connman),
m_banman(banman),
m_chainman(chainman),
m_mempool(pool),
@@ -1262,13 +1248,12 @@ PeerLogicValidation::PeerLogicValidation(CConnman& connman, BanMan* banman, CSch
// same probability that we have in the reject filter).
g_recent_confirmed_transactions.reset(new CRollingBloomFilter(48000, 0.000001));
- const Consensus::Params& consensusParams = Params().GetConsensus();
// Stale tip checking and peer eviction are on two different timers, but we
// don't want them to get out of sync due to drift in the scheduler, so we
// combine them in one function and schedule at the quicker (peer-eviction)
// timer.
static_assert(EXTRA_PEER_CHECK_INTERVAL < STALE_CHECK_INTERVAL, "peer eviction timer should be less than stale tip check timer");
- scheduler.scheduleEvery([this, consensusParams] { this->CheckForStaleTipAndEvictPeers(consensusParams); }, std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL});
+ scheduler.scheduleEvery([this] { this->CheckForStaleTipAndEvictPeers(); }, std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL});
// schedule next run for 10-15 minutes in the future
const std::chrono::milliseconds delta = std::chrono::minutes{10} + GetRandMillis(std::chrono::minutes{5});
@@ -1279,7 +1264,7 @@ PeerLogicValidation::PeerLogicValidation(CConnman& connman, BanMan* banman, CSch
* Evict orphan txn pool entries (EraseOrphanTx) based on a newly connected
* block. Also save the time of the last tip update.
*/
-void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
+void PeerManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
{
{
LOCK(g_cs_orphans);
@@ -1323,7 +1308,7 @@ void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pb
}
}
-void PeerLogicValidation::BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex)
+void PeerManager::BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex)
{
// To avoid relay problems with transactions that were previously
// confirmed, clear our filter of recently confirmed transactions whenever
@@ -1348,7 +1333,7 @@ static bool fWitnessesPresentInMostRecentCompactBlock GUARDED_BY(cs_most_recent_
* Maintain state about the best-seen block and fast-announce a compact block
* to compatible peers.
*/
-void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) {
+void PeerManager::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) {
std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs> (*pblock, true);
const CNetMsgMaker msgMaker(PROTOCOL_VERSION);
@@ -1359,7 +1344,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
return;
nHighestFastAnnounce = pindex->nHeight;
- bool fWitnessEnabled = IsWitnessEnabled(pindex->pprev, Params().GetConsensus());
+ bool fWitnessEnabled = IsWitnessEnabled(pindex->pprev, m_chainparams.GetConsensus());
uint256 hashBlock(pblock->GetHash());
{
@@ -1371,10 +1356,10 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
}
m_connman.ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) {
- AssertLockHeld(cs_main);
+ LockAssertion lock(::cs_main);
// TODO: Avoid the repeated-serialization here
- if (pnode->nVersion < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect)
+ if (pnode->GetCommonVersion() < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect)
return;
ProcessBlockAvailability(pnode->GetId());
CNodeState &state = *State(pnode->GetId());
@@ -1383,7 +1368,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
if (state.fPreferHeaderAndIDs && (!fWitnessEnabled || state.fWantsCmpctWitness) &&
!PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) {
- LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerLogicValidation::NewPoWValidBlock",
+ LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerManager::NewPoWValidBlock",
hashBlock.ToString(), pnode->GetId());
m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock));
state.pindexBestHeaderSent = pindex;
@@ -1395,7 +1380,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
* Update our best height and announce any block hashes which weren't previously
* in ::ChainActive() to our peers.
*/
-void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
+void PeerManager::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
const int nNewHeight = pindexNew->nHeight;
m_connman.SetBestHeight(nNewHeight);
@@ -1430,7 +1415,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
* Handle invalid block rejection and consequent peer discouragement, maintain which
* peers announce compact blocks.
*/
-void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidationState& state) {
+void PeerManager::BlockChecked(const CBlock& block, const BlockValidationState& state) {
LOCK(cs_main);
const uint256 hash(block.GetHash());
@@ -1466,56 +1451,51 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidatio
//
-bool static AlreadyHave(const CInv& inv, const CTxMemPool& mempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+bool static AlreadyHaveTx(const GenTxid& gtxid, const CTxMemPool& mempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- switch (inv.type)
- {
- case MSG_TX:
- case MSG_WITNESS_TX:
- case MSG_WTX:
- {
- assert(recentRejects);
- if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip)
- {
- // If the chain tip has changed previously rejected transactions
- // might be now valid, e.g. due to a nLockTime'd tx becoming valid,
- // or a double-spend. Reset the rejects filter and give those
- // txs a second chance.
- hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash();
- recentRejects->reset();
- }
-
- {
- LOCK(g_cs_orphans);
- if (!inv.IsMsgWtx() && mapOrphanTransactions.count(inv.hash)) {
- return true;
- } else if (inv.IsMsgWtx() && g_orphans_by_wtxid.count(inv.hash)) {
- return true;
- }
- }
+ assert(recentRejects);
+ if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip) {
+ // If the chain tip has changed previously rejected transactions
+ // might be now valid, e.g. due to a nLockTime'd tx becoming valid,
+ // or a double-spend. Reset the rejects filter and give those
+ // txs a second chance.
+ hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash();
+ recentRejects->reset();
+ }
- {
- LOCK(g_cs_recent_confirmed_transactions);
- if (g_recent_confirmed_transactions->contains(inv.hash)) return true;
- }
+ const uint256& hash = gtxid.GetHash();
- return recentRejects->contains(inv.hash) || mempool.exists(ToGenTxid(inv));
+ {
+ LOCK(g_cs_orphans);
+ if (!gtxid.IsWtxid() && mapOrphanTransactions.count(hash)) {
+ return true;
+ } else if (gtxid.IsWtxid() && g_orphans_by_wtxid.count(hash)) {
+ return true;
}
- case MSG_BLOCK:
- case MSG_WITNESS_BLOCK:
- return LookupBlockIndex(inv.hash) != nullptr;
}
- // Don't know what it is, just say we already got one
- return true;
+
+ {
+ LOCK(g_cs_recent_confirmed_transactions);
+ if (g_recent_confirmed_transactions->contains(hash)) return true;
+ }
+
+ return recentRejects->contains(hash) || mempool.exists(gtxid);
+}
+
+bool static AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ return LookupBlockIndex(block_hash) != nullptr;
}
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman)
{
connman.ForEachNode([&txid, &wtxid](CNode* pnode)
{
- AssertLockHeld(cs_main);
- CNodeState &state = *State(pnode->GetId());
- if (state.m_wtxid_relay) {
+ LockAssertion lock(::cs_main);
+
+ CNodeState* state = State(pnode->GetId());
+ if (state == nullptr) return;
+ if (state->m_wtxid_relay) {
pnode->PushTxInventory(wtxid);
} else {
pnode->PushTxInventory(txid);
@@ -1525,7 +1505,6 @@ void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman&
static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& connman)
{
- unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
// Relay to a limited number of other nodes
// Use deterministic randomness to send to the same nodes for 24 hours
@@ -1534,11 +1513,14 @@ static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman&
const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24 * 60 * 60));
FastRandomContext insecure_rand;
+ // Relay reachable addresses to 2 peers. Unreachable addresses are relayed randomly to 1 or 2 peers.
+ unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
+
std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
assert(nRelayNodes <= best.size());
auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode) {
- if (pnode->IsAddrRelayPeer()) {
+ if (pnode->RelayAddrsWithConn()) {
uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();
for (unsigned int i = 0; i < nRelayNodes; i++) {
if (hashKey > best[i].first) {
@@ -1591,7 +1573,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
} // release cs_main before calling ActivateBestChain
if (need_activate_chain) {
BlockValidationState state;
- if (!ActivateBestChain(state, Params(), a_recent_block)) {
+ if (!ActivateBestChain(state, chainparams, a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString());
}
}
@@ -1604,11 +1586,11 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId());
}
}
- const CNetMsgMaker msgMaker(pfrom.GetSendVersion());
+ const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
// disconnect node in case we have reached the outbound limit for serving historical blocks
if (send &&
connman.OutboundTargetReached(true) &&
- (((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) &&
+ (((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
!pfrom.HasPermission(PF_DOWNLOAD) // nodes with the download permission may exceed target
) {
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
@@ -1634,7 +1616,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
std::shared_ptr<const CBlock> pblock;
if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
pblock = a_recent_block;
- } else if (inv.type == MSG_WITNESS_BLOCK) {
+ } else if (inv.IsMsgWitnessBlk()) {
// Fast-path: in this case it is possible to serve the block directly from disk,
// as the network format matches the format on disk
std::vector<uint8_t> block_data;
@@ -1651,12 +1633,11 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
pblock = pblockRead;
}
if (pblock) {
- if (inv.type == MSG_BLOCK)
+ if (inv.IsMsgBlk()) {
connman.PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
- else if (inv.type == MSG_WITNESS_BLOCK)
+ } else if (inv.IsMsgWitnessBlk()) {
connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
- else if (inv.type == MSG_FILTERED_BLOCK)
- {
+ } else if (inv.IsMsgFilteredBlk()) {
bool sendMerkleBlock = false;
CMerkleBlock merkleBlock;
if (pfrom.m_tx_relay != nullptr) {
@@ -1680,9 +1661,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
}
// else
// no response
- }
- else if (inv.type == MSG_CMPCT_BLOCK)
- {
+ } else if (inv.IsMsgCmpctBlk()) {
// If a peer is asking for old blocks, we're almost guaranteed
// they won't have a useful mempool to match against a compact block,
// and we don't feel like constructing the object for them, so
@@ -1717,7 +1696,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
}
//! Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed).
-CTransactionRef static FindTxForGetData(const CNode& peer, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now) LOCKS_EXCLUDED(cs_main)
+static CTransactionRef FindTxForGetData(const CTxMemPool& mempool, const CNode& peer, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now) LOCKS_EXCLUDED(cs_main)
{
auto txinfo = mempool.info(gtxid);
if (txinfo.tx) {
@@ -1750,7 +1729,7 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm
std::deque<CInv>::iterator it = pfrom.vRecvGetData.begin();
std::vector<CInv> vNotFound;
- const CNetMsgMaker msgMaker(pfrom.GetSendVersion());
+ const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
const std::chrono::seconds now = GetTime<std::chrono::seconds>();
// Get last mempool request time
@@ -1773,7 +1752,7 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm
continue;
}
- CTransactionRef tx = FindTxForGetData(pfrom, ToGenTxid(inv), mempool_req, now);
+ CTransactionRef tx = FindTxForGetData(mempool, pfrom, ToGenTxid(inv), mempool_req, now);
if (tx) {
// WTX and WITNESS_TX imply we serialize with witness
int nSendFlags = (inv.IsMsgTx() ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
@@ -1785,11 +1764,11 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm
LOCK(mempool.cs);
auto txiter = mempool.GetIter(tx->GetHash());
if (txiter) {
- const CTxMemPool::setEntries& parents = mempool.GetMemPoolParents(*txiter);
+ const CTxMemPoolEntry::Parents& parents = (*txiter)->GetMemPoolParentsConst();
parent_ids_to_add.reserve(parents.size());
- for (CTxMemPool::txiter parent_iter : parents) {
- if (parent_iter->GetTime() > now - UNCONDITIONAL_RELAY_DELAY) {
- parent_ids_to_add.push_back(parent_iter->GetTx().GetHash());
+ for (const CTxMemPoolEntry& parent : parents) {
+ if (parent.GetTime() > now - UNCONDITIONAL_RELAY_DELAY) {
+ parent_ids_to_add.push_back(parent.GetTx().GetHash());
}
}
}
@@ -1810,7 +1789,7 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm
// expensive to process.
if (it != pfrom.vRecvGetData.end() && !pfrom.fPauseSend) {
const CInv &inv = *it++;
- if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK) {
+ if (inv.IsGenBlkMsg()) {
ProcessGetBlockData(pfrom, chainparams, inv, connman);
}
// else: If the first item on the queue is an unknown type, we erase it
@@ -1846,7 +1825,7 @@ static uint32_t GetFetchFlags(const CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(cs_ma
return nFetchFlags;
}
-inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode& pfrom, CConnman& connman) {
+void PeerManager::SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req) {
BlockTransactions resp(req);
for (size_t i = 0; i < req.indexes.size(); i++) {
if (req.indexes[i] >= block.vtx.size()) {
@@ -1856,14 +1835,14 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
resp.txn[i] = block.vtx[req.indexes[i]];
}
LOCK(cs_main);
- const CNetMsgMaker msgMaker(pfrom.GetSendVersion());
+ const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
int nSendFlags = State(pfrom.GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
- connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
}
-static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateManager& chainman, CTxMemPool& mempool, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool via_compact_block)
+void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHeader>& headers, bool via_compact_block)
{
- const CNetMsgMaker msgMaker(pfrom.GetSendVersion());
+ const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
size_t nCount = headers.size();
if (nCount == 0) {
@@ -1887,7 +1866,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
// nUnconnectingHeaders gets reset back to 0.
if (!LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++;
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(),
@@ -1921,7 +1900,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
}
BlockValidationState state;
- if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) {
+ if (!m_chainman.ProcessNewBlockHeaders(headers, state, m_chainparams, &pindexLast)) {
if (state.IsInvalid()) {
MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
return;
@@ -1952,10 +1931,10 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
// TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue
// from there instead.
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom.GetId(), pfrom.nStartingHeight);
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256()));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256()));
}
- bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
+ bool fCanDirectFetch = CanDirectFetch(m_chainparams.GetConsensus());
// If this set of headers is valid and ends in a block with at least as
// much work as our tip, download as much as possible.
if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && ::ChainActive().Tip()->nChainWork <= pindexLast->nChainWork) {
@@ -1965,7 +1944,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
while (pindexWalk && !::ChainActive().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
!mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
- (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom.GetId())->fHaveWitness)) {
+ (!IsWitnessEnabled(pindexWalk->pprev, m_chainparams.GetConsensus()) || State(pfrom.GetId())->fHaveWitness)) {
// We don't have this block, and it's not yet in flight.
vToFetch.push_back(pindexWalk);
}
@@ -1989,7 +1968,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
}
uint32_t nFetchFlags = GetFetchFlags(pfrom);
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(mempool, pfrom.GetId(), pindex->GetBlockHash(), pindex);
+ MarkBlockAsInFlight(m_mempool, pfrom.GetId(), pindex->GetBlockHash(), pindex);
LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
pindex->GetBlockHash().ToString(), pfrom.GetId());
}
@@ -2002,7 +1981,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
// In any case, we want to download using a compact block, not a regular one
vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
}
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
}
}
}
@@ -2027,7 +2006,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
}
}
- if (!pfrom.fDisconnect && pfrom.IsOutboundOrBlockRelayConn() && nodestate->pindexBestKnownBlock != nullptr && pfrom.m_tx_relay != nullptr) {
+ if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn() && nodestate->pindexBestKnownBlock != nullptr) {
// If this is an outbound full-relay peer, check to see if we should protect
// it from the bad/lagging chain logic.
// Note that block-relay-only peers are already implicitly protected, so we
@@ -2043,7 +2022,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
return;
}
-void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans)
+void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn)
{
AssertLockHeld(cs_main);
AssertLockHeld(g_cs_orphans);
@@ -2065,9 +2044,9 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
TxValidationState orphan_state;
if (setMisbehaving.count(fromPeer)) continue;
- if (AcceptToMemoryPool(mempool, orphan_state, porphanTx, &removed_txn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ if (AcceptToMemoryPool(m_mempool, orphan_state, porphanTx, &removed_txn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanHash, porphanTx->GetWitnessHash(), connman);
+ RelayTransaction(orphanHash, porphanTx->GetWitnessHash(), m_connman);
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(orphanHash, i));
if (it_by_prev != mapOrphanTransactionsByPrev.end()) {
@@ -2125,7 +2104,7 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
EraseOrphanTx(orphanHash);
done = true;
}
- mempool.check(&::ChainstateActive().CoinsTip());
+ m_mempool.check(&::ChainstateActive().CoinsTip());
}
}
@@ -2233,7 +2212,7 @@ static void ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainPara
}
for (const auto& filter : filters) {
- CSerializedNetMsg msg = CNetMsgMaker(peer.GetSendVersion())
+ CSerializedNetMsg msg = CNetMsgMaker(peer.GetCommonVersion())
.Make(NetMsgType::CFILTER, filter);
connman.PushMessage(&peer, std::move(msg));
}
@@ -2285,7 +2264,7 @@ static void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainPar
return;
}
- CSerializedNetMsg msg = CNetMsgMaker(peer.GetSendVersion())
+ CSerializedNetMsg msg = CNetMsgMaker(peer.GetCommonVersion())
.Make(NetMsgType::CFHEADERS,
filter_type_ser,
stop_index->GetBlockHash(),
@@ -2337,7 +2316,7 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
}
}
- CSerializedNetMsg msg = CNetMsgMaker(peer.GetSendVersion())
+ CSerializedNetMsg msg = CNetMsgMaker(peer.GetCommonVersion())
.Make(NetMsgType::CFCHECKPT,
filter_type_ser,
stop_index->GetBlockHash(),
@@ -2345,9 +2324,9 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
connman.PushMessage(&peer, std::move(msg));
}
-void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
+void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
const std::chrono::microseconds time_received,
- const CChainParams& chainparams, const std::atomic<bool>& interruptMsgProc)
+ const std::atomic<bool>& interruptMsgProc)
{
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom.GetId());
if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0)
@@ -2372,13 +2351,11 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
uint64_t nServiceInt;
ServiceFlags nServices;
int nVersion;
- int nSendVersion;
std::string cleanSubVer;
int nStartingHeight = -1;
bool fRelay = true;
vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
- nSendVersion = std::min(nVersion, PROTOCOL_VERSION);
nServices = ServiceFlags(nServiceInt);
if (!pfrom.IsInboundConn())
{
@@ -2427,11 +2404,16 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
if (pfrom.IsInboundConn())
PushNodeVersion(pfrom, m_connman, GetAdjustedTime());
- if (nVersion >= WTXID_RELAY_VERSION) {
- m_connman.PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::WTXIDRELAY));
+ // Change version
+ const int greatest_common_version = std::min(nVersion, PROTOCOL_VERSION);
+ pfrom.SetCommonVersion(greatest_common_version);
+ pfrom.nVersion = nVersion;
+
+ if (greatest_common_version >= WTXID_RELAY_VERSION) {
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::WTXIDRELAY));
}
- m_connman.PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::VERACK));
pfrom.nServices = nServices;
pfrom.SetAddrLocal(addrMe);
@@ -2452,10 +2434,6 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
pfrom.m_tx_relay->fRelayTxes = fRelay; // set to true after we get the first filter* message
}
- // Change version
- pfrom.SetSendVersion(nSendVersion);
- pfrom.nVersion = nVersion;
-
if((nServices & NODE_WITNESS))
{
LOCK(cs_main);
@@ -2468,9 +2446,23 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
UpdatePreferredDownload(pfrom, State(pfrom.GetId()));
}
- if (!pfrom.IsInboundConn() && pfrom.IsAddrRelayPeer())
- {
- // Advertise our address
+ if (!pfrom.IsInboundConn() && !pfrom.IsBlockOnlyConn()) {
+ // For outbound peers, we try to relay our address (so that other
+ // nodes can try to find us more quickly, as we have no guarantee
+ // that an outbound peer is even aware of how to reach us) and do a
+ // one-time address fetch (to help populate/update our addrman). If
+ // we're starting up for the first time, our addrman may be pretty
+ // empty and no one will know who we are, so these mechanisms are
+ // important to help us connect to the network.
+ //
+ // We also update the addrman to record connection success for
+ // these peers (which include OUTBOUND_FULL_RELAY and FEELER
+ // connections) so that addrman will have an up-to-date notion of
+ // which peers are online and available.
+ //
+ // We skip these operations for BLOCK_RELAY peers to avoid
+ // potentially leaking information about our BLOCK_RELAY
+ // connections via the addrman or address relay.
if (fListen && !::ChainstateActive().IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices());
@@ -2487,8 +2479,11 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
// Get recent addresses
- m_connman.PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
pfrom.fGetAddr = true;
+
+ // Moves address from New to Tried table in Addrman, resolves
+ // tried-table collisions, etc.
m_connman.MarkAddressGood(pfrom.addr);
}
@@ -2506,9 +2501,9 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
AddTimeData(pfrom.addr, nTimeOffset);
// If the peer is old enough to have the old alert system, send it the final alert.
- if (pfrom.nVersion <= 70012) {
+ if (greatest_common_version <= 70012) {
CDataStream finalAlert(ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"), SER_NETWORK, PROTOCOL_VERSION);
- m_connman.PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert));
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make("alert", finalAlert));
}
// Feeler connections exist only to verify if address is online.
@@ -2525,12 +2520,10 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
// At this point, the outgoing message serialization version can't change.
- const CNetMsgMaker msgMaker(pfrom.GetSendVersion());
+ const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
if (msg_type == NetMsgType::VERACK)
{
- pfrom.SetRecvVersion(std::min(pfrom.nVersion.load(), PROTOCOL_VERSION));
-
if (!pfrom.IsInboundConn()) {
// Mark this node as currently connected, so we update its timestamp later.
LOCK(cs_main);
@@ -2541,14 +2534,14 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
pfrom.m_tx_relay == nullptr ? "block-relay" : "full-relay");
}
- if (pfrom.nVersion >= SENDHEADERS_VERSION) {
+ if (pfrom.GetCommonVersion() >= SENDHEADERS_VERSION) {
// Tell our peer we prefer to receive headers rather than inv's
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
}
- if (pfrom.nVersion >= SHORT_IDS_BLOCKS_VERSION) {
+ if (pfrom.GetCommonVersion() >= SHORT_IDS_BLOCKS_VERSION) {
// Tell our peer we are willing to provide version 1 or 2 cmpctblocks
// However, we do not request new block announcements using
// cmpctblock messages.
@@ -2574,7 +2567,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
pfrom.fDisconnect = true;
return;
}
- if (pfrom.nVersion >= WTXID_RELAY_VERSION) {
+ if (pfrom.GetCommonVersion() >= WTXID_RELAY_VERSION) {
LOCK(cs_main);
if (!State(pfrom.GetId())->m_wtxid_relay) {
State(pfrom.GetId())->m_wtxid_relay = true;
@@ -2594,7 +2587,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
std::vector<CAddress> vAddr;
vRecv >> vAddr;
- if (!pfrom.IsAddrRelayPeer()) {
+ if (!pfrom.RelayAddrsWithConn()) {
return;
}
if (vAddr.size() > MAX_ADDR_TO_SEND)
@@ -2692,14 +2685,11 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
LOCK(cs_main);
- uint32_t nFetchFlags = GetFetchFlags(pfrom);
const auto current_time = GetTime<std::chrono::microseconds>();
uint256* best_block{nullptr};
- for (CInv &inv : vInv)
- {
- if (interruptMsgProc)
- return;
+ for (CInv& inv : vInv) {
+ if (interruptMsgProc) return;
// Ignore INVs that don't match wtxidrelay setting.
// Note that orphan parent fetching always uses MSG_TX GETDATAs regardless of the wtxidrelay setting.
@@ -2710,14 +2700,10 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
if (inv.IsMsgWtx()) continue;
}
- bool fAlreadyHave = AlreadyHave(inv, m_mempool);
- LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
-
- if (inv.IsMsgTx()) {
- inv.type |= nFetchFlags;
- }
+ if (inv.IsMsgBlk()) {
+ const bool fAlreadyHave = AlreadyHaveBlock(inv.hash);
+ LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
- if (inv.type == MSG_BLOCK) {
UpdateBlockAvailability(pfrom.GetId(), inv.hash);
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
// Headers-first is the primary method of announcement on
@@ -2727,15 +2713,21 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
// then fetch the blocks we need to catch up.
best_block = &inv.hash;
}
- } else {
+ } else if (inv.IsGenTxMsg()) {
+ const GenTxid gtxid = ToGenTxid(inv);
+ const bool fAlreadyHave = AlreadyHaveTx(gtxid, m_mempool);
+ LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
+
pfrom.AddKnownTx(inv.hash);
if (fBlocksOnly) {
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
pfrom.fDisconnect = true;
return;
} else if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
- RequestTx(State(pfrom.GetId()), ToGenTxid(inv), current_time);
+ RequestTx(State(pfrom.GetId()), gtxid, current_time);
}
+ } else {
+ LogPrint(BCLog::NET, "Unknown inv type \"%s\" received from peer=%d\n", inv.ToString(), pfrom.GetId());
}
}
@@ -2763,7 +2755,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
pfrom.vRecvGetData.insert(pfrom.vRecvGetData.end(), vInv.begin(), vInv.end());
- ProcessGetData(pfrom, chainparams, m_connman, m_mempool, interruptMsgProc);
+ ProcessGetData(pfrom, m_chainparams, m_connman, m_mempool, interruptMsgProc);
return;
}
@@ -2792,7 +2784,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
a_recent_block = most_recent_block;
}
BlockValidationState state;
- if (!ActivateBestChain(state, Params(), a_recent_block)) {
+ if (!ActivateBestChain(state, m_chainparams, a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString());
}
}
@@ -2816,7 +2808,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
// If pruning, don't inv blocks unless we have on disk and are likely to still have
// for some reasonable time window (1 hour) that block relay might require.
- const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing;
+ const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / m_chainparams.GetConsensus().nPowTargetSpacing;
if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= ::ChainActive().Tip()->nHeight - nPrunedBlocksLikelyToHave))
{
LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
@@ -2847,7 +2839,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
// Unlock cs_most_recent_block to avoid cs_main lock inversion
}
if (recent_block) {
- SendBlockTransactions(*recent_block, req, pfrom, m_connman);
+ SendBlockTransactions(pfrom, *recent_block, req);
return;
}
@@ -2877,10 +2869,10 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
CBlock block;
- bool ret = ReadBlockFromDisk(block, pindex, chainparams.GetConsensus());
+ bool ret = ReadBlockFromDisk(block, pindex, m_chainparams.GetConsensus());
assert(ret);
- SendBlockTransactions(block, req, pfrom, m_connman);
+ SendBlockTransactions(pfrom, block, req);
return;
}
@@ -2911,7 +2903,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
return;
}
- if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) {
+ if (!BlockRequestAllowed(pindex, m_chainparams.GetConsensus())) {
LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom.GetId());
return;
}
@@ -2994,7 +2986,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
std::list<CTransactionRef> lRemovedTxn;
- // We do the AlreadyHave() check using wtxid, rather than txid - in the
+ // We do the AlreadyHaveTx() check using wtxid, rather than txid - in the
// absence of witness malleation, this is strictly better, because the
// recent rejects filter may contain the wtxid but rarely contains
// the txid of a segwit transaction that has been rejected.
@@ -3006,7 +2998,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
// already; and an adversary can already relay us old transactions
// (older than our recency filter) if trying to DoS us, without any need
// for witness malleation.
- if (!AlreadyHave(CInv(MSG_WTX, wtxid), m_mempool) &&
+ if (!AlreadyHaveTx(GenTxid(/* is_wtxid=*/true, wtxid), m_mempool) &&
AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
m_mempool.check(&::ChainstateActive().CoinsTip());
RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
@@ -3027,7 +3019,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);
// Recursively process any orphan transactions that depended on this one
- ProcessOrphanTx(m_connman, m_mempool, pfrom.orphan_work_set, lRemovedTxn);
+ ProcessOrphanTx(pfrom.orphan_work_set, lRemovedTxn);
}
else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS)
{
@@ -3050,7 +3042,6 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
}
if (!fRejectedParents) {
- uint32_t nFetchFlags = GetFetchFlags(pfrom);
const auto current_time = GetTime<std::chrono::microseconds>();
for (const uint256& parent_txid : unique_parents) {
@@ -3059,9 +3050,9 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
// wtxidrelay peers.
// Eventually we should replace this with an improved
// protocol for getting all unconfirmed parents.
- CInv _inv(MSG_TX | nFetchFlags, parent_txid);
+ const GenTxid gtxid{/* is_wtxid=*/false, parent_txid};
pfrom.AddKnownTx(parent_txid);
- if (!AlreadyHave(_inv, m_mempool)) RequestTx(State(pfrom.GetId()), ToGenTxid(_inv), current_time);
+ if (!AlreadyHaveTx(gtxid, m_mempool)) RequestTx(State(pfrom.GetId()), gtxid, current_time);
}
AddOrphanTx(ptx, pfrom.GetId());
@@ -3113,8 +3104,6 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
if (RecursiveDynamicUsage(*ptx) < 100000) {
AddToCompactExtraTransactions(ptx);
}
- } else if (tx.HasWitness() && RecursiveDynamicUsage(*ptx) < 100000) {
- AddToCompactExtraTransactions(ptx);
}
if (pfrom.HasPermission(PF_FORCERELAY)) {
@@ -3190,7 +3179,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
const CBlockIndex *pindex = nullptr;
BlockValidationState state;
- if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
+ if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, m_chainparams, &pindex)) {
if (state.IsInvalid()) {
MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
return;
@@ -3246,10 +3235,10 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
// If we're not close to tip yet, give up and let parallel block fetch work its magic
- if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus()))
+ if (!fAlreadyInFlight && !CanDirectFetch(m_chainparams.GetConsensus()))
return;
- if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) {
+ if (IsWitnessEnabled(pindex->pprev, m_chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) {
// Don't bother trying to process compact blocks from v1 peers
// after segwit activates.
return;
@@ -3333,8 +3322,9 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
} // cs_main
- if (fProcessBLOCKTXN)
- return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, time_received, chainparams, interruptMsgProc);
+ if (fProcessBLOCKTXN) {
+ return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, time_received, interruptMsgProc);
+ }
if (fRevertToHeaderProcessing) {
// Headers received from HB compact block peers are permitted to be
@@ -3342,7 +3332,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
// the peer if the header turns out to be for an invalid block.
// Note that if a peer tries to build on an invalid chain, that
// will be detected and the peer will be disconnected/discouraged.
- return ProcessHeadersMessage(pfrom, m_connman, m_chainman, m_mempool, {cmpctblock.header}, chainparams, /*via_compact_block=*/true);
+ return ProcessHeadersMessage(pfrom, {cmpctblock.header}, /*via_compact_block=*/true);
}
if (fBlockReconstructed) {
@@ -3362,7 +3352,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
// we have a chain with at least nMinimumChainWork), and we ignore
// compact blocks with less work than our tip, it is safe to treat
// reconstructed compact blocks as having been requested.
- m_chainman.ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
+ m_chainman.ProcessNewBlock(m_chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
if (fNewBlock) {
pfrom.nLastBlockTime = GetTime();
} else {
@@ -3452,7 +3442,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
// disk-space attacks), but this should be safe due to the
// protections in the compact block handler -- see related comment
// in compact block optimistic reconstruction handling.
- m_chainman.ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
+ m_chainman.ProcessNewBlock(m_chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
if (fNewBlock) {
pfrom.nLastBlockTime = GetTime();
} else {
@@ -3485,7 +3475,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
- return ProcessHeadersMessage(pfrom, m_connman, m_chainman, m_mempool, headers, chainparams, /*via_compact_block=*/false);
+ return ProcessHeadersMessage(pfrom, headers, /*via_compact_block=*/false);
}
if (msg_type == NetMsgType::BLOCK)
@@ -3514,7 +3504,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
}
bool fNewBlock = false;
- m_chainman.ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock);
+ m_chainman.ProcessNewBlock(m_chainparams, pblock, forceProcessing, &fNewBlock);
if (fNewBlock) {
pfrom.nLastBlockTime = GetTime();
} else {
@@ -3534,7 +3524,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
LogPrint(BCLog::NET, "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom.GetId());
return;
}
- if (!pfrom.IsAddrRelayPeer()) {
+ if (!pfrom.RelayAddrsWithConn()) {
LogPrint(BCLog::NET, "Ignoring \"getaddr\" from block-relay-only connection. peer=%d\n", pfrom.GetId());
return;
}
@@ -3552,7 +3542,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
if (pfrom.HasPermission(PF_ADDR)) {
vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
} else {
- vAddr = m_connman.GetAddresses(pfrom.addr.GetNetwork(), MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
+ vAddr = m_connman.GetAddresses(pfrom, MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
}
FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr) {
@@ -3590,8 +3580,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
if (msg_type == NetMsgType::PING) {
- if (pfrom.nVersion > BIP0031_VERSION)
- {
+ if (pfrom.GetCommonVersion() > BIP0031_VERSION) {
uint64_t nonce = 0;
vRecv >> nonce;
// Echo the message back with the nonce. This allows for two useful features:
@@ -3743,17 +3732,17 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
}
if (msg_type == NetMsgType::GETCFILTERS) {
- ProcessGetCFilters(pfrom, vRecv, chainparams, m_connman);
+ ProcessGetCFilters(pfrom, vRecv, m_chainparams, m_connman);
return;
}
if (msg_type == NetMsgType::GETCFHEADERS) {
- ProcessGetCFHeaders(pfrom, vRecv, chainparams, m_connman);
+ ProcessGetCFHeaders(pfrom, vRecv, m_chainparams, m_connman);
return;
}
if (msg_type == NetMsgType::GETCFCHECKPT) {
- ProcessGetCFCheckPt(pfrom, vRecv, chainparams, m_connman);
+ ProcessGetCFCheckPt(pfrom, vRecv, m_chainparams, m_connman);
return;
}
@@ -3787,12 +3776,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
return;
}
-/** Maybe disconnect a peer and discourage future connections from its address.
- *
- * @param[in] pnode The node to check.
- * @return True if the peer was marked for disconnection in this function
- */
-bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode& pnode)
+bool PeerManager::MaybeDiscourageAndDisconnect(CNode& pnode)
{
const NodeId peer_id{pnode.GetId()};
PeerRef peer = GetPeerRef(peer_id);
@@ -3834,9 +3818,8 @@ bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode& pnode)
return true;
}
-bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
+bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
{
- const CChainParams& chainparams = Params();
//
// Message format
// (4) message start
@@ -3848,12 +3831,12 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
bool fMoreWork = false;
if (!pfrom->vRecvGetData.empty())
- ProcessGetData(*pfrom, chainparams, m_connman, m_mempool, interruptMsgProc);
+ ProcessGetData(*pfrom, m_chainparams, m_connman, m_mempool, interruptMsgProc);
if (!pfrom->orphan_work_set.empty()) {
std::list<CTransactionRef> removed_txn;
LOCK2(cs_main, g_cs_orphans);
- ProcessOrphanTx(m_connman, m_mempool, pfrom->orphan_work_set, removed_txn);
+ ProcessOrphanTx(pfrom->orphan_work_set, removed_txn);
for (const CTransactionRef& removedTx : removed_txn) {
AddToCompactExtraTransactions(removedTx);
}
@@ -3884,7 +3867,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
}
CNetMessage& msg(msgs.front());
- msg.SetVersion(pfrom->GetRecvVersion());
+ msg.SetVersion(pfrom->GetCommonVersion());
// Check network magic
if (!msg.m_valid_netmagic) {
LogPrint(BCLog::NET, "PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.m_command), pfrom->GetId());
@@ -3913,7 +3896,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
}
try {
- ProcessMessage(*pfrom, msg_type, vRecv, msg.m_time, chainparams, interruptMsgProc);
+ ProcessMessage(*pfrom, msg_type, vRecv, msg.m_time, interruptMsgProc);
if (interruptMsgProc)
return false;
if (!pfrom->vRecvGetData.empty())
@@ -3927,12 +3910,12 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
return fMoreWork;
}
-void PeerLogicValidation::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
+void PeerManager::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
{
AssertLockHeld(cs_main);
CNodeState &state = *State(pto.GetId());
- const CNetMsgMaker msgMaker(pto.GetSendVersion());
+ const CNetMsgMaker msgMaker(pto.GetCommonVersion());
if (!state.m_chain_sync.m_protect && pto.IsOutboundOrBlockRelayConn() && state.fSyncStarted) {
// This is an outbound peer subject to disconnection if they don't
@@ -3980,7 +3963,7 @@ void PeerLogicValidation::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
}
}
-void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
+void PeerManager::EvictExtraOutboundPeers(int64_t time_in_seconds)
{
// Check whether we have too many outbound peers
int extra_peers = m_connman.GetExtraOutboundCount();
@@ -3993,7 +3976,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
m_connman.ForEachNode([&](CNode* pnode) {
- AssertLockHeld(cs_main);
+ LockAssertion lock(::cs_main);
// Ignore non-outbound peers, or nodes marked for disconnect already
if (!pnode->IsOutboundOrBlockRelayConn() || pnode->fDisconnect) return;
@@ -4010,7 +3993,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
});
if (worst_peer != -1) {
bool disconnected = m_connman.ForNode(worst_peer, [&](CNode *pnode) {
- AssertLockHeld(cs_main);
+ LockAssertion lock(::cs_main);
// Only disconnect a peer that has been connected to us for
// some reasonable fraction of our check-frequency, to give
@@ -4039,7 +4022,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
}
}
-void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams)
+void PeerManager::CheckForStaleTipAndEvictPeers()
{
LOCK(cs_main);
@@ -4050,7 +4033,7 @@ void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params
if (time_in_seconds > m_stale_tip_check_time) {
// Check whether our tip is stale, and if so, allow using an extra
// outbound peer
- if (!fImporting && !fReindex && m_connman.GetNetworkActive() && m_connman.GetUseAddrmanOutgoing() && TipMayBeStale(consensusParams)) {
+ if (!fImporting && !fReindex && m_connman.GetNetworkActive() && m_connman.GetUseAddrmanOutgoing() && TipMayBeStale(m_chainparams.GetConsensus())) {
LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - g_last_tip_update);
m_connman.SetTryNewOutboundPeer(true);
} else if (m_connman.GetTryNewOutboundPeer()) {
@@ -4081,9 +4064,9 @@ public:
};
}
-bool PeerLogicValidation::SendMessages(CNode* pto)
+bool PeerManager::SendMessages(CNode* pto)
{
- const Consensus::Params& consensusParams = Params().GetConsensus();
+ const Consensus::Params& consensusParams = m_chainparams.GetConsensus();
// We must call MaybeDiscourageAndDisconnect first, to ensure that we'll
// disconnect misbehaving peers even before the version handshake is complete.
@@ -4094,7 +4077,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
return true;
// If we get here, the outgoing message serialization version is set and can't change.
- const CNetMsgMaker msgMaker(pto->GetSendVersion());
+ const CNetMsgMaker msgMaker(pto->GetCommonVersion());
//
// Message: ping
@@ -4115,7 +4098,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
}
pto->fPingQueued = false;
pto->m_ping_start = GetTime<std::chrono::microseconds>();
- if (pto->nVersion > BIP0031_VERSION) {
+ if (pto->GetCommonVersion() > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
} else {
@@ -4134,7 +4117,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
int64_t nNow = GetTimeMicros();
auto current_time = GetTime<std::chrono::microseconds>();
- if (pto->IsAddrRelayPeer() && !::ChainstateActive().IsInitialBlockDownload() && pto->m_next_local_addr_send < current_time) {
+ if (pto->RelayAddrsWithConn() && !::ChainstateActive().IsInitialBlockDownload() && pto->m_next_local_addr_send < current_time) {
AdvertiseLocal(pto);
pto->m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
@@ -4142,7 +4125,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
//
// Message: addr
//
- if (pto->IsAddrRelayPeer() && pto->m_next_addr_send < current_time) {
+ if (pto->RelayAddrsWithConn() && pto->m_next_addr_send < current_time) {
pto->m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
std::vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());
@@ -4611,7 +4594,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// processing at a later time, see below)
tx_process_time.erase(tx_process_time.begin());
CInv inv(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*pto)), gtxid.GetHash());
- if (!AlreadyHave(inv, m_mempool)) {
+ if (!AlreadyHaveTx(ToGenTxid(inv), m_mempool)) {
// If this transaction was last requested more than 1 minute ago,
// then request.
const auto last_request_time = GetTxRequestTime(gtxid);
@@ -4654,7 +4637,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
//
// Message: feefilter
//
- if (pto->m_tx_relay != nullptr && pto->nVersion >= FEEFILTER_VERSION && gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ if (pto->m_tx_relay != nullptr && 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 4f1c52fc17..3e748c0c5b 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -11,9 +11,13 @@
#include <sync.h>
#include <validationinterface.h>
+class BlockTransactionsRequest;
+class BlockValidationState;
+class CBlockHeader;
class CChainParams;
class CTxMemPool;
class ChainstateManager;
+class TxValidationState;
extern RecursiveMutex cs_main;
extern RecursiveMutex g_cs_orphans;
@@ -27,18 +31,10 @@ static const bool DEFAULT_PEERBLOCKFILTERS = false;
/** Threshold for marking a node to be discouraged, e.g. disconnected and added to the discouragement filter. */
static const int DISCOURAGEMENT_THRESHOLD{100};
-class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface {
-private:
- CConnman& m_connman;
- /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
- BanMan* const m_banman;
- ChainstateManager& m_chainman;
- CTxMemPool& m_mempool;
-
- bool MaybeDiscourageAndDisconnect(CNode& pnode);
-
+class PeerManager final : public CValidationInterface, public NetEventsInterface {
public:
- PeerLogicValidation(CConnman& connman, BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool);
+ PeerManager(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
+ CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool);
/**
* Overridden from CValidationInterface.
@@ -80,7 +76,7 @@ public:
/** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
void ConsiderEviction(CNode& pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound */
- void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams);
+ void CheckForStaleTipAndEvictPeers();
/** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */
void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */
@@ -88,12 +84,58 @@ public:
/** Process a single message from a peer. Public for fuzz testing */
void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
- const std::chrono::microseconds time_received, const CChainParams& chainparams,
- const std::atomic<bool>& interruptMsgProc);
+ const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc);
+
+ /**
+ * Increment peer's misbehavior score. If the new value >= DISCOURAGEMENT_THRESHOLD, mark the node
+ * to be discouraged, meaning the peer might be disconnected and added to the discouragement filter.
+ * Public for unit testing.
+ */
+ void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message);
private:
- int64_t m_stale_tip_check_time; //!< Next time to check for stale tip
+ /**
+ * Potentially mark a node discouraged based on the contents of a BlockValidationState object
+ *
+ * @param[in] via_compact_block this bool is passed in because net_processing should
+ * punish peers differently depending on whether the data was provided in a compact
+ * block message or not. If the compact block had a valid header, but contained invalid
+ * txs, the peer should not be punished. See BIP 152.
+ *
+ * @return Returns true if the peer was punished (probably disconnected)
+ */
+ bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
+ bool via_compact_block, const std::string& message = "");
+ /**
+ * Potentially disconnect and discourage a node based on the contents of a TxValidationState object
+ *
+ * @return Returns true if the peer was punished (probably disconnected)
+ */
+ bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "");
+
+ /** Maybe disconnect a peer and discourage future connections from its address.
+ *
+ * @param[in] pnode The node to check.
+ * @return True if the peer was marked for disconnection in this function
+ */
+ bool MaybeDiscourageAndDisconnect(CNode& pnode);
+
+ void ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn)
+ EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans);
+ /** Process a single headers message from a peer. */
+ void ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHeader>& headers, bool via_compact_block);
+
+ void SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req);
+
+ const CChainParams& m_chainparams;
+ CConnman& m_connman;
+ /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
+ BanMan* const m_banman;
+ ChainstateManager& m_chainman;
+ CTxMemPool& m_mempool;
+
+ int64_t m_stale_tip_check_time; //!< Next time to check for stale tip
};
struct CNodeStateStats {
diff --git a/src/node/context.cpp b/src/node/context.cpp
index 0238aab0d9..49d0c37235 100644
--- a/src/node/context.cpp
+++ b/src/node/context.cpp
@@ -9,6 +9,7 @@
#include <net.h>
#include <net_processing.h>
#include <scheduler.h>
+#include <txmempool.h>
NodeContext::NodeContext() {}
NodeContext::~NodeContext() {}
diff --git a/src/node/context.h b/src/node/context.h
index 793c9dfc34..3228831ed1 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -16,7 +16,7 @@ class CConnman;
class CScheduler;
class CTxMemPool;
class ChainstateManager;
-class PeerLogicValidation;
+class PeerManager;
namespace interfaces {
class Chain;
class ChainClient;
@@ -35,8 +35,8 @@ class WalletClient;
//! be used without pulling in unwanted dependencies or functionality.
struct NodeContext {
std::unique_ptr<CConnman> connman;
- CTxMemPool* mempool{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
- std::unique_ptr<PeerLogicValidation> peer_logic;
+ std::unique_ptr<CTxMemPool> mempool;
+ std::unique_ptr<PeerManager> peerman;
ChainstateManager* chainman{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
std::unique_ptr<BanMan> banman;
ArgsManager* args{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 5633abe817..9ae4700743 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -38,8 +38,8 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
if (!node.mempool->exists(hashTx)) {
// Transaction is not already in the mempool. Submit it.
TxValidationState state;
- if (!AcceptToMemoryPool(*node.mempool, state, std::move(tx),
- nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
+ if (!AcceptToMemoryPool(*node.mempool, state, tx,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
err_string = state.ToString();
if (state.IsInvalid()) {
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
@@ -80,7 +80,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
if (relay) {
// the mempool tracks locally submitted transactions to make a
// best-effort of initial broadcast
- node.mempool->AddUnbroadcastTx(hashTx, tx->GetWitnessHash());
+ node.mempool->AddUnbroadcastTx(hashTx);
LOCK(cs_main);
RelayTransaction(hashTx, tx->GetWitnessHash(), *node.connman);
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index f8b17d18d5..4b55934891 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -36,3 +36,9 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
}
return RBFTransactionState::FINAL;
}
+
+RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx)
+{
+ // If we don't have a local mempool we can only check the transaction itself.
+ return SignalsOptInRBF(tx) ? RBFTransactionState::REPLACEABLE_BIP125 : RBFTransactionState::UNKNOWN;
+}
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index d335fbbb36..f84e6e5286 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -7,16 +7,28 @@
#include <txmempool.h>
+/** The rbf state of unconfirmed transactions */
enum class RBFTransactionState {
+ /** Unconfirmed tx that does not signal rbf and is not in the mempool */
UNKNOWN,
+ /** Either this tx or a mempool ancestor signals rbf */
REPLACEABLE_BIP125,
- FINAL
+ /** Neither this tx nor a mempool ancestor signals rbf */
+ FINAL,
};
-// Determine whether an in-mempool transaction is signaling opt-in to RBF
-// according to BIP 125
-// This involves checking sequence numbers of the transaction, as well
-// as the sequence numbers of all in-mempool ancestors.
+/**
+ * Determine whether an unconfirmed transaction is signaling opt-in to RBF
+ * according to BIP 125
+ * This involves checking sequence numbers of the transaction, as well
+ * as the sequence numbers of all in-mempool ancestors.
+ *
+ * @param tx The unconfirmed transaction
+ * @param pool The mempool, which may contain the tx
+ *
+ * @return The rbf state
+ */
RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
+RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx);
#endif // BITCOIN_POLICY_RBF_H
diff --git a/src/protocol.cpp b/src/protocol.cpp
index c989aa3902..48ca0c6df6 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -8,10 +8,6 @@
#include <util/strencodings.h>
#include <util/system.h>
-#ifndef WIN32
-# include <arpa/inet.h>
-#endif
-
static std::atomic<bool> g_initial_block_download_completed(false);
namespace NetMsgType {
@@ -163,7 +159,7 @@ CInv::CInv()
hash.SetNull();
}
-CInv::CInv(int typeIn, const uint256& hashIn) : type(typeIn), hash(hashIn) {}
+CInv::CInv(uint32_t typeIn, const uint256& hashIn) : type(typeIn), hash(hashIn) {}
bool operator<(const CInv& a, const CInv& b)
{
diff --git a/src/protocol.h b/src/protocol.h
index 2e6c767cdd..7fb84cddf1 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -247,7 +247,7 @@ extern const char* CFCHECKPT;
* txid.
* @since protocol version 70016 as described by BIP 339.
*/
-extern const char *WTXIDRELAY;
+extern const char* WTXIDRELAY;
}; // namespace NetMsgType
/* Get a vector of all valid message types (see above) */
@@ -408,7 +408,7 @@ class CInv
{
public:
CInv();
- CInv(int typeIn, const uint256& hashIn);
+ CInv(uint32_t typeIn, const uint256& hashIn);
SERIALIZE_METHODS(CInv, obj) { READWRITE(obj.type, obj.hash); }
@@ -418,14 +418,24 @@ public:
std::string ToString() const;
// Single-message helper methods
- bool IsMsgTx() const { return type == MSG_TX; }
- bool IsMsgWtx() const { return type == MSG_WTX; }
- bool IsMsgWitnessTx() const { return type == MSG_WITNESS_TX; }
+ bool IsMsgTx() const { return type == MSG_TX; }
+ bool IsMsgBlk() const { return type == MSG_BLOCK; }
+ bool IsMsgWtx() const { return type == MSG_WTX; }
+ bool IsMsgFilteredBlk() const { return type == MSG_FILTERED_BLOCK; }
+ bool IsMsgCmpctBlk() const { return type == MSG_CMPCT_BLOCK; }
+ bool IsMsgWitnessBlk() const { return type == MSG_WITNESS_BLOCK; }
// Combined-message helper methods
- bool IsGenTxMsg() const { return type == MSG_TX || type == MSG_WTX || type == MSG_WITNESS_TX; }
+ bool IsGenTxMsg() const
+ {
+ return type == MSG_TX || type == MSG_WTX || type == MSG_WITNESS_TX;
+ }
+ bool IsGenBlkMsg() const
+ {
+ return type == MSG_BLOCK || type == MSG_FILTERED_BLOCK || type == MSG_CMPCT_BLOCK || type == MSG_WITNESS_BLOCK;
+ }
- int type;
+ uint32_t type;
uint256 hash;
};
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index eaaaaeb904..7a3fb420cc 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -166,8 +166,8 @@ void BitcoinCore::initialize()
{
try
{
- qDebug() << __func__ << ": Running initialization in thread";
util::ThreadRename("qt-init");
+ qDebug() << __func__ << ": Running initialization in thread";
interfaces::BlockAndHeaderTipInfo tip_info;
bool rv = m_node.appInitMain(&tip_info);
Q_EMIT initializeResult(rv, tip_info);
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index aa58c0b10e..0c2dcc3584 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -660,6 +660,11 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
}
}
+WalletController* BitcoinGUI::getWalletController()
+{
+ return m_wallet_controller;
+}
+
void BitcoinGUI::addWallet(WalletModel* walletModel)
{
if (!walletFrame) return;
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 4c55f28693..912297a74e 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -79,6 +79,7 @@ public:
void setClientModel(ClientModel *clientModel = nullptr, interfaces::BlockAndHeaderTipInfo* tip_info = nullptr);
#ifdef ENABLE_WALLET
void setWalletController(WalletController* wallet_controller);
+ WalletController* getWalletController();
#endif
#ifdef ENABLE_WALLET
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 7822d4c5f3..a2f46c339b 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -15,6 +15,7 @@
#include <net.h>
#include <netbase.h>
#include <util/system.h>
+#include <util/threadnames.h>
#include <validation.h>
#include <stdint.h>
@@ -52,6 +53,9 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO
// move timer to thread so that polling doesn't disturb main event loop
timer->moveToThread(m_thread);
m_thread->start();
+ QTimer::singleShot(0, timer, []() {
+ util::ThreadRename("qt-clientmodl");
+ });
subscribeToCoreSignals();
}
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index 9457ea37d6..882d2c8f52 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -46,6 +46,7 @@ static const int TOOLTIP_WRAP_THRESHOLD = 80;
#define QAPP_ORG_DOMAIN "bitcoin.org"
#define QAPP_APP_NAME_DEFAULT "Bitcoin-Qt"
#define QAPP_APP_NAME_TESTNET "Bitcoin-Qt-testnet"
+#define QAPP_APP_NAME_SIGNET "Bitcoin-Qt-signet"
#define QAPP_APP_NAME_REGTEST "Bitcoin-Qt-regtest"
/* One gigabyte (GB) in bytes */
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index 3a251e0573..b1081f6aee 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -19,7 +19,8 @@ static const struct {
} network_styles[] = {
{"main", QAPP_APP_NAME_DEFAULT, 0, 0},
{"test", QAPP_APP_NAME_TESTNET, 70, 30},
- {"regtest", QAPP_APP_NAME_REGTEST, 160, 30}
+ {"signet", QAPP_APP_NAME_SIGNET, 35, 15},
+ {"regtest", QAPP_APP_NAME_REGTEST, 160, 30},
};
static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles);
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index a14fae6460..4c5601242e 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -20,6 +20,7 @@
#include <rpc/client.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/threadnames.h>
#include <univalue.h>
@@ -978,6 +979,9 @@ void RPCConsole::startExecutor()
// Default implementation of QThread::run() simply spins up an event loop in the thread,
// which is what we want.
thread.start();
+ QTimer::singleShot(0, executor, []() {
+ util::ThreadRename("qt-rpcconsole");
+ });
}
void RPCConsole::on_tabWidget_currentChanged(int index)
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 84f981dff3..35fcb2b0ca 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -61,7 +61,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
{
TestChain100Setup test;
node.setContext(&test.m_node);
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), CreateMockWalletDatabase());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
bool firstRun;
wallet->LoadWallet(firstRun);
@@ -112,7 +112,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
ClientModel clientModel(node, &optionsModel);
AddWallet(wallet);
WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get());
- RemoveWallet(wallet);
+ RemoveWallet(wallet, nullopt);
EditAddressDialog editAddressDialog(EditAddressDialog::NewSendingAddress);
editAddressDialog.setModel(walletModel.getAddressTableModel());
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index adcfe0d25c..d6d2d0e3df 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -139,7 +139,7 @@ void TestGUI(interfaces::Node& node)
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
}
node.setContext(&test.m_node);
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), CreateMockWalletDatabase());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
bool firstRun;
wallet->LoadWallet(firstRun);
{
@@ -167,7 +167,7 @@ void TestGUI(interfaces::Node& node)
ClientModel clientModel(node, &optionsModel);
AddWallet(wallet);
WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get());
- RemoveWallet(wallet);
+ RemoveWallet(wallet, nullopt);
sendCoinsDialog.setModel(&walletModel);
transactionView.setModel(&walletModel);
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 828f84ffcc..d9e0274d01 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -14,6 +14,7 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <util/string.h>
+#include <util/threadnames.h>
#include <util/translation.h>
#include <wallet/wallet.h>
@@ -45,6 +46,9 @@ WalletController::WalletController(ClientModel& client_model, const PlatformStyl
m_activity_worker->moveToThread(m_activity_thread);
m_activity_thread->start();
+ QTimer::singleShot(0, m_activity_worker, []() {
+ util::ThreadRename("qt-walletctrl");
+ });
}
// Not using the default destructor because not all member types definitions are
@@ -249,10 +253,9 @@ void CreateWalletActivity::createWallet()
}
QTimer::singleShot(500, worker(), [this, name, flags] {
- WalletCreationStatus status;
- std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().createWallet(name, m_passphrase, flags, status, m_error_message, m_warning_message);
+ std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message);
- if (status == WalletCreationStatus::SUCCESS) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
+ if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
QTimer::singleShot(500, this, &CreateWalletActivity::finish);
});
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index ec56f2755f..f16761d6b2 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -2,6 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <qt/createwalletdialog.h>
+#include <qt/walletcontroller.h>
#include <qt/walletframe.h>
#include <qt/walletmodel.h>
@@ -10,8 +12,11 @@
#include <cassert>
+#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
+#include <QPushButton>
+#include <QVBoxLayout>
WalletFrame::WalletFrame(const PlatformStyle *_platformStyle, BitcoinGUI *_gui) :
QFrame(_gui),
@@ -25,9 +30,25 @@ WalletFrame::WalletFrame(const PlatformStyle *_platformStyle, BitcoinGUI *_gui)
walletFrameLayout->setContentsMargins(0,0,0,0);
walletFrameLayout->addWidget(walletStack);
- QLabel *noWallet = new QLabel(tr("No wallet has been loaded."));
+ // hbox for no wallet
+ QGroupBox* no_wallet_group = new QGroupBox(walletStack);
+ QVBoxLayout* no_wallet_layout = new QVBoxLayout(no_wallet_group);
+
+ QLabel *noWallet = new QLabel(tr("No wallet has been loaded.\nGo to File > Open Wallet to load a wallet.\n- OR -"));
noWallet->setAlignment(Qt::AlignCenter);
- walletStack->addWidget(noWallet);
+ no_wallet_layout->addWidget(noWallet, 0, Qt::AlignHCenter | Qt::AlignBottom);
+
+ // A button for create wallet dialog
+ QPushButton* create_wallet_button = new QPushButton(tr("Create a new wallet"), walletStack);
+ connect(create_wallet_button, &QPushButton::clicked, [this] {
+ auto activity = new CreateWalletActivity(gui->getWalletController(), this);
+ connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater);
+ activity->create();
+ });
+ no_wallet_layout->addWidget(create_wallet_button, 0, Qt::AlignHCenter | Qt::AlignTop);
+ no_wallet_group->setLayout(no_wallet_layout);
+
+ walletStack->addWidget(no_wallet_group);
}
WalletFrame::~WalletFrame()
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 0556895948..6a3f903206 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -413,7 +413,7 @@ void WalletModel::subscribeToCoreSignals()
m_handler_transaction_changed = m_wallet->handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2));
m_handler_show_progress = m_wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(std::bind(NotifyWatchonlyChanged, this, std::placeholders::_1));
- m_handler_can_get_addrs_changed = m_wallet->handleCanGetAddressesChanged(boost::bind(NotifyCanGetAddressesChanged, this));
+ m_handler_can_get_addrs_changed = m_wallet->handleCanGetAddressesChanged(std::bind(NotifyCanGetAddressesChanged, this));
}
void WalletModel::unsubscribeFromCoreSignals()
diff --git a/src/rest.cpp b/src/rest.cpp
index 4e7ba15fe2..949cc9d84a 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -102,7 +102,7 @@ static CTxMemPool* GetMemPool(const util::Ref& context, HTTPRequest* req)
RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found");
return nullptr;
}
- return node->mempool;
+ return node->mempool.get();
}
static RetFormat ParseDataFormat(std::string& param, const std::string& strReq)
@@ -393,7 +393,7 @@ static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::strin
const NodeContext* const node = GetNodeContext(context, req);
if (!node) return false;
uint256 hashBlock = uint256();
- const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, node->mempool, hash, Params().GetConsensus(), hashBlock);
+ const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, node->mempool.get(), hash, Params().GetConsensus(), hashBlock);
if (!tx) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 37a2e4c467..9b464bee72 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -480,9 +480,9 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
UniValue spent(UniValue::VARR);
const CTxMemPool::txiter& it = pool.mapTx.find(tx.GetHash());
- const CTxMemPool::setEntries& setChildren = pool.GetMemPoolChildren(it);
- for (CTxMemPool::txiter childiter : setChildren) {
- spent.push_back(childiter->GetTx().GetHash().ToString());
+ const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst();
+ for (const CTxMemPoolEntry& child : children) {
+ spent.push_back(child.GetTx().GetHash().ToString());
}
info.pushKV("spentby", spent);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 4d08671bd2..6ef3294132 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -125,6 +125,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "gettxoutproof", 0, "txids" },
{ "lockunspent", 0, "unlock" },
{ "lockunspent", 1, "transactions" },
+ { "send", 0, "outputs" },
+ { "send", 1, "conf_target" },
+ { "send", 3, "options" },
{ "importprivkey", 2, "rescan" },
{ "importaddress", 2, "rescan" },
{ "importaddress", 3, "p2sh" },
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 7e2052c7cb..5af4389857 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -414,7 +414,7 @@ static UniValue getnettotals(const JSONRPCRequest& request)
{
{RPCResult::Type::NUM, "totalbytesrecv", "Total bytes received"},
{RPCResult::Type::NUM, "totalbytessent", "Total bytes sent"},
- {RPCResult::Type::NUM_TIME, "timemillis", "Current UNIX time in milliseconds"},
+ {RPCResult::Type::NUM_TIME, "timemillis", "Current " + UNIX_EPOCH_TIME + " in milliseconds"},
{RPCResult::Type::OBJ, "uploadtarget", "",
{
{RPCResult::Type::NUM, "timeframe", "Length of the measuring timeframe in seconds"},
@@ -490,7 +490,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
}},
{RPCResult::Type::BOOL, "localrelay", "true if transaction relay is requested from peers"},
{RPCResult::Type::NUM, "timeoffset", "the time offset"},
- {RPCResult::Type::NUM, "connections", "the number of connections"},
+ {RPCResult::Type::NUM, "connections", "the total number of connections"},
+ {RPCResult::Type::NUM, "connections_in", "the number of inbound connections"},
+ {RPCResult::Type::NUM, "connections_out", "the number of outbound connections"},
{RPCResult::Type::BOOL, "networkactive", "whether p2p networking is enabled"},
{RPCResult::Type::ARR, "networks", "information per network",
{
@@ -538,7 +540,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
obj.pushKV("timeoffset", GetTimeOffset());
if (node.connman) {
obj.pushKV("networkactive", node.connman->GetNetworkActive());
- obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
+ obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
+ obj.pushKV("connections_in", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_IN));
+ obj.pushKV("connections_out", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_OUT));
}
obj.pushKV("networks", GetNetworksInfo());
obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 05ba5e9406..e60e0a2d90 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -191,7 +191,7 @@ static RPCHelpMan getrawtransaction()
}
uint256 hash_block;
- const CTransactionRef tx = GetTransaction(blockindex, node.mempool, hash, Params().GetConsensus(), hash_block);
+ const CTransactionRef tx = GetTransaction(blockindex, node.mempool.get(), hash, Params().GetConsensus(), hash_block);
if (!tx) {
std::string errmsg;
if (blockindex) {
@@ -639,7 +639,7 @@ static RPCHelpMan combinerawtransaction()
{
{"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The hex strings of partially signed transactions",
{
- {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
+ {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A hex-encoded raw transaction"},
},
},
},
@@ -896,6 +896,11 @@ static RPCHelpMan testmempoolaccept()
{
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
{RPCResult::Type::BOOL, "allowed", "If the mempool allows this tx to be inserted"},
+ {RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
+ {RPCResult::Type::OBJ, "fees", "Transaction fees (only present if 'allowed' is true)",
+ {
+ {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
+ }},
{RPCResult::Type::STR, "reject-reason", "Rejection string (only present when 'allowed' is false)"},
}},
}
@@ -942,13 +947,22 @@ static RPCHelpMan testmempoolaccept()
TxValidationState state;
bool test_accept_res;
+ CAmount fee;
{
LOCK(cs_main);
test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx),
- nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true);
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true, &fee);
}
result_0.pushKV("allowed", test_accept_res);
- if (!test_accept_res) {
+
+ // Only return the fee and vsize if the transaction would pass ATMP.
+ // These can be used to calculate the feerate.
+ if (test_accept_res) {
+ result_0.pushKV("vsize", virtual_size);
+ UniValue fees(UniValue::VOBJ);
+ fees.pushKV("base", ValueFromAmount(fee));
+ result_0.pushKV("fees", fees);
+ } else {
if (state.IsInvalid()) {
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
result_0.pushKV("reject-reason", "missing-inputs");
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 1031716b4a..cfe4575090 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -21,10 +21,15 @@
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
{
- if (inputs_in.isNull() || outputs_in.isNull())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
+ if (outputs_in.isNull())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
+
+ UniValue inputs;
+ if (inputs_in.isNull())
+ inputs = UniValue::VARR;
+ else
+ inputs = inputs_in.get_array();
- UniValue inputs = inputs_in.get_array();
const bool outputs_is_obj = outputs_in.isObject();
UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index cb4331aa90..ccdef02b29 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -1,9 +1,9 @@
bench_inv
bench_ecdh
bench_ecmult
+bench_schnorrsig
bench_sign
bench_verify
-bench_schnorr_verify
bench_recover
bench_internal
tests
@@ -31,6 +31,8 @@ libtool
*.lo
*.o
*~
+*.log
+*.trs
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
src/ecmult_static_context.h
diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml
index a6ad6fb27e..e1a88c4051 100644
--- a/src/secp256k1/.travis.yml
+++ b/src/secp256k1/.travis.yml
@@ -17,19 +17,19 @@ compiler:
- gcc
env:
global:
- - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2
+ - WIDEMUL=auto BIGNUM=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no SCHNORRSIG=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2
matrix:
- - SCALAR=32bit RECOVERY=yes
- - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
- - SCALAR=64bit
- - FIELD=64bit RECOVERY=yes
- - FIELD=64bit ENDOMORPHISM=yes
- - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
- - FIELD=64bit ASM=x86_64
- - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- - FIELD=32bit ENDOMORPHISM=yes
+ - WIDEMUL=int64 RECOVERY=yes
+ - WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes
+ - WIDEMUL=int64 ENDOMORPHISM=yes
+ - WIDEMUL=int128
+ - WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes
+ - WIDEMUL=int128 ENDOMORPHISM=yes
+ - WIDEMUL=int128 ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes
+ - WIDEMUL=int128 ASM=x86_64
+ - WIDEMUL=int128 ENDOMORPHISM=yes ASM=x86_64
- BIGNUM=no
- - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
+ - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck CTIMETEST= BENCH=
- CPPFLAGS=-DDETERMINISTIC
@@ -83,6 +83,10 @@ matrix:
- valgrind
- libtool-bin
- libc6-dbg:i386
+ # S390x build (big endian system)
+ - compiler: gcc
+ env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes CTIMETEST=
+ arch: s390x
# We use this to install macOS dependencies instead of the built in `homebrew` plugin,
# because in xcode earlier than 11 they have a bug requiring updating the system which overall takes ~8 minutes.
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index d8c1c79e8c..023fa6067f 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -34,9 +34,11 @@ noinst_HEADERS += src/field_5x52.h
noinst_HEADERS += src/field_5x52_impl.h
noinst_HEADERS += src/field_5x52_int128_impl.h
noinst_HEADERS += src/field_5x52_asm_impl.h
+noinst_HEADERS += src/assumptions.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/scratch.h
noinst_HEADERS += src/scratch_impl.h
+noinst_HEADERS += src/selftest.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
noinst_HEADERS += src/hash.h
@@ -99,7 +101,7 @@ if VALGRIND_ENABLED
tests_CPPFLAGS += -DVALGRIND
noinst_PROGRAMS += valgrind_ctime_test
valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
-valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
+valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_LIBS) $(COMMON_LIB)
endif
if !ENABLE_COVERAGE
tests_CPPFLAGS += -DVERIFY
@@ -152,3 +154,11 @@ endif
if ENABLE_MODULE_RECOVERY
include src/modules/recovery/Makefile.am.include
endif
+
+if ENABLE_MODULE_EXTRAKEYS
+include src/modules/extrakeys/Makefile.am.include
+endif
+
+if ENABLE_MODULE_SCHNORRSIG
+include src/modules/schnorrsig/Makefile.am.include
+endif
diff --git a/src/secp256k1/TODO b/src/secp256k1/TODO
deleted file mode 100644
index a300e1c5eb..0000000000
--- a/src/secp256k1/TODO
+++ /dev/null
@@ -1,3 +0,0 @@
-* Unit tests for fieldelem/groupelem, including ones intended to
- trigger fieldelem's boundary cases.
-* Complete constant-time operations for signing/keygen
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index 1b2b71e6ab..57595f4499 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -1,8 +1,3 @@
-dnl libsecp25k1 helper checks
-AC_DEFUN([SECP_INT128_CHECK],[
-has_int128=$ac_cv_type___int128
-])
-
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 6021b760b5..6fe8984f4d 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -136,20 +136,28 @@ AC_ARG_ENABLE(module_recovery,
[enable_module_recovery=$enableval],
[enable_module_recovery=no])
+AC_ARG_ENABLE(module_extrakeys,
+ AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module (experimental)]),
+ [enable_module_extrakeys=$enableval],
+ [enable_module_extrakeys=no])
+
+AC_ARG_ENABLE(module_schnorrsig,
+ AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
+ [enable_module_schnorrsig=$enableval],
+ [enable_module_schnorrsig=no])
+
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
[use_external_default_callbacks=$enableval],
[use_external_default_callbacks=no])
-AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
-[finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto])
+dnl Test-only override of the (autodetected by the C code) "widemul" setting.
+dnl Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
+AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
[bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto])
-AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
-[scalar implementation to use [default=auto]])],[req_scalar=$withval], [req_scalar=auto])
-
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
@@ -170,8 +178,6 @@ AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision
)],
[req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto])
-AC_CHECK_TYPES([__int128])
-
AC_CHECK_HEADER([valgrind/memcheck.h], [enable_valgrind=yes], [enable_valgrind=no], [])
AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
@@ -265,63 +271,6 @@ else
esac
fi
-if test x"$req_field" = x"auto"; then
- if test x"set_asm" = x"x86_64"; then
- set_field=64bit
- fi
- if test x"$set_field" = x; then
- SECP_INT128_CHECK
- if test x"$has_int128" = x"yes"; then
- set_field=64bit
- fi
- fi
- if test x"$set_field" = x; then
- set_field=32bit
- fi
-else
- set_field=$req_field
- case $set_field in
- 64bit)
- if test x"$set_asm" != x"x86_64"; then
- SECP_INT128_CHECK
- if test x"$has_int128" != x"yes"; then
- AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available])
- fi
- fi
- ;;
- 32bit)
- ;;
- *)
- AC_MSG_ERROR([invalid field implementation selection])
- ;;
- esac
-fi
-
-if test x"$req_scalar" = x"auto"; then
- SECP_INT128_CHECK
- if test x"$has_int128" = x"yes"; then
- set_scalar=64bit
- fi
- if test x"$set_scalar" = x; then
- set_scalar=32bit
- fi
-else
- set_scalar=$req_scalar
- case $set_scalar in
- 64bit)
- SECP_INT128_CHECK
- if test x"$has_int128" != x"yes"; then
- AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available])
- fi
- ;;
- 32bit)
- ;;
- *)
- AC_MSG_ERROR([invalid scalar implementation selected])
- ;;
- esac
-fi
-
if test x"$req_bignum" = x"auto"; then
SECP_GMP_CHECK
if test x"$has_gmp" = x"yes"; then
@@ -365,16 +314,18 @@ no)
;;
esac
-# select field implementation
-case $set_field in
-64bit)
- AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation])
+# select wide multiplication implementation
+case $set_widemul in
+int128)
+ AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation])
+ ;;
+int64)
+ AC_DEFINE(USE_FORCE_WIDEMUL_INT64, 1, [Define this symbol to force the use of the (u)int64_t based wide multiplication implementation])
;;
-32bit)
- AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation])
+auto)
;;
*)
- AC_MSG_ERROR([invalid field implementation])
+ AC_MSG_ERROR([invalid wide multiplication implementation])
;;
esac
@@ -396,19 +347,6 @@ no)
;;
esac
-#select scalar implementation
-case $set_scalar in
-64bit)
- AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation])
- ;;
-32bit)
- AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation])
- ;;
-*)
- AC_MSG_ERROR([invalid scalar implementation])
- ;;
-esac
-
#set ecmult window size
if test x"$req_ecmult_window" = x"auto"; then
set_ecmult_window=15
@@ -493,7 +431,16 @@ if test x"$enable_module_recovery" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
fi
-AC_C_BIGENDIAN()
+if test x"$enable_module_schnorrsig" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
+ enable_module_extrakeys=yes
+fi
+
+# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
+# module to set enable_module_extrakeys=yes
+if test x"$enable_module_extrakeys" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
+fi
if test x"$use_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
@@ -508,11 +455,19 @@ if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([WARNING: experimental build])
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
+ AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
+ AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
AC_MSG_NOTICE([******])
else
if test x"$enable_module_ecdh" = x"yes"; then
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
fi
+ if test x"$enable_module_extrakeys" = x"yes"; then
+ AC_MSG_ERROR([extrakeys module is experimental. Use --enable-experimental to allow.])
+ fi
+ if test x"$enable_module_schnorrsig" = x"yes"; then
+ AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
+ fi
if test x"$set_asm" = x"arm"; then
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
fi
@@ -531,6 +486,8 @@ AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
@@ -550,13 +507,17 @@ echo " with benchmarks = $use_benchmark"
echo " with coverage = $enable_coverage"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
+echo " module extrakeys = $enable_module_extrakeys"
+echo " module schnorrsig = $enable_module_schnorrsig"
echo
echo " asm = $set_asm"
echo " bignum = $set_bignum"
-echo " field = $set_field"
-echo " scalar = $set_scalar"
echo " ecmult window size = $set_ecmult_window"
echo " ecmult gen prec. bits = $set_ecmult_gen_precision"
+dnl Hide test-only options unless they're used.
+if test x"$set_widemul" != xauto; then
+echo " wide multiplication = $set_widemul"
+fi
echo
echo " valgrind = $enable_valgrind"
echo " CC = $CC"
diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/src/secp256k1/contrib/lax_der_parsing.c
index e177a0562d..f71db4b535 100644
--- a/src/secp256k1/contrib/lax_der_parsing.c
+++ b/src/secp256k1/contrib/lax_der_parsing.c
@@ -112,7 +112,6 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
return 0;
}
spos = pos;
- pos += slen;
/* Ignore leading zeroes in R */
while (rlen > 0 && input[rpos] == 0) {
diff --git a/src/secp256k1/contrib/travis.sh b/src/secp256k1/contrib/travis.sh
index 3909d16a27..b0b55b44b8 100755
--- a/src/secp256k1/contrib/travis.sh
+++ b/src/secp256k1/contrib/travis.sh
@@ -3,10 +3,6 @@
set -e
set -x
-if [ -n "$HOST" ]
-then
- export USE_HOST="--host=$HOST"
-fi
if [ "$HOST" = "i686-linux-gnu" ]
then
export CC="$CC -m32"
@@ -18,9 +14,11 @@ fi
./configure \
--enable-experimental="$EXPERIMENTAL" --enable-endomorphism="$ENDOMORPHISM" \
- --with-field="$FIELD" --with-bignum="$BIGNUM" --with-asm="$ASM" --with-scalar="$SCALAR" \
+ --with-test-override-wide-multiply="$WIDEMUL" --with-bignum="$BIGNUM" --with-asm="$ASM" \
--enable-ecmult-static-precomputation="$STATICPRECOMPUTATION" --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
- --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" "$EXTRAFLAGS" "$USE_HOST"
+ --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
+ --enable-module-schnorrsig="$SCHNORRSIG" \
+ --host="$HOST" $EXTRAFLAGS
if [ -n "$BUILD" ]
then
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 2ba2dca388..2178c8e2d6 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -134,7 +134,7 @@ typedef int (*secp256k1_nonce_function)(
# else
# define SECP256K1_API
# endif
-# elif defined(__GNUC__) && defined(SECP256K1_BUILD)
+# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
# define SECP256K1_API __attribute__ ((visibility ("default")))
# else
# define SECP256K1_API
diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h
new file mode 100644
index 0000000000..0c5dff2c94
--- /dev/null
+++ b/src/secp256k1/include/secp256k1_extrakeys.h
@@ -0,0 +1,236 @@
+#ifndef SECP256K1_EXTRAKEYS_H
+#define SECP256K1_EXTRAKEYS_H
+
+#include "secp256k1.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Opaque data structure that holds a parsed and valid "x-only" public key.
+ * An x-only pubkey encodes a point whose Y coordinate is even. It is
+ * serialized using only its X coordinate (32 bytes). See BIP-340 for more
+ * information about x-only pubkeys.
+ *
+ * The exact representation of data inside is implementation defined and not
+ * guaranteed to be portable between different platforms or versions. It is
+ * however guaranteed to be 64 bytes in size, and can be safely copied/moved.
+ * If you need to convert to a format suitable for storage, transmission, or
+ * comparison, use secp256k1_xonly_pubkey_serialize and
+ * secp256k1_xonly_pubkey_parse.
+ */
+typedef struct {
+ unsigned char data[64];
+} secp256k1_xonly_pubkey;
+
+/** Opaque data structure that holds a keypair consisting of a secret and a
+ * public key.
+ *
+ * The exact representation of data inside is implementation defined and not
+ * guaranteed to be portable between different platforms or versions. It is
+ * however guaranteed to be 96 bytes in size, and can be safely copied/moved.
+ */
+typedef struct {
+ unsigned char data[96];
+} secp256k1_keypair;
+
+/** Parse a 32-byte sequence into a xonly_pubkey object.
+ *
+ * Returns: 1 if the public key was fully valid.
+ * 0 if the public key could not be parsed or is invalid.
+ *
+ * Args: ctx: a secp256k1 context object (cannot be NULL).
+ * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
+ * parsed version of input. If not, it's set to an invalid value.
+ * (cannot be NULL).
+ * In: input32: pointer to a serialized xonly_pubkey (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
+ const secp256k1_context* ctx,
+ secp256k1_xonly_pubkey* pubkey,
+ const unsigned char *input32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Serialize an xonly_pubkey object into a 32-byte sequence.
+ *
+ * Returns: 1 always.
+ *
+ * Args: ctx: a secp256k1 context object (cannot be NULL).
+ * Out: output32: a pointer to a 32-byte array to place the serialized key in
+ * (cannot be NULL).
+ * In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an
+ * initialized public key (cannot be NULL).
+ */
+SECP256K1_API int secp256k1_xonly_pubkey_serialize(
+ const secp256k1_context* ctx,
+ unsigned char *output32,
+ const secp256k1_xonly_pubkey* pubkey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
+ *
+ * Returns: 1 if the public key was successfully converted
+ * 0 otherwise
+ *
+ * Args: ctx: pointer to a context object (cannot be NULL)
+ * Out: xonly_pubkey: pointer to an x-only public key object for placing the
+ * converted public key (cannot be NULL)
+ * pk_parity: pointer to an integer that will be set to 1 if the point
+ * encoded by xonly_pubkey is the negation of the pubkey and
+ * set to 0 otherwise. (can be NULL)
+ * In: pubkey: pointer to a public key that is converted (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
+ const secp256k1_context* ctx,
+ secp256k1_xonly_pubkey *xonly_pubkey,
+ int *pk_parity,
+ const secp256k1_pubkey *pubkey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
+
+/** Tweak an x-only public key by adding the generator multiplied with tweak32
+ * to it.
+ *
+ * Note that the resulting point can not in general be represented by an x-only
+ * pubkey because it may have an odd Y coordinate. Instead, the output_pubkey
+ * is a normal secp256k1_pubkey.
+ *
+ * Returns: 0 if the arguments are invalid or the resulting public key would be
+ * invalid (only when the tweak is the negation of the corresponding
+ * secret key). 1 otherwise.
+ *
+ * Args: ctx: pointer to a context object initialized for verification
+ * (cannot be NULL)
+ * Out: output_pubkey: pointer to a public key to store the result. Will be set
+ * to an invalid value if this function returns 0 (cannot
+ * be NULL)
+ * In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
+ * (cannot be NULL).
+ * tweak32: pointer to a 32-byte tweak. If the tweak is invalid
+ * according to secp256k1_ec_seckey_verify, this function
+ * returns 0. For uniformly random 32-byte arrays the
+ * chance of being invalid is negligible (around 1 in
+ * 2^128) (cannot be NULL).
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *output_pubkey,
+ const secp256k1_xonly_pubkey *internal_pubkey,
+ const unsigned char *tweak32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Checks that a tweaked pubkey is the result of calling
+ * secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32.
+ *
+ * The tweaked pubkey is represented by its 32-byte x-only serialization and
+ * its pk_parity, which can both be obtained by converting the result of
+ * tweak_add to a secp256k1_xonly_pubkey.
+ *
+ * Note that this alone does _not_ verify that the tweaked pubkey is a
+ * commitment. If the tweak is not chosen in a specific way, the tweaked pubkey
+ * can easily be the result of a different internal_pubkey and tweak.
+ *
+ * Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
+ * result of tweaking the internal_pubkey with tweak32. 1 otherwise.
+ * Args: ctx: pointer to a context object initialized for verification
+ * (cannot be NULL)
+ * In: tweaked_pubkey32: pointer to a serialized xonly_pubkey (cannot be NULL)
+ * tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
+ * is passed in as tweaked_pubkey32). This must match the
+ * pk_parity value that is returned when calling
+ * secp256k1_xonly_pubkey with the tweaked pubkey, or
+ * this function will fail.
+ * internal_pubkey: pointer to an x-only public key object to apply the
+ * tweak to (cannot be NULL)
+ * tweak32: pointer to a 32-byte tweak (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
+ const secp256k1_context* ctx,
+ const unsigned char *tweaked_pubkey32,
+ int tweaked_pk_parity,
+ const secp256k1_xonly_pubkey *internal_pubkey,
+ const unsigned char *tweak32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
+
+/** Compute the keypair for a secret key.
+ *
+ * Returns: 1: secret was valid, keypair is ready to use
+ * 0: secret was invalid, try again with a different secret
+ * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
+ * Out: keypair: pointer to the created keypair (cannot be NULL)
+ * In: seckey: pointer to a 32-byte secret key (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
+ const secp256k1_context* ctx,
+ secp256k1_keypair *keypair,
+ const unsigned char *seckey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Get the public key from a keypair.
+ *
+ * Returns: 0 if the arguments are invalid. 1 otherwise.
+ * Args: ctx: pointer to a context object (cannot be NULL)
+ * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
+ * the keypair public key. If not, it's set to an invalid value.
+ * (cannot be NULL)
+ * In: keypair: pointer to a keypair (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey,
+ const secp256k1_keypair *keypair
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Get the x-only public key from a keypair.
+ *
+ * This is the same as calling secp256k1_keypair_pub and then
+ * secp256k1_xonly_pubkey_from_pubkey.
+ *
+ * Returns: 0 if the arguments are invalid. 1 otherwise.
+ * Args: ctx: pointer to a context object (cannot be NULL)
+ * Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
+ * to the keypair public key after converting it to an
+ * xonly_pubkey. If not, it's set to an invalid value (cannot be
+ * NULL).
+ * pk_parity: pointer to an integer that will be set to the pk_parity
+ * argument of secp256k1_xonly_pubkey_from_pubkey (can be NULL).
+ * In: keypair: pointer to a keypair (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
+ const secp256k1_context* ctx,
+ secp256k1_xonly_pubkey *pubkey,
+ int *pk_parity,
+ const secp256k1_keypair *keypair
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
+
+/** Tweak a keypair by adding tweak32 to the secret key and updating the public
+ * key accordingly.
+ *
+ * Calling this function and then secp256k1_keypair_pub results in the same
+ * public key as calling secp256k1_keypair_xonly_pub and then
+ * secp256k1_xonly_pubkey_tweak_add.
+ *
+ * Returns: 0 if the arguments are invalid or the resulting keypair would be
+ * invalid (only when the tweak is the negation of the keypair's
+ * secret key). 1 otherwise.
+ *
+ * Args: ctx: pointer to a context object initialized for verification
+ * (cannot be NULL)
+ * In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
+ * an invalid value if this function returns 0 (cannot be
+ * NULL).
+ * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
+ * to secp256k1_ec_seckey_verify, this function returns 0. For
+ * uniformly random 32-byte arrays the chance of being invalid
+ * is negligible (around 1 in 2^128) (cannot be NULL).
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
+ const secp256k1_context* ctx,
+ secp256k1_keypair *keypair,
+ const unsigned char *tweak32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECP256K1_EXTRAKEYS_H */
diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h
new file mode 100644
index 0000000000..0150cd3395
--- /dev/null
+++ b/src/secp256k1/include/secp256k1_schnorrsig.h
@@ -0,0 +1,111 @@
+#ifndef SECP256K1_SCHNORRSIG_H
+#define SECP256K1_SCHNORRSIG_H
+
+#include "secp256k1.h"
+#include "secp256k1_extrakeys.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** This module implements a variant of Schnorr signatures compliant with
+ * Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1"
+ * (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
+ */
+
+/** A pointer to a function to deterministically generate a nonce.
+ *
+ * Same as secp256k1_nonce function with the exception of accepting an
+ * additional pubkey argument and not requiring an attempt argument. The pubkey
+ * argument can protect signature schemes with key-prefixed challenge hash
+ * inputs against reusing the nonce when signing with the wrong precomputed
+ * pubkey.
+ *
+ * Returns: 1 if a nonce was successfully generated. 0 will cause signing to
+ * return an error.
+ * Out: nonce32: pointer to a 32-byte array to be filled by the function.
+ * In: msg32: the 32-byte message hash being verified (will not be NULL)
+ * key32: pointer to a 32-byte secret key (will not be NULL)
+ * xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
+ * (will not be NULL)
+ * algo16: pointer to a 16-byte array describing the signature
+ * algorithm (will not be NULL).
+ * data: Arbitrary data pointer that is passed through.
+ *
+ * Except for test cases, this function should compute some cryptographic hash of
+ * the message, the key, the pubkey, the algorithm description, and data.
+ */
+typedef int (*secp256k1_nonce_function_hardened)(
+ unsigned char *nonce32,
+ const unsigned char *msg32,
+ const unsigned char *key32,
+ const unsigned char *xonly_pk32,
+ const unsigned char *algo16,
+ void *data
+);
+
+/** An implementation of the nonce generation function as defined in Bitcoin
+ * Improvement Proposal 340 "Schnorr Signatures for secp256k1"
+ * (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
+ *
+ * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
+ * auxiliary random data as defined in BIP-340. If the data pointer is NULL,
+ * schnorrsig_sign does not produce BIP-340 compliant signatures. The algo16
+ * argument must be non-NULL, otherwise the function will fail and return 0.
+ * The hash will be tagged with algo16 after removing all terminating null
+ * bytes. Therefore, to create BIP-340 compliant signatures, algo16 must be set
+ * to "BIP0340/nonce\0\0\0"
+ */
+SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
+
+/** Create a Schnorr signature.
+ *
+ * Does _not_ strictly follow BIP-340 because it does not verify the resulting
+ * signature. Instead, you can manually use secp256k1_schnorrsig_verify and
+ * abort if it fails.
+ *
+ * Otherwise BIP-340 compliant if the noncefp argument is NULL or
+ * secp256k1_nonce_function_bip340 and the ndata argument is 32-byte auxiliary
+ * randomness.
+ *
+ * Returns 1 on success, 0 on failure.
+ * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
+ * Out: sig64: pointer to a 64-byte array to store the serialized signature (cannot be NULL)
+ * In: msg32: the 32-byte message being signed (cannot be NULL)
+ * keypair: pointer to an initialized keypair (cannot be NULL)
+ * noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bip340 is used
+ * ndata: pointer to arbitrary data used by the nonce generation
+ * function (can be NULL). If it is non-NULL and
+ * secp256k1_nonce_function_bip340 is used, then ndata must be a
+ * pointer to 32-byte auxiliary randomness as per BIP-340.
+ */
+SECP256K1_API int secp256k1_schnorrsig_sign(
+ const secp256k1_context* ctx,
+ unsigned char *sig64,
+ const unsigned char *msg32,
+ const secp256k1_keypair *keypair,
+ secp256k1_nonce_function_hardened noncefp,
+ void *ndata
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Verify a Schnorr signature.
+ *
+ * Returns: 1: correct signature
+ * 0: incorrect signature
+ * Args: ctx: a secp256k1 context object, initialized for verification.
+ * In: sig64: pointer to the 64-byte signature to verify (cannot be NULL)
+ * msg32: the 32-byte message being verified (cannot be NULL)
+ * pubkey: pointer to an x-only public key to verify with (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
+ const secp256k1_context* ctx,
+ const unsigned char *sig64,
+ const unsigned char *msg32,
+ const secp256k1_xonly_pubkey *pubkey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECP256K1_SCHNORRSIG_H */
diff --git a/src/secp256k1/src/assumptions.h b/src/secp256k1/src/assumptions.h
new file mode 100644
index 0000000000..f9d4e8e793
--- /dev/null
+++ b/src/secp256k1/src/assumptions.h
@@ -0,0 +1,74 @@
+/**********************************************************************
+ * Copyright (c) 2020 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef SECP256K1_ASSUMPTIONS_H
+#define SECP256K1_ASSUMPTIONS_H
+
+#include "util.h"
+
+/* This library, like most software, relies on a number of compiler implementation defined (but not undefined)
+ behaviours. Although the behaviours we require are essentially universal we test them specifically here to
+ reduce the odds of experiencing an unwelcome surprise.
+*/
+
+struct secp256k1_assumption_checker {
+ /* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not
+ allowed. */
+ int dummy_array[(
+ /* Bytes are 8 bits. */
+ CHAR_BIT == 8 &&
+
+ /* Conversions from unsigned to signed outside of the bounds of the signed type are
+ implementation-defined. Verify that they function as reinterpreting the lower
+ bits of the input in two's complement notation. Do this for conversions:
+ - from uint(N)_t to int(N)_t with negative result
+ - from uint(2N)_t to int(N)_t with negative result
+ - from int(2N)_t to int(N)_t with negative result
+ - from int(2N)_t to int(N)_t with positive result */
+
+ /* To int8_t. */
+ ((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) &&
+ ((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) &&
+ ((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) &&
+ ((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) &&
+
+ /* To int16_t. */
+ ((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) &&
+ ((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) &&
+ ((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) &&
+ ((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) &&
+
+ /* To int32_t. */
+ ((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) &&
+ ((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) &&
+ ((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) &&
+ ((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) &&
+
+ /* To int64_t. */
+ ((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
+#if defined(SECP256K1_WIDEMUL_INT128)
+ ((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
+ (((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
+ (((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
+
+ /* To int128_t. */
+ ((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) &&
+#endif
+
+ /* Right shift on negative signed values is implementation defined. Verify that it
+ acts as a right shift in two's complement with sign extension (i.e duplicating
+ the top bit into newly added bits). */
+ ((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) &&
+ ((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
+ ((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
+ ((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
+#if defined(SECP256K1_WIDEMUL_INT128)
+ ((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
+#endif
+ 1) * 2 - 1];
+};
+
+#endif /* SECP256K1_ASSUMPTIONS_H */
diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h
index e9be39d4ca..83dbe6f25b 100644
--- a/src/secp256k1/src/basic-config.h
+++ b/src/secp256k1/src/basic-config.h
@@ -14,23 +14,20 @@
#undef USE_ENDOMORPHISM
#undef USE_EXTERNAL_ASM
#undef USE_EXTERNAL_DEFAULT_CALLBACKS
-#undef USE_FIELD_10X26
-#undef USE_FIELD_5X52
#undef USE_FIELD_INV_BUILTIN
#undef USE_FIELD_INV_NUM
#undef USE_NUM_GMP
#undef USE_NUM_NONE
-#undef USE_SCALAR_4X64
-#undef USE_SCALAR_8X32
#undef USE_SCALAR_INV_BUILTIN
#undef USE_SCALAR_INV_NUM
+#undef USE_FORCE_WIDEMUL_INT64
+#undef USE_FORCE_WIDEMUL_INT128
#undef ECMULT_WINDOW_SIZE
#define USE_NUM_NONE 1
#define USE_FIELD_INV_BUILTIN 1
#define USE_SCALAR_INV_BUILTIN 1
-#define USE_FIELD_10X26 1
-#define USE_SCALAR_8X32 1
+#define USE_WIDEMUL_64 1
#define ECMULT_WINDOW_SIZE 15
#endif /* USE_BASIC_CONFIG */
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index 20759127d3..9687fe4482 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -7,6 +7,7 @@
#include "include/secp256k1.h"
+#include "assumptions.h"
#include "util.h"
#include "hash_impl.h"
#include "num_impl.h"
@@ -19,10 +20,10 @@
#include "secp256k1.c"
typedef struct {
- secp256k1_scalar scalar_x, scalar_y;
- secp256k1_fe fe_x, fe_y;
- secp256k1_ge ge_x, ge_y;
- secp256k1_gej gej_x, gej_y;
+ secp256k1_scalar scalar[2];
+ secp256k1_fe fe[4];
+ secp256k1_ge ge[2];
+ secp256k1_gej gej[2];
unsigned char data[64];
int wnaf[256];
} bench_inv;
@@ -30,30 +31,53 @@ typedef struct {
void bench_setup(void* arg) {
bench_inv *data = (bench_inv*)arg;
- static const unsigned char init_x[32] = {
- 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
- 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
- 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
- 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
+ static const unsigned char init[4][32] = {
+ /* Initializer for scalar[0], fe[0], first half of data, the X coordinate of ge[0],
+ and the (implied affine) X coordinate of gej[0]. */
+ {
+ 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
+ 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
+ 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
+ 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
+ },
+ /* Initializer for scalar[1], fe[1], first half of data, the X coordinate of ge[1],
+ and the (implied affine) X coordinate of gej[1]. */
+ {
+ 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,
+ 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,
+ 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,
+ 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3
+ },
+ /* Initializer for fe[2] and the Z coordinate of gej[0]. */
+ {
+ 0x3d, 0x2d, 0xef, 0xf4, 0x25, 0x98, 0x4f, 0x5d,
+ 0xe2, 0xca, 0x5f, 0x41, 0x3f, 0x3f, 0xce, 0x44,
+ 0xaa, 0x2c, 0x53, 0x8a, 0xc6, 0x59, 0x1f, 0x38,
+ 0x38, 0x23, 0xe4, 0x11, 0x27, 0xc6, 0xa0, 0xe7
+ },
+ /* Initializer for fe[3] and the Z coordinate of gej[1]. */
+ {
+ 0xbd, 0x21, 0xa5, 0xe1, 0x13, 0x50, 0x73, 0x2e,
+ 0x52, 0x98, 0xc8, 0x9e, 0xab, 0x00, 0xa2, 0x68,
+ 0x43, 0xf5, 0xd7, 0x49, 0x80, 0x72, 0xa7, 0xf3,
+ 0xd7, 0x60, 0xe6, 0xab, 0x90, 0x92, 0xdf, 0xc5
+ }
};
- static const unsigned char init_y[32] = {
- 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,
- 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,
- 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,
- 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3
- };
-
- secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL);
- secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL);
- secp256k1_fe_set_b32(&data->fe_x, init_x);
- secp256k1_fe_set_b32(&data->fe_y, init_y);
- CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0));
- CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1));
- secp256k1_gej_set_ge(&data->gej_x, &data->ge_x);
- secp256k1_gej_set_ge(&data->gej_y, &data->ge_y);
- memcpy(data->data, init_x, 32);
- memcpy(data->data + 32, init_y, 32);
+ secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL);
+ secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL);
+ secp256k1_fe_set_b32(&data->fe[0], init[0]);
+ secp256k1_fe_set_b32(&data->fe[1], init[1]);
+ secp256k1_fe_set_b32(&data->fe[2], init[2]);
+ secp256k1_fe_set_b32(&data->fe[3], init[3]);
+ CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0));
+ CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1));
+ secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]);
+ secp256k1_gej_rescale(&data->gej[0], &data->fe[2]);
+ secp256k1_gej_set_ge(&data->gej[1], &data->ge[1]);
+ secp256k1_gej_rescale(&data->gej[1], &data->fe[3]);
+ memcpy(data->data, init[0], 32);
+ memcpy(data->data + 32, init[1], 32);
}
void bench_scalar_add(void* arg, int iters) {
@@ -61,7 +85,7 @@ void bench_scalar_add(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- j += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(j <= iters);
}
@@ -71,7 +95,7 @@ void bench_scalar_negate(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x);
+ secp256k1_scalar_negate(&data->scalar[0], &data->scalar[0]);
}
}
@@ -80,7 +104,7 @@ void bench_scalar_sqr(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x);
+ secp256k1_scalar_sqr(&data->scalar[0], &data->scalar[0]);
}
}
@@ -89,7 +113,7 @@ void bench_scalar_mul(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ secp256k1_scalar_mul(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
}
@@ -99,8 +123,8 @@ void bench_scalar_split(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_scalar_split_lambda(&data->scalar_x, &data->scalar_y, &data->scalar_x);
- j += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ secp256k1_scalar_split_lambda(&data->scalar[0], &data->scalar[1], &data->scalar[0]);
+ j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(j <= iters);
}
@@ -111,8 +135,8 @@ void bench_scalar_inverse(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x);
- j += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ secp256k1_scalar_inverse(&data->scalar[0], &data->scalar[0]);
+ j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(j <= iters);
}
@@ -122,8 +146,8 @@ void bench_scalar_inverse_var(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x);
- j += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ secp256k1_scalar_inverse_var(&data->scalar[0], &data->scalar[0]);
+ j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(j <= iters);
}
@@ -133,7 +157,7 @@ void bench_field_normalize(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_fe_normalize(&data->fe_x);
+ secp256k1_fe_normalize(&data->fe[0]);
}
}
@@ -142,7 +166,7 @@ void bench_field_normalize_weak(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_fe_normalize_weak(&data->fe_x);
+ secp256k1_fe_normalize_weak(&data->fe[0]);
}
}
@@ -151,7 +175,7 @@ void bench_field_mul(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y);
+ secp256k1_fe_mul(&data->fe[0], &data->fe[0], &data->fe[1]);
}
}
@@ -160,7 +184,7 @@ void bench_field_sqr(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_fe_sqr(&data->fe_x, &data->fe_x);
+ secp256k1_fe_sqr(&data->fe[0], &data->fe[0]);
}
}
@@ -169,8 +193,8 @@ void bench_field_inverse(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_fe_inv(&data->fe_x, &data->fe_x);
- secp256k1_fe_add(&data->fe_x, &data->fe_y);
+ secp256k1_fe_inv(&data->fe[0], &data->fe[0]);
+ secp256k1_fe_add(&data->fe[0], &data->fe[1]);
}
}
@@ -179,8 +203,8 @@ void bench_field_inverse_var(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_fe_inv_var(&data->fe_x, &data->fe_x);
- secp256k1_fe_add(&data->fe_x, &data->fe_y);
+ secp256k1_fe_inv_var(&data->fe[0], &data->fe[0]);
+ secp256k1_fe_add(&data->fe[0], &data->fe[1]);
}
}
@@ -190,9 +214,9 @@ void bench_field_sqrt(void* arg, int iters) {
secp256k1_fe t;
for (i = 0; i < iters; i++) {
- t = data->fe_x;
- j += secp256k1_fe_sqrt(&data->fe_x, &t);
- secp256k1_fe_add(&data->fe_x, &data->fe_y);
+ t = data->fe[0];
+ j += secp256k1_fe_sqrt(&data->fe[0], &t);
+ secp256k1_fe_add(&data->fe[0], &data->fe[1]);
}
CHECK(j <= iters);
}
@@ -202,7 +226,7 @@ void bench_group_double_var(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);
+ secp256k1_gej_double_var(&data->gej[0], &data->gej[0], NULL);
}
}
@@ -211,7 +235,7 @@ void bench_group_add_var(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);
+ secp256k1_gej_add_var(&data->gej[0], &data->gej[0], &data->gej[1], NULL);
}
}
@@ -220,7 +244,7 @@ void bench_group_add_affine(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y);
+ secp256k1_gej_add_ge(&data->gej[0], &data->gej[0], &data->ge[1]);
}
}
@@ -229,7 +253,7 @@ void bench_group_add_affine_var(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL);
+ secp256k1_gej_add_ge_var(&data->gej[0], &data->gej[0], &data->ge[1], NULL);
}
}
@@ -238,9 +262,37 @@ void bench_group_jacobi_var(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- j += secp256k1_gej_has_quad_y_var(&data->gej_x);
+ j += secp256k1_gej_has_quad_y_var(&data->gej[0]);
+ /* Vary the Y and Z coordinates of the input (the X coordinate doesn't matter to
+ secp256k1_gej_has_quad_y_var). Note that the resulting coordinates will
+ generally not correspond to a point on the curve, but this is not a problem
+ for the code being benchmarked here. Adding and normalizing have less
+ overhead than EC operations (which could guarantee the point remains on the
+ curve). */
+ secp256k1_fe_add(&data->gej[0].y, &data->fe[1]);
+ secp256k1_fe_add(&data->gej[0].z, &data->fe[2]);
+ secp256k1_fe_normalize_var(&data->gej[0].y);
+ secp256k1_fe_normalize_var(&data->gej[0].z);
+ }
+ CHECK(j <= iters);
+}
+
+void bench_group_to_affine_var(void* arg, int iters) {
+ int i;
+ bench_inv *data = (bench_inv*)arg;
+
+ for (i = 0; i < iters; ++i) {
+ secp256k1_ge_set_gej_var(&data->ge[1], &data->gej[0]);
+ /* Use the output affine X/Y coordinates to vary the input X/Y/Z coordinates.
+ Similar to bench_group_jacobi_var, this approach does not result in
+ coordinates of points on the curve. */
+ secp256k1_fe_add(&data->gej[0].x, &data->ge[1].y);
+ secp256k1_fe_add(&data->gej[0].y, &data->fe[2]);
+ secp256k1_fe_add(&data->gej[0].z, &data->ge[1].x);
+ secp256k1_fe_normalize_var(&data->gej[0].x);
+ secp256k1_fe_normalize_var(&data->gej[0].y);
+ secp256k1_fe_normalize_var(&data->gej[0].z);
}
- CHECK(j == iters);
}
void bench_ecmult_wnaf(void* arg, int iters) {
@@ -248,8 +300,8 @@ void bench_ecmult_wnaf(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- bits += secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A);
- overflow += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ bits += secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar[0], WINDOW_A);
+ overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(overflow >= 0);
CHECK(bits <= 256*iters);
@@ -260,8 +312,8 @@ void bench_wnaf_const(void* arg, int iters) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
- bits += secp256k1_wnaf_const(data->wnaf, &data->scalar_x, WINDOW_A, 256);
- overflow += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
+ bits += secp256k1_wnaf_const(data->wnaf, &data->scalar[0], WINDOW_A, 256);
+ overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(overflow >= 0);
CHECK(bits <= 256*iters);
@@ -323,14 +375,15 @@ void bench_context_sign(void* arg, int iters) {
void bench_num_jacobi(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
- secp256k1_num nx, norder;
+ secp256k1_num nx, na, norder;
- secp256k1_scalar_get_num(&nx, &data->scalar_x);
+ secp256k1_scalar_get_num(&nx, &data->scalar[0]);
secp256k1_scalar_order_get_num(&norder);
- secp256k1_scalar_get_num(&norder, &data->scalar_y);
+ secp256k1_scalar_get_num(&na, &data->scalar[1]);
for (i = 0; i < iters; i++) {
j += secp256k1_num_jacobi(&nx, &norder);
+ secp256k1_num_add(&nx, &nx, &na);
}
CHECK(j <= iters);
}
@@ -363,6 +416,7 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, iters);
+ if (have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters);
diff --git a/src/secp256k1/src/bench_schnorrsig.c b/src/secp256k1/src/bench_schnorrsig.c
new file mode 100644
index 0000000000..315f5af28e
--- /dev/null
+++ b/src/secp256k1/src/bench_schnorrsig.c
@@ -0,0 +1,102 @@
+/**********************************************************************
+ * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+
+
+#include "include/secp256k1.h"
+#include "include/secp256k1_schnorrsig.h"
+#include "util.h"
+#include "bench.h"
+
+typedef struct {
+ secp256k1_context *ctx;
+ int n;
+
+ const secp256k1_keypair **keypairs;
+ const unsigned char **pk;
+ const unsigned char **sigs;
+ const unsigned char **msgs;
+} bench_schnorrsig_data;
+
+void bench_schnorrsig_sign(void* arg, int iters) {
+ bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
+ int i;
+ unsigned char msg[32] = "benchmarkexamplemessagetemplate";
+ unsigned char sig[64];
+
+ for (i = 0; i < iters; i++) {
+ msg[0] = i;
+ msg[1] = i >> 8;
+ CHECK(secp256k1_schnorrsig_sign(data->ctx, sig, msg, data->keypairs[i], NULL, NULL));
+ }
+}
+
+void bench_schnorrsig_verify(void* arg, int iters) {
+ bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
+ int i;
+
+ for (i = 0; i < iters; i++) {
+ secp256k1_xonly_pubkey pk;
+ CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1);
+ CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk));
+ }
+}
+
+int main(void) {
+ int i;
+ bench_schnorrsig_data data;
+ int iters = get_iters(10000);
+
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
+ data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *));
+ data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
+ data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
+ data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
+
+ for (i = 0; i < iters; i++) {
+ unsigned char sk[32];
+ unsigned char *msg = (unsigned char *)malloc(32);
+ unsigned char *sig = (unsigned char *)malloc(64);
+ secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair));
+ unsigned char *pk_char = (unsigned char *)malloc(32);
+ secp256k1_xonly_pubkey pk;
+ msg[0] = sk[0] = i;
+ msg[1] = sk[1] = i >> 8;
+ msg[2] = sk[2] = i >> 16;
+ msg[3] = sk[3] = i >> 24;
+ memset(&msg[4], 'm', 28);
+ memset(&sk[4], 's', 28);
+
+ data.keypairs[i] = keypair;
+ data.pk[i] = pk_char;
+ data.msgs[i] = msg;
+ data.sigs[i] = sig;
+
+ CHECK(secp256k1_keypair_create(data.ctx, keypair, sk));
+ CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, keypair, NULL, NULL));
+ CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair));
+ CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1);
+ }
+
+ run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters);
+ run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters);
+
+ for (i = 0; i < iters; i++) {
+ free((void *)data.keypairs[i]);
+ free((void *)data.pk[i]);
+ free((void *)data.msgs[i]);
+ free((void *)data.sigs[i]);
+ }
+ free(data.keypairs);
+ free(data.pk);
+ free(data.msgs);
+ free(data.sigs);
+
+ secp256k1_context_destroy(data.ctx);
+ return 0;
+}
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 6d6d354aa4..55b61e4937 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -105,16 +105,22 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
/* 4 */
u_last = secp256k1_scalar_shr_int(&s, w);
do {
- int sign;
int even;
/* 4.1 4.4 */
u = secp256k1_scalar_shr_int(&s, w);
/* 4.2 */
even = ((u & 1) == 0);
- sign = 2 * (u_last > 0) - 1;
- u += sign * even;
- u_last -= sign * even * (1 << w);
+ /* In contrast to the original algorithm, u_last is always > 0 and
+ * therefore we do not need to check its sign. In particular, it's easy
+ * to see that u_last is never < 0 because u is never < 0. Moreover,
+ * u_last is never = 0 because u is never even after a loop
+ * iteration. The same holds analogously for the initial value of
+ * u_last (in the first loop iteration). */
+ VERIFY_CHECK(u_last > 0);
+ VERIFY_CHECK((u_last & 1) == 1);
+ u += even;
+ u_last -= even * (1 << w);
/* 4.3, adapted for global sign change */
wnaf[word++] = u_last * global_sign;
@@ -202,7 +208,7 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
int n;
int j;
for (j = 0; j < WINDOW_A - 1; ++j) {
- secp256k1_gej_double_nonzero(r, r);
+ secp256k1_gej_double(r, r);
}
n = wnaf_1[i];
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 7993a1f11e..aca1fb72c5 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -22,16 +22,16 @@
#include "libsecp256k1-config.h"
#endif
-#if defined(USE_FIELD_10X26)
-#include "field_10x26.h"
-#elif defined(USE_FIELD_5X52)
+#include "util.h"
+
+#if defined(SECP256K1_WIDEMUL_INT128)
#include "field_5x52.h"
+#elif defined(SECP256K1_WIDEMUL_INT64)
+#include "field_10x26.h"
#else
-#error "Please select field implementation"
+#error "Please select wide multiplication implementation"
#endif
-#include "util.h"
-
/** Normalize a field element. This brings the field element to a canonical representation, reduces
* its magnitude to 1, and reduces it modulo field size `p`.
*/
diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h
index fc5bfe357e..6a068484c2 100644
--- a/src/secp256k1/src/field_5x52.h
+++ b/src/secp256k1/src/field_5x52.h
@@ -46,4 +46,10 @@ typedef struct {
(d6) | (((uint64_t)(d7)) << 32) \
}}
+#define SECP256K1_FE_STORAGE_CONST_GET(d) \
+ (uint32_t)(d.n[3] >> 32), (uint32_t)d.n[3], \
+ (uint32_t)(d.n[2] >> 32), (uint32_t)d.n[2], \
+ (uint32_t)(d.n[1] >> 32), (uint32_t)d.n[1], \
+ (uint32_t)(d.n[0] >> 32), (uint32_t)d.n[0]
+
#endif /* SECP256K1_FIELD_REPR_H */
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 485921a60e..18e4d2f30e 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -14,12 +14,12 @@
#include "util.h"
#include "num.h"
-#if defined(USE_FIELD_10X26)
-#include "field_10x26_impl.h"
-#elif defined(USE_FIELD_5X52)
+#if defined(SECP256K1_WIDEMUL_INT128)
#include "field_5x52_impl.h"
+#elif defined(SECP256K1_WIDEMUL_INT64)
+#include "field_10x26_impl.h"
#else
-#error "Please select field implementation"
+#error "Please select wide multiplication implementation"
#endif
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c
index 539f574bfd..8b7729aee4 100644
--- a/src/secp256k1/src/gen_context.c
+++ b/src/secp256k1/src/gen_context.c
@@ -13,6 +13,7 @@
#include "basic-config.h"
#include "include/secp256k1.h"
+#include "assumptions.h"
#include "util.h"
#include "field_impl.h"
#include "scalar_impl.h"
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index 863644f0f0..6185be052d 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -95,8 +95,8 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
/** Check whether a group element's y coordinate is a quadratic residue. */
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
-/** Set r equal to the double of a, a cannot be infinity. Constant time. */
-static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a);
+/** Set r equal to the double of a. Constant time. */
+static void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a);
/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 43b039becf..ccd93d3483 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -303,7 +303,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
return secp256k1_fe_equal_var(&y2, &x3);
}
-static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a) {
+static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
*
* Note that there is an implementation described at
@@ -313,8 +313,7 @@ static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, cons
*/
secp256k1_fe t1,t2,t3,t4;
- VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
- r->infinity = 0;
+ r->infinity = a->infinity;
secp256k1_fe_mul(&r->z, &a->z, &a->y);
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
@@ -363,7 +362,7 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
secp256k1_fe_mul_int(rzr, 2);
}
- secp256k1_gej_double_nonzero(r, a);
+ secp256k1_gej_double(r, a);
}
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
@@ -400,7 +399,7 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
if (rzr != NULL) {
secp256k1_fe_set_int(rzr, 0);
}
- r->infinity = 1;
+ secp256k1_gej_set_infinity(r);
}
return;
}
@@ -450,7 +449,7 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
if (rzr != NULL) {
secp256k1_fe_set_int(rzr, 0);
}
- r->infinity = 1;
+ secp256k1_gej_set_infinity(r);
}
return;
}
@@ -509,7 +508,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
secp256k1_gej_double_var(r, a, NULL);
} else {
- r->infinity = 1;
+ secp256k1_gej_set_infinity(r);
}
return;
}
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index 782f97216c..409772587b 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -8,6 +8,7 @@
#define SECP256K1_HASH_IMPL_H
#include "hash.h"
+#include "util.h"
#include <stdlib.h>
#include <stdint.h>
@@ -27,9 +28,9 @@
(h) = t1 + t2; \
} while(0)
-#ifdef WORDS_BIGENDIAN
+#if defined(SECP256K1_BIG_ENDIAN)
#define BE32(x) (x)
-#else
+#elif defined(SECP256K1_LITTLE_ENDIAN)
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#endif
@@ -163,6 +164,19 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out
memcpy(out32, (const unsigned char*)out, 32);
}
+/* Initializes a sha256 struct and writes the 64 byte string
+ * SHA256(tag)||SHA256(tag) into it. */
+static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) {
+ unsigned char buf[32];
+ secp256k1_sha256_initialize(hash);
+ secp256k1_sha256_write(hash, tag, taglen);
+ secp256k1_sha256_finalize(hash, buf);
+
+ secp256k1_sha256_initialize(hash);
+ secp256k1_sha256_write(hash, buf, 32);
+ secp256k1_sha256_write(hash, buf, 32);
+}
+
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
size_t n;
unsigned char rkey[64];
diff --git a/src/secp256k1/src/modules/extrakeys/Makefile.am.include b/src/secp256k1/src/modules/extrakeys/Makefile.am.include
new file mode 100644
index 0000000000..8515f92e7a
--- /dev/null
+++ b/src/secp256k1/src/modules/extrakeys/Makefile.am.include
@@ -0,0 +1,3 @@
+include_HEADERS += include/secp256k1_extrakeys.h
+noinst_HEADERS += src/modules/extrakeys/tests_impl.h
+noinst_HEADERS += src/modules/extrakeys/main_impl.h
diff --git a/src/secp256k1/src/modules/extrakeys/main_impl.h b/src/secp256k1/src/modules/extrakeys/main_impl.h
new file mode 100644
index 0000000000..d319215355
--- /dev/null
+++ b/src/secp256k1/src/modules/extrakeys/main_impl.h
@@ -0,0 +1,248 @@
+/**********************************************************************
+ * Copyright (c) 2020 Jonas Nick *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_EXTRAKEYS_MAIN_
+#define _SECP256K1_MODULE_EXTRAKEYS_MAIN_
+
+#include "include/secp256k1.h"
+#include "include/secp256k1_extrakeys.h"
+
+static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
+ return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey);
+}
+
+static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) {
+ secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge);
+}
+
+int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) {
+ secp256k1_ge pk;
+ secp256k1_fe x;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+ memset(pubkey, 0, sizeof(*pubkey));
+ ARG_CHECK(input32 != NULL);
+
+ if (!secp256k1_fe_set_b32(&x, input32)) {
+ return 0;
+ }
+ if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {
+ return 0;
+ }
+ secp256k1_xonly_pubkey_save(pubkey, &pk);
+ return 1;
+}
+
+int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) {
+ secp256k1_ge pk;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(output32 != NULL);
+ memset(output32, 0, 32);
+ ARG_CHECK(pubkey != NULL);
+
+ if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
+ return 0;
+ }
+ secp256k1_fe_get_b32(output32, &pk.x);
+ return 1;
+}
+
+/** Keeps a group element as is if it has an even Y and otherwise negates it.
+ * y_parity is set to 0 in the former case and to 1 in the latter case.
+ * Requires that the coordinates of r are normalized. */
+static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) {
+ int y_parity = 0;
+ VERIFY_CHECK(!secp256k1_ge_is_infinity(r));
+
+ if (secp256k1_fe_is_odd(&r->y)) {
+ secp256k1_fe_negate(&r->y, &r->y, 1);
+ y_parity = 1;
+ }
+ return y_parity;
+}
+
+int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) {
+ secp256k1_ge pk;
+ int tmp;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(xonly_pubkey != NULL);
+ ARG_CHECK(pubkey != NULL);
+
+ if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
+ return 0;
+ }
+ tmp = secp256k1_extrakeys_ge_even_y(&pk);
+ if (pk_parity != NULL) {
+ *pk_parity = tmp;
+ }
+ secp256k1_xonly_pubkey_save(xonly_pubkey, &pk);
+ return 1;
+}
+
+int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
+ secp256k1_ge pk;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(output_pubkey != NULL);
+ memset(output_pubkey, 0, sizeof(*output_pubkey));
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(internal_pubkey != NULL);
+ ARG_CHECK(tweak32 != NULL);
+
+ if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
+ || !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) {
+ return 0;
+ }
+ secp256k1_pubkey_save(output_pubkey, &pk);
+ return 1;
+}
+
+int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
+ secp256k1_ge pk;
+ unsigned char pk_expected32[32];
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(internal_pubkey != NULL);
+ ARG_CHECK(tweaked_pubkey32 != NULL);
+ ARG_CHECK(tweak32 != NULL);
+
+ if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
+ || !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) {
+ return 0;
+ }
+ secp256k1_fe_normalize_var(&pk.x);
+ secp256k1_fe_normalize_var(&pk.y);
+ secp256k1_fe_get_b32(pk_expected32, &pk.x);
+
+ return memcmp(&pk_expected32, tweaked_pubkey32, 32) == 0
+ && secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity;
+}
+
+static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) {
+ secp256k1_scalar_get_b32(&keypair->data[0], sk);
+ secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk);
+}
+
+
+static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) {
+ int ret;
+
+ ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]);
+ /* We can declassify ret here because sk is only zero if a keypair function
+ * failed (which zeroes the keypair) and its return value is ignored. */
+ secp256k1_declassify(ctx, &ret, sizeof(ret));
+ ARG_CHECK(ret);
+ return ret;
+}
+
+/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk
+ * and ARG_CHECKs that the keypair is not invalid. It always initializes sk and
+ * pk with dummy values. */
+static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) {
+ int ret;
+ const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32];
+
+ /* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's
+ * invalid. */
+ secp256k1_declassify(ctx, pubkey, sizeof(*pubkey));
+ ret = secp256k1_pubkey_load(ctx, pk, pubkey);
+ if (sk != NULL) {
+ ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair);
+ }
+ if (!ret) {
+ *pk = secp256k1_ge_const_g;
+ if (sk != NULL) {
+ *sk = secp256k1_scalar_one;
+ }
+ }
+ return ret;
+}
+
+int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) {
+ secp256k1_scalar sk;
+ secp256k1_ge pk;
+ int ret = 0;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(keypair != NULL);
+ memset(keypair, 0, sizeof(*keypair));
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(seckey32 != NULL);
+
+ ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32);
+ secp256k1_keypair_save(keypair, &sk, &pk);
+ memczero(keypair, sizeof(*keypair), !ret);
+
+ secp256k1_scalar_clear(&sk);
+ return ret;
+}
+
+int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) {
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+ memset(pubkey, 0, sizeof(*pubkey));
+ ARG_CHECK(keypair != NULL);
+
+ memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey));
+ return 1;
+}
+
+int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) {
+ secp256k1_ge pk;
+ int tmp;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+ memset(pubkey, 0, sizeof(*pubkey));
+ ARG_CHECK(keypair != NULL);
+
+ if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) {
+ return 0;
+ }
+ tmp = secp256k1_extrakeys_ge_even_y(&pk);
+ if (pk_parity != NULL) {
+ *pk_parity = tmp;
+ }
+ secp256k1_xonly_pubkey_save(pubkey, &pk);
+
+ return 1;
+}
+
+int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) {
+ secp256k1_ge pk;
+ secp256k1_scalar sk;
+ int y_parity;
+ int ret;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(keypair != NULL);
+ ARG_CHECK(tweak32 != NULL);
+
+ ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair);
+ memset(keypair, 0, sizeof(*keypair));
+
+ y_parity = secp256k1_extrakeys_ge_even_y(&pk);
+ if (y_parity == 1) {
+ secp256k1_scalar_negate(&sk, &sk);
+ }
+
+ ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32);
+ ret &= secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32);
+
+ secp256k1_declassify(ctx, &ret, sizeof(ret));
+ if (ret) {
+ secp256k1_keypair_save(keypair, &sk, &pk);
+ }
+
+ secp256k1_scalar_clear(&sk);
+ return ret;
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/extrakeys/tests_impl.h b/src/secp256k1/src/modules/extrakeys/tests_impl.h
new file mode 100644
index 0000000000..fc9d40eda1
--- /dev/null
+++ b/src/secp256k1/src/modules/extrakeys/tests_impl.h
@@ -0,0 +1,524 @@
+/**********************************************************************
+ * Copyright (c) 2020 Jonas Nick *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_
+#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_
+
+#include "secp256k1_extrakeys.h"
+
+static secp256k1_context* api_test_context(int flags, int *ecount) {
+ secp256k1_context *ctx0 = secp256k1_context_create(flags);
+ secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount);
+ secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
+ return ctx0;
+}
+
+void test_xonly_pubkey(void) {
+ secp256k1_pubkey pk;
+ secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
+ secp256k1_ge pk1;
+ secp256k1_ge pk2;
+ secp256k1_fe y;
+ unsigned char sk[32];
+ unsigned char xy_sk[32];
+ unsigned char buf32[32];
+ unsigned char ones32[32];
+ unsigned char zeros64[64] = { 0 };
+ int pk_parity;
+ int i;
+
+ int ecount;
+ secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
+ secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
+ secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ secp256k1_rand256(sk);
+ memset(ones32, 0xFF, 32);
+ secp256k1_rand256(xy_sk);
+ CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
+
+ /* Test xonly_pubkey_from_pubkey */
+ ecount = 0;
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0);
+ CHECK(ecount == 2);
+ memset(&pk, 0, sizeof(pk));
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0);
+ CHECK(ecount == 3);
+
+ /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
+ memset(sk, 0, sizeof(sk));
+ sk[0] = 1;
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(memcmp(&pk, &xonly_pk, sizeof(pk)) == 0);
+ CHECK(pk_parity == 0);
+
+ /* Choose a secret key such that pubkey and xonly_pubkey are each others
+ * negation. */
+ sk[0] = 2;
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(memcmp(&xonly_pk, &pk, sizeof(xonly_pk)) != 0);
+ CHECK(pk_parity == 1);
+ secp256k1_pubkey_load(ctx, &pk1, &pk);
+ secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk);
+ CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1);
+ secp256k1_fe_negate(&y, &pk2.y, 1);
+ CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
+
+ /* Test xonly_pubkey_serialize and xonly_pubkey_parse */
+ ecount = 0;
+ CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0);
+ CHECK(memcmp(buf32, zeros64, 32) == 0);
+ CHECK(ecount == 2);
+ {
+ /* A pubkey filled with 0s will fail to serialize due to pubkey_load
+ * special casing. */
+ secp256k1_xonly_pubkey pk_tmp;
+ memset(&pk_tmp, 0, sizeof(pk_tmp));
+ CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &pk_tmp) == 0);
+ }
+ /* pubkey_load called illegal callback */
+ CHECK(ecount == 3);
+
+ CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1);
+ ecount = 0;
+ CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0);
+ CHECK(ecount == 2);
+
+ /* Serialization and parse roundtrip */
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1);
+ CHECK(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0);
+
+ /* Test parsing invalid field elements */
+ memset(&xonly_pk, 1, sizeof(xonly_pk));
+ /* Overflowing field element */
+ CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0);
+ CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
+ memset(&xonly_pk, 1, sizeof(xonly_pk));
+ /* There's no point with x-coordinate 0 on secp256k1 */
+ CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0);
+ CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
+ /* If a random 32-byte string can not be parsed with ec_pubkey_parse
+ * (because interpreted as X coordinate it does not correspond to a point on
+ * the curve) then xonly_pubkey_parse should fail as well. */
+ for (i = 0; i < count; i++) {
+ unsigned char rand33[33];
+ secp256k1_rand256(&rand33[1]);
+ rand33[0] = SECP256K1_TAG_PUBKEY_EVEN;
+ if (!secp256k1_ec_pubkey_parse(ctx, &pk, rand33, 33)) {
+ memset(&xonly_pk, 1, sizeof(xonly_pk));
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0);
+ CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
+ } else {
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1);
+ }
+ }
+ CHECK(ecount == 2);
+
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(verify);
+}
+
+void test_xonly_pubkey_tweak(void) {
+ unsigned char zeros64[64] = { 0 };
+ unsigned char overflows[32];
+ unsigned char sk[32];
+ secp256k1_pubkey internal_pk;
+ secp256k1_xonly_pubkey internal_xonly_pk;
+ secp256k1_pubkey output_pk;
+ int pk_parity;
+ unsigned char tweak[32];
+ int i;
+
+ int ecount;
+ secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
+ secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
+ secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ memset(overflows, 0xff, sizeof(overflows));
+ secp256k1_rand256(tweak);
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
+
+ ecount = 0;
+ CHECK(secp256k1_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0);
+ CHECK(ecount == 4);
+ /* NULL internal_xonly_pk zeroes the output_pk */
+ CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0);
+ CHECK(ecount == 5);
+ /* NULL tweak zeroes the output_pk */
+ CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
+
+ /* Invalid tweak zeroes the output_pk */
+ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0);
+ CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
+
+ /* A zero tweak is fine */
+ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1);
+
+ /* Fails if the resulting key was infinity */
+ for (i = 0; i < count; i++) {
+ secp256k1_scalar scalar_tweak;
+ /* Because sk may be negated before adding, we need to try with tweak =
+ * sk as well as tweak = -sk. */
+ secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
+ secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
+ secp256k1_scalar_get_b32(tweak, &scalar_tweak);
+ CHECK((secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0)
+ || (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0));
+ CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
+ }
+
+ /* Invalid pk with a valid tweak */
+ memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
+ secp256k1_rand256(tweak);
+ ecount = 0;
+ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0);
+ CHECK(ecount == 1);
+ CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
+
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(verify);
+}
+
+void test_xonly_pubkey_tweak_check(void) {
+ unsigned char zeros64[64] = { 0 };
+ unsigned char overflows[32];
+ unsigned char sk[32];
+ secp256k1_pubkey internal_pk;
+ secp256k1_xonly_pubkey internal_xonly_pk;
+ secp256k1_pubkey output_pk;
+ secp256k1_xonly_pubkey output_xonly_pk;
+ unsigned char output_pk32[32];
+ unsigned char buf32[32];
+ int pk_parity;
+ unsigned char tweak[32];
+
+ int ecount;
+ secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
+ secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
+ secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ memset(overflows, 0xff, sizeof(overflows));
+ secp256k1_rand256(tweak);
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
+
+ ecount = 0;
+ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &output_xonly_pk, &pk_parity, &output_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
+ CHECK(ecount == 3);
+ /* invalid pk_parity value */
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
+ CHECK(ecount == 5);
+
+ memset(tweak, 1, sizeof(tweak));
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, NULL, &internal_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk32, &output_xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1);
+
+ /* Wrong pk_parity */
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0);
+ /* Wrong public key */
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &internal_xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
+
+ /* Overflowing tweak not allowed */
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0);
+ CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
+ CHECK(ecount == 5);
+
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(verify);
+}
+
+/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
+ * additional pubkeys by calling tweak_add. Then verifies every tweak starting
+ * from the last pubkey. */
+#define N_PUBKEYS 32
+void test_xonly_pubkey_tweak_recursive(void) {
+ unsigned char sk[32];
+ secp256k1_pubkey pk[N_PUBKEYS];
+ unsigned char pk_serialized[32];
+ unsigned char tweak[N_PUBKEYS - 1][32];
+ int i;
+
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk) == 1);
+ /* Add tweaks */
+ for (i = 0; i < N_PUBKEYS - 1; i++) {
+ secp256k1_xonly_pubkey xonly_pk;
+ memset(tweak[i], i + 1, sizeof(tweak[i]));
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i]) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &xonly_pk, tweak[i]) == 1);
+ }
+
+ /* Verify tweaks */
+ for (i = N_PUBKEYS - 1; i > 0; i--) {
+ secp256k1_xonly_pubkey xonly_pk;
+ int pk_parity;
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk[i]) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_serialized, &xonly_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i - 1]) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1);
+ }
+}
+#undef N_PUBKEYS
+
+void test_keypair(void) {
+ unsigned char sk[32];
+ unsigned char zeros96[96] = { 0 };
+ unsigned char overflows[32];
+ secp256k1_keypair keypair;
+ secp256k1_pubkey pk, pk_tmp;
+ secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
+ int pk_parity, pk_parity_tmp;
+ int ecount;
+ secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
+ secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
+ secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ CHECK(sizeof(zeros96) == sizeof(keypair));
+ memset(overflows, 0xFF, sizeof(overflows));
+
+ /* Test keypair_create */
+ ecount = 0;
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_keypair_create(none, &keypair, sk) == 0);
+ CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 0);
+ CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0);
+ CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
+ CHECK(ecount == 4);
+
+ /* Invalid secret key */
+ CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0);
+ CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
+ CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0);
+ CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
+
+ /* Test keypair_pub */
+ ecount = 0;
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
+ CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0);
+ CHECK(ecount == 2);
+ CHECK(memcmp(zeros96, &pk, sizeof(pk)) == 0);
+
+ /* Using an invalid keypair is fine for keypair_pub */
+ memset(&keypair, 0, sizeof(keypair));
+ CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
+ CHECK(memcmp(zeros96, &pk, sizeof(pk)) == 0);
+
+ /* keypair holds the same pubkey as pubkey_create */
+ CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
+ CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1);
+ CHECK(memcmp(&pk, &pk_tmp, sizeof(pk)) == 0);
+
+ /** Test keypair_xonly_pub **/
+ ecount = 0;
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0);
+ CHECK(ecount == 2);
+ CHECK(memcmp(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
+ /* Using an invalid keypair will set the xonly_pk to 0 (first reset
+ * xonly_pk). */
+ CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
+ memset(&keypair, 0, sizeof(keypair));
+ CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0);
+ CHECK(memcmp(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
+ CHECK(ecount == 3);
+
+ /** keypair holds the same xonly pubkey as pubkey_create **/
+ CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
+ CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
+ CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
+ CHECK(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
+ CHECK(pk_parity == pk_parity_tmp);
+
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(verify);
+}
+
+void test_keypair_add(void) {
+ unsigned char sk[32];
+ secp256k1_keypair keypair;
+ unsigned char overflows[32];
+ unsigned char zeros96[96] = { 0 };
+ unsigned char tweak[32];
+ int i;
+ int ecount = 0;
+ secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
+ secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
+ secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
+
+ CHECK(sizeof(zeros96) == sizeof(keypair));
+ secp256k1_rand256(sk);
+ secp256k1_rand256(tweak);
+ memset(overflows, 0xFF, 32);
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+
+ CHECK(secp256k1_keypair_xonly_tweak_add(none, &keypair, tweak) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(sign, &keypair, tweak) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(verify, NULL, tweak) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0);
+ CHECK(ecount == 4);
+ /* This does not set the keypair to zeroes */
+ CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) != 0);
+
+ /* Invalid tweak zeroes the keypair */
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0);
+ CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0);
+
+ /* A zero tweak is fine */
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, zeros96) == 1);
+
+ /* Fails if the resulting keypair was (sk=0, pk=infinity) */
+ for (i = 0; i < count; i++) {
+ secp256k1_scalar scalar_tweak;
+ secp256k1_keypair keypair_tmp;
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ memcpy(&keypair_tmp, &keypair, sizeof(keypair));
+ /* Because sk may be negated before adding, we need to try with tweak =
+ * sk as well as tweak = -sk. */
+ secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
+ secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
+ secp256k1_scalar_get_b32(tweak, &scalar_tweak);
+ CHECK((secp256k1_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0)
+ || (secp256k1_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0));
+ CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0
+ || memcmp(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0);
+ }
+
+ /* Invalid keypair with a valid tweak */
+ memset(&keypair, 0, sizeof(keypair));
+ secp256k1_rand256(tweak);
+ ecount = 0;
+ CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
+ CHECK(ecount == 1);
+ CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0);
+ /* Only seckey part of keypair invalid */
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ memset(&keypair, 0, 32);
+ CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
+ CHECK(ecount == 2);
+ /* Only pubkey part of keypair invalid */
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ memset(&keypair.data[32], 0, 64);
+ CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
+ CHECK(ecount == 3);
+
+ /* Check that the keypair_tweak_add implementation is correct */
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ for (i = 0; i < count; i++) {
+ secp256k1_xonly_pubkey internal_pk;
+ secp256k1_xonly_pubkey output_pk;
+ secp256k1_pubkey output_pk_xy;
+ secp256k1_pubkey output_pk_expected;
+ unsigned char pk32[32];
+ int pk_parity;
+
+ secp256k1_rand256(tweak);
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1);
+
+ /* Check that it passes xonly_pubkey_tweak_add_check */
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk32, &output_pk) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk32, pk_parity, &internal_pk, tweak) == 1);
+
+ /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */
+ CHECK(secp256k1_keypair_pub(ctx, &output_pk_xy, &keypair) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1);
+ CHECK(memcmp(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
+
+ /* Check that the secret key in the keypair is tweaked correctly */
+ CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, &keypair.data[0]) == 1);
+ CHECK(memcmp(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
+ }
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(verify);
+}
+
+void run_extrakeys_tests(void) {
+ /* xonly key test cases */
+ test_xonly_pubkey();
+ test_xonly_pubkey_tweak();
+ test_xonly_pubkey_tweak_check();
+ test_xonly_pubkey_tweak_recursive();
+
+ /* keypair tests */
+ test_keypair();
+ test_keypair_add();
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/schnorrsig/Makefile.am.include b/src/secp256k1/src/modules/schnorrsig/Makefile.am.include
new file mode 100644
index 0000000000..a82bafe43f
--- /dev/null
+++ b/src/secp256k1/src/modules/schnorrsig/Makefile.am.include
@@ -0,0 +1,8 @@
+include_HEADERS += include/secp256k1_schnorrsig.h
+noinst_HEADERS += src/modules/schnorrsig/main_impl.h
+noinst_HEADERS += src/modules/schnorrsig/tests_impl.h
+if USE_BENCHMARK
+noinst_PROGRAMS += bench_schnorrsig
+bench_schnorrsig_SOURCES = src/bench_schnorrsig.c
+bench_schnorrsig_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
+endif
diff --git a/src/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h
new file mode 100644
index 0000000000..a0218f881a
--- /dev/null
+++ b/src/secp256k1/src/modules/schnorrsig/main_impl.h
@@ -0,0 +1,238 @@
+/**********************************************************************
+ * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_SCHNORRSIG_MAIN_
+#define _SECP256K1_MODULE_SCHNORRSIG_MAIN_
+
+#include "include/secp256k1.h"
+#include "include/secp256k1_schnorrsig.h"
+#include "hash.h"
+
+/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
+ * SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */
+static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) {
+ secp256k1_sha256_initialize(sha);
+ sha->s[0] = 0x46615b35ul;
+ sha->s[1] = 0xf4bfbff7ul;
+ sha->s[2] = 0x9f8dc671ul;
+ sha->s[3] = 0x83627ab3ul;
+ sha->s[4] = 0x60217180ul;
+ sha->s[5] = 0x57358661ul;
+ sha->s[6] = 0x21a29e54ul;
+ sha->s[7] = 0x68b07b4cul;
+
+ sha->bytes = 64;
+}
+
+/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
+ * SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */
+static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *sha) {
+ secp256k1_sha256_initialize(sha);
+ sha->s[0] = 0x24dd3219ul;
+ sha->s[1] = 0x4eba7e70ul;
+ sha->s[2] = 0xca0fabb9ul;
+ sha->s[3] = 0x0fa3166dul;
+ sha->s[4] = 0x3afbe4b1ul;
+ sha->s[5] = 0x4c44df97ul;
+ sha->s[6] = 0x4aac2739ul;
+ sha->s[7] = 0x249e850aul;
+
+ sha->bytes = 64;
+}
+
+/* algo16 argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340
+ * by using the correct tagged hash function. */
+static const unsigned char bip340_algo16[16] = "BIP0340/nonce\0\0\0";
+
+static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
+ secp256k1_sha256 sha;
+ unsigned char masked_key[32];
+ int i;
+
+ if (algo16 == NULL) {
+ return 0;
+ }
+
+ if (data != NULL) {
+ secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha);
+ secp256k1_sha256_write(&sha, data, 32);
+ secp256k1_sha256_finalize(&sha, masked_key);
+ for (i = 0; i < 32; i++) {
+ masked_key[i] ^= key32[i];
+ }
+ }
+
+ /* Tag the hash with algo16 which is important to avoid nonce reuse across
+ * algorithms. If this nonce function is used in BIP-340 signing as defined
+ * in the spec, an optimized tagging implementation is used. */
+ if (memcmp(algo16, bip340_algo16, 16) == 0) {
+ secp256k1_nonce_function_bip340_sha256_tagged(&sha);
+ } else {
+ int algo16_len = 16;
+ /* Remove terminating null bytes */
+ while (algo16_len > 0 && !algo16[algo16_len - 1]) {
+ algo16_len--;
+ }
+ secp256k1_sha256_initialize_tagged(&sha, algo16, algo16_len);
+ }
+
+ /* Hash (masked-)key||pk||msg using the tagged hash as per the spec */
+ if (data != NULL) {
+ secp256k1_sha256_write(&sha, masked_key, 32);
+ } else {
+ secp256k1_sha256_write(&sha, key32, 32);
+ }
+ secp256k1_sha256_write(&sha, xonly_pk32, 32);
+ secp256k1_sha256_write(&sha, msg32, 32);
+ secp256k1_sha256_finalize(&sha, nonce32);
+ return 1;
+}
+
+const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340;
+
+/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
+ * SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */
+static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) {
+ secp256k1_sha256_initialize(sha);
+ sha->s[0] = 0x9cecba11ul;
+ sha->s[1] = 0x23925381ul;
+ sha->s[2] = 0x11679112ul;
+ sha->s[3] = 0xd1627e0ful;
+ sha->s[4] = 0x97c87550ul;
+ sha->s[5] = 0x003cc765ul;
+ sha->s[6] = 0x90f61164ul;
+ sha->s[7] = 0x33e9b66aul;
+ sha->bytes = 64;
+}
+
+int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
+ secp256k1_scalar sk;
+ secp256k1_scalar e;
+ secp256k1_scalar k;
+ secp256k1_gej rj;
+ secp256k1_ge pk;
+ secp256k1_ge r;
+ secp256k1_sha256 sha;
+ unsigned char buf[32] = { 0 };
+ unsigned char pk_buf[32];
+ unsigned char seckey[32];
+ int ret = 1;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(sig64 != NULL);
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(keypair != NULL);
+
+ if (noncefp == NULL) {
+ noncefp = secp256k1_nonce_function_bip340;
+ }
+
+ ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair);
+ /* Because we are signing for a x-only pubkey, the secret key is negated
+ * before signing if the point corresponding to the secret key does not
+ * have an even Y. */
+ if (secp256k1_fe_is_odd(&pk.y)) {
+ secp256k1_scalar_negate(&sk, &sk);
+ }
+
+ secp256k1_scalar_get_b32(seckey, &sk);
+ secp256k1_fe_get_b32(pk_buf, &pk.x);
+ ret &= !!noncefp(buf, msg32, seckey, pk_buf, bip340_algo16, ndata);
+ secp256k1_scalar_set_b32(&k, buf, NULL);
+ ret &= !secp256k1_scalar_is_zero(&k);
+ secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
+
+ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k);
+ secp256k1_ge_set_gej(&r, &rj);
+
+ /* We declassify r to allow using it as a branch point. This is fine
+ * because r is not a secret. */
+ secp256k1_declassify(ctx, &r, sizeof(r));
+ secp256k1_fe_normalize_var(&r.y);
+ if (secp256k1_fe_is_odd(&r.y)) {
+ secp256k1_scalar_negate(&k, &k);
+ }
+ secp256k1_fe_normalize_var(&r.x);
+ secp256k1_fe_get_b32(&sig64[0], &r.x);
+
+ /* tagged hash(r.x, pk.x, msg32) */
+ secp256k1_schnorrsig_sha256_tagged(&sha);
+ secp256k1_sha256_write(&sha, &sig64[0], 32);
+ secp256k1_sha256_write(&sha, pk_buf, sizeof(pk_buf));
+ secp256k1_sha256_write(&sha, msg32, 32);
+ secp256k1_sha256_finalize(&sha, buf);
+
+ /* Set scalar e to the challenge hash modulo the curve order as per
+ * BIP340. */
+ secp256k1_scalar_set_b32(&e, buf, NULL);
+ secp256k1_scalar_mul(&e, &e, &sk);
+ secp256k1_scalar_add(&e, &e, &k);
+ secp256k1_scalar_get_b32(&sig64[32], &e);
+
+ memczero(sig64, 64, !ret);
+ secp256k1_scalar_clear(&k);
+ secp256k1_scalar_clear(&sk);
+ memset(seckey, 0, sizeof(seckey));
+
+ return ret;
+}
+
+int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_xonly_pubkey *pubkey) {
+ secp256k1_scalar s;
+ secp256k1_scalar e;
+ secp256k1_gej rj;
+ secp256k1_ge pk;
+ secp256k1_gej pkj;
+ secp256k1_fe rx;
+ secp256k1_ge r;
+ secp256k1_sha256 sha;
+ unsigned char buf[32];
+ int overflow;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
+ ARG_CHECK(sig64 != NULL);
+ ARG_CHECK(msg32 != NULL);
+ ARG_CHECK(pubkey != NULL);
+
+ if (!secp256k1_fe_set_b32(&rx, &sig64[0])) {
+ return 0;
+ }
+
+ secp256k1_scalar_set_b32(&s, &sig64[32], &overflow);
+ if (overflow) {
+ return 0;
+ }
+
+ if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
+ return 0;
+ }
+
+ secp256k1_schnorrsig_sha256_tagged(&sha);
+ secp256k1_sha256_write(&sha, &sig64[0], 32);
+ secp256k1_fe_get_b32(buf, &pk.x);
+ secp256k1_sha256_write(&sha, buf, sizeof(buf));
+ secp256k1_sha256_write(&sha, msg32, 32);
+ secp256k1_sha256_finalize(&sha, buf);
+ secp256k1_scalar_set_b32(&e, buf, NULL);
+
+ /* Compute rj = s*G + (-e)*pkj */
+ secp256k1_scalar_negate(&e, &e);
+ secp256k1_gej_set_ge(&pkj, &pk);
+ secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s);
+
+ secp256k1_ge_set_gej_var(&r, &rj);
+ if (secp256k1_ge_is_infinity(&r)) {
+ return 0;
+ }
+
+ secp256k1_fe_normalize_var(&r.y);
+ return !secp256k1_fe_is_odd(&r.y) &&
+ secp256k1_fe_equal_var(&rx, &r.x);
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
new file mode 100644
index 0000000000..88d8f56404
--- /dev/null
+++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
@@ -0,0 +1,806 @@
+/**********************************************************************
+ * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_
+#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_
+
+#include "secp256k1_schnorrsig.h"
+
+/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many
+ * bytes) changes the hash function
+ */
+void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
+ unsigned char nonces[2][32];
+ CHECK(nonce_function_bip340(nonces[0], args[0], args[1], args[2], args[3], args[4]) == 1);
+ secp256k1_rand_flip(args[n_flip], n_bytes);
+ CHECK(nonce_function_bip340(nonces[1], args[0], args[1], args[2], args[3], args[4]) == 1);
+ CHECK(memcmp(nonces[0], nonces[1], 32) != 0);
+}
+
+/* Tests for the equality of two sha256 structs. This function only produces a
+ * correct result if an integer multiple of 64 many bytes have been written
+ * into the hash functions. */
+void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
+ /* Is buffer fully consumed? */
+ CHECK((sha1->bytes & 0x3F) == 0);
+
+ CHECK(sha1->bytes == sha2->bytes);
+ CHECK(memcmp(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
+}
+
+void run_nonce_function_bip340_tests(void) {
+ unsigned char tag[13] = "BIP0340/nonce";
+ unsigned char aux_tag[11] = "BIP0340/aux";
+ unsigned char algo16[16] = "BIP0340/nonce\0\0\0";
+ secp256k1_sha256 sha;
+ secp256k1_sha256 sha_optimized;
+ unsigned char nonce[32];
+ unsigned char msg[32];
+ unsigned char key[32];
+ unsigned char pk[32];
+ unsigned char aux_rand[32];
+ unsigned char *args[5];
+ int i;
+
+ /* Check that hash initialized by
+ * secp256k1_nonce_function_bip340_sha256_tagged has the expected
+ * state. */
+ secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag));
+ secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+
+ /* Check that hash initialized by
+ * secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected
+ * state. */
+ secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag));
+ secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+
+ secp256k1_rand256(msg);
+ secp256k1_rand256(key);
+ secp256k1_rand256(pk);
+ secp256k1_rand256(aux_rand);
+
+ /* Check that a bitflip in an argument results in different nonces. */
+ args[0] = msg;
+ args[1] = key;
+ args[2] = pk;
+ args[3] = algo16;
+ args[4] = aux_rand;
+ for (i = 0; i < count; i++) {
+ nonce_function_bip340_bitflip(args, 0, 32);
+ nonce_function_bip340_bitflip(args, 1, 32);
+ nonce_function_bip340_bitflip(args, 2, 32);
+ /* Flip algo16 special case "BIP0340/nonce" */
+ nonce_function_bip340_bitflip(args, 3, 16);
+ /* Flip algo16 again */
+ nonce_function_bip340_bitflip(args, 3, 16);
+ nonce_function_bip340_bitflip(args, 4, 32);
+ }
+
+ /* NULL algo16 is disallowed */
+ CHECK(nonce_function_bip340(nonce, msg, key, pk, NULL, NULL) == 0);
+ /* Empty algo16 is fine */
+ memset(algo16, 0x00, 16);
+ CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
+ /* algo16 with terminating null bytes is fine */
+ algo16[1] = 65;
+ CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
+ /* Other algo16 is fine */
+ memset(algo16, 0xFF, 16);
+ CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
+
+ /* NULL aux_rand argument is allowed. */
+ CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
+}
+
+void test_schnorrsig_api(void) {
+ unsigned char sk1[32];
+ unsigned char sk2[32];
+ unsigned char sk3[32];
+ unsigned char msg[32];
+ secp256k1_keypair keypairs[3];
+ secp256k1_keypair invalid_keypair = { 0 };
+ secp256k1_xonly_pubkey pk[3];
+ secp256k1_xonly_pubkey zero_pk;
+ unsigned char sig[64];
+
+ /** setup **/
+ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
+ secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ int ecount;
+
+ secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
+
+ secp256k1_rand256(sk1);
+ secp256k1_rand256(sk2);
+ secp256k1_rand256(sk3);
+ secp256k1_rand256(msg);
+ CHECK(secp256k1_keypair_create(ctx, &keypairs[0], sk1) == 1);
+ CHECK(secp256k1_keypair_create(ctx, &keypairs[1], sk2) == 1);
+ CHECK(secp256k1_keypair_create(ctx, &keypairs[2], sk3) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[0], NULL, &keypairs[0]) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[1], NULL, &keypairs[1]) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[2], NULL, &keypairs[2]) == 1);
+ memset(&zero_pk, 0, sizeof(zero_pk));
+
+ /** main test body **/
+ ecount = 0;
+ CHECK(secp256k1_schnorrsig_sign(none, sig, msg, &keypairs[0], NULL, NULL) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_schnorrsig_sign(vrfy, sig, msg, &keypairs[0], NULL, NULL) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL, NULL) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, &keypairs[0], NULL, NULL) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_schnorrsig_sign(sign, sig, NULL, &keypairs[0], NULL, NULL) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, NULL, NULL, NULL) == 0);
+ CHECK(ecount == 5);
+ CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &invalid_keypair, NULL, NULL) == 0);
+ CHECK(ecount == 6);
+
+ ecount = 0;
+ CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL, NULL) == 1);
+ CHECK(secp256k1_schnorrsig_verify(none, sig, msg, &pk[0]) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, &pk[0]) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, &pk[0]) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, &pk[0]) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, &pk[0]) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, NULL) == 0);
+ CHECK(ecount == 5);
+ CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, &zero_pk) == 0);
+ CHECK(ecount == 6);
+
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(vrfy);
+ secp256k1_context_destroy(both);
+}
+
+/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the
+ * expected state. */
+void test_schnorrsig_sha256_tagged(void) {
+ char tag[17] = "BIP0340/challenge";
+ secp256k1_sha256 sha;
+ secp256k1_sha256 sha_optimized;
+
+ secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag));
+ secp256k1_schnorrsig_sha256_tagged(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+}
+
+/* Helper function for schnorrsig_bip_vectors
+ * Signs the message and checks that it's the same as expected_sig. */
+void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, unsigned char *aux_rand, const unsigned char *msg, const unsigned char *expected_sig) {
+ unsigned char sig[64];
+ secp256k1_keypair keypair;
+ secp256k1_xonly_pubkey pk, pk_expected;
+
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, aux_rand));
+ CHECK(memcmp(sig, expected_sig, 64) == 0);
+
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized));
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
+ CHECK(memcmp(&pk, &pk_expected, sizeof(pk)) == 0);
+ CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, &pk));
+}
+
+/* Helper function for schnorrsig_bip_vectors
+ * Checks that both verify and verify_batch (TODO) return the same value as expected. */
+void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) {
+ secp256k1_xonly_pubkey pk;
+
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk, pk_serialized));
+ CHECK(expected == secp256k1_schnorrsig_verify(ctx, sig, msg32, &pk));
+}
+
+/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See
+ * https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */
+void test_schnorrsig_bip_vectors(void) {
+ {
+ /* Test vector 0 */
+ const unsigned char sk[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
+ };
+ const unsigned char pk[32] = {
+ 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10,
+ 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29,
+ 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0,
+ 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9
+ };
+ unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const unsigned char msg[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const unsigned char sig[64] = {
+ 0xE9, 0x07, 0x83, 0x1F, 0x80, 0x84, 0x8D, 0x10,
+ 0x69, 0xA5, 0x37, 0x1B, 0x40, 0x24, 0x10, 0x36,
+ 0x4B, 0xDF, 0x1C, 0x5F, 0x83, 0x07, 0xB0, 0x08,
+ 0x4C, 0x55, 0xF1, 0xCE, 0x2D, 0xCA, 0x82, 0x15,
+ 0x25, 0xF6, 0x6A, 0x4A, 0x85, 0xEA, 0x8B, 0x71,
+ 0xE4, 0x82, 0xA7, 0x4F, 0x38, 0x2D, 0x2C, 0xE5,
+ 0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47,
+ 0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ }
+ {
+ /* Test vector 1 */
+ const unsigned char sk[32] = {
+ 0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A,
+ 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7,
+ 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56,
+ 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF
+ };
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0x68, 0x96, 0xBD, 0x60, 0xEE, 0xAE, 0x29, 0x6D,
+ 0xB4, 0x8A, 0x22, 0x9F, 0xF7, 0x1D, 0xFE, 0x07,
+ 0x1B, 0xDE, 0x41, 0x3E, 0x6D, 0x43, 0xF9, 0x17,
+ 0xDC, 0x8D, 0xCF, 0x8C, 0x78, 0xDE, 0x33, 0x41,
+ 0x89, 0x06, 0xD1, 0x1A, 0xC9, 0x76, 0xAB, 0xCC,
+ 0xB2, 0x0B, 0x09, 0x12, 0x92, 0xBF, 0xF4, 0xEA,
+ 0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C,
+ 0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ }
+ {
+ /* Test vector 2 */
+ const unsigned char sk[32] = {
+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC9
+ };
+ const unsigned char pk[32] = {
+ 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13,
+ 0x12, 0x1F, 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC,
+ 0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9,
+ 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8
+ };
+ unsigned char aux_rand[32] = {
+ 0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE,
+ 0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC,
+ 0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C,
+ 0x4B, 0x0B, 0x62, 0xD7, 0x98, 0xE6, 0xD9, 0x06
+ };
+ const unsigned char msg[32] = {
+ 0x7E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A,
+ 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D,
+ 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33,
+ 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C
+ };
+ const unsigned char sig[64] = {
+ 0x58, 0x31, 0xAA, 0xEE, 0xD7, 0xB4, 0x4B, 0xB7,
+ 0x4E, 0x5E, 0xAB, 0x94, 0xBA, 0x9D, 0x42, 0x94,
+ 0xC4, 0x9B, 0xCF, 0x2A, 0x60, 0x72, 0x8D, 0x8B,
+ 0x4C, 0x20, 0x0F, 0x50, 0xDD, 0x31, 0x3C, 0x1B,
+ 0xAB, 0x74, 0x58, 0x79, 0xA5, 0xAD, 0x95, 0x4A,
+ 0x72, 0xC4, 0x5A, 0x91, 0xC3, 0xA5, 0x1D, 0x3C,
+ 0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E,
+ 0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ }
+ {
+ /* Test vector 3 */
+ const unsigned char sk[32] = {
+ 0x0B, 0x43, 0x2B, 0x26, 0x77, 0x93, 0x73, 0x81,
+ 0xAE, 0xF0, 0x5B, 0xB0, 0x2A, 0x66, 0xEC, 0xD0,
+ 0x12, 0x77, 0x30, 0x62, 0xCF, 0x3F, 0xA2, 0x54,
+ 0x9E, 0x44, 0xF5, 0x8E, 0xD2, 0x40, 0x17, 0x10
+ };
+ const unsigned char pk[32] = {
+ 0x25, 0xD1, 0xDF, 0xF9, 0x51, 0x05, 0xF5, 0x25,
+ 0x3C, 0x40, 0x22, 0xF6, 0x28, 0xA9, 0x96, 0xAD,
+ 0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A,
+ 0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17
+ };
+ unsigned char aux_rand[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+ const unsigned char msg[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+ const unsigned char sig[64] = {
+ 0x7E, 0xB0, 0x50, 0x97, 0x57, 0xE2, 0x46, 0xF1,
+ 0x94, 0x49, 0x88, 0x56, 0x51, 0x61, 0x1C, 0xB9,
+ 0x65, 0xEC, 0xC1, 0xA1, 0x87, 0xDD, 0x51, 0xB6,
+ 0x4F, 0xDA, 0x1E, 0xDC, 0x96, 0x37, 0xD5, 0xEC,
+ 0x97, 0x58, 0x2B, 0x9C, 0xB1, 0x3D, 0xB3, 0x93,
+ 0x37, 0x05, 0xB3, 0x2B, 0xA9, 0x82, 0xAF, 0x5A,
+ 0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27,
+ 0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ }
+ {
+ /* Test vector 4 */
+ const unsigned char pk[32] = {
+ 0xD6, 0x9C, 0x35, 0x09, 0xBB, 0x99, 0xE4, 0x12,
+ 0xE6, 0x8B, 0x0F, 0xE8, 0x54, 0x4E, 0x72, 0x83,
+ 0x7D, 0xFA, 0x30, 0x74, 0x6D, 0x8B, 0xE2, 0xAA,
+ 0x65, 0x97, 0x5F, 0x29, 0xD2, 0x2D, 0xC7, 0xB9
+ };
+ const unsigned char msg[32] = {
+ 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2,
+ 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24,
+ 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B,
+ 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03
+ };
+ const unsigned char sig[64] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F,
+ 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28,
+ 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63,
+ 0x76, 0xAF, 0xB1, 0x54, 0x8A, 0xF6, 0x03, 0xB3,
+ 0xEB, 0x45, 0xC9, 0xF8, 0x20, 0x7D, 0xEE, 0x10,
+ 0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93,
+ 0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ }
+ {
+ /* Test vector 5 */
+ const unsigned char pk[32] = {
+ 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, 0x50,
+ 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, 0x21,
+ 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, 0x87,
+ 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34
+ };
+ secp256k1_xonly_pubkey pk_parsed;
+ /* No need to check the signature of the test vector as parsing the pubkey already fails */
+ CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk));
+ }
+ {
+ /* Test vector 6 */
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0xFF, 0xF9, 0x7B, 0xD5, 0x75, 0x5E, 0xEE, 0xA4,
+ 0x20, 0x45, 0x3A, 0x14, 0x35, 0x52, 0x35, 0xD3,
+ 0x82, 0xF6, 0x47, 0x2F, 0x85, 0x68, 0xA1, 0x8B,
+ 0x2F, 0x05, 0x7A, 0x14, 0x60, 0x29, 0x75, 0x56,
+ 0x3C, 0xC2, 0x79, 0x44, 0x64, 0x0A, 0xC6, 0x07,
+ 0xCD, 0x10, 0x7A, 0xE1, 0x09, 0x23, 0xD9, 0xEF,
+ 0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E,
+ 0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ }
+ {
+ /* Test vector 7 */
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0x1F, 0xA6, 0x2E, 0x33, 0x1E, 0xDB, 0xC2, 0x1C,
+ 0x39, 0x47, 0x92, 0xD2, 0xAB, 0x11, 0x00, 0xA7,
+ 0xB4, 0x32, 0xB0, 0x13, 0xDF, 0x3F, 0x6F, 0xF4,
+ 0xF9, 0x9F, 0xCB, 0x33, 0xE0, 0xE1, 0x51, 0x5F,
+ 0x28, 0x89, 0x0B, 0x3E, 0xDB, 0x6E, 0x71, 0x89,
+ 0xB6, 0x30, 0x44, 0x8B, 0x51, 0x5C, 0xE4, 0xF8,
+ 0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35,
+ 0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ }
+ {
+ /* Test vector 8 */
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA,
+ 0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F,
+ 0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96,
+ 0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69,
+ 0x96, 0x17, 0x64, 0xB3, 0xAA, 0x9B, 0x2F, 0xFC,
+ 0xB6, 0xEF, 0x94, 0x7B, 0x68, 0x87, 0xA2, 0x26,
+ 0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C,
+ 0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ }
+ {
+ /* Test vector 9 */
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x3D, 0xDA, 0x83, 0x28, 0xAF, 0x9C, 0x23,
+ 0xA9, 0x4C, 0x1F, 0xEE, 0xCF, 0xD1, 0x23, 0xBA,
+ 0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC,
+ 0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ }
+ {
+ /* Test vector 10 */
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x76, 0x15, 0xFB, 0xAF, 0x5A, 0xE2, 0x88, 0x64,
+ 0x01, 0x3C, 0x09, 0x97, 0x42, 0xDE, 0xAD, 0xB4,
+ 0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9,
+ 0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ }
+ {
+ /* Test vector 11 */
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A,
+ 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB,
+ 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7,
+ 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D,
+ 0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03,
+ 0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7,
+ 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
+ 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ }
+ {
+ /* Test vector 12 */
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F,
+ 0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03,
+ 0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7,
+ 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
+ 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ }
+ {
+ /* Test vector 13 */
+ const unsigned char pk[32] = {
+ 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
+ 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
+ 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
+ 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
+ };
+ const unsigned char msg[32] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
+ 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
+ 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
+ };
+ const unsigned char sig[64] = {
+ 0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA,
+ 0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F,
+ 0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96,
+ 0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+ 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
+ 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
+ };
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ }
+ {
+ /* Test vector 14 */
+ const unsigned char pk[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30
+ };
+ secp256k1_xonly_pubkey pk_parsed;
+ /* No need to check the signature of the test vector as parsing the pubkey already fails */
+ CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk));
+ }
+}
+
+/* Nonce function that returns constant 0 */
+static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
+ (void) msg32;
+ (void) key32;
+ (void) xonly_pk32;
+ (void) algo16;
+ (void) data;
+ (void) nonce32;
+ return 0;
+}
+
+/* Nonce function that sets nonce to 0 */
+static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
+ (void) msg32;
+ (void) key32;
+ (void) xonly_pk32;
+ (void) algo16;
+ (void) data;
+
+ memset(nonce32, 0, 32);
+ return 1;
+}
+
+/* Nonce function that sets nonce to 0xFF...0xFF */
+static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
+ (void) msg32;
+ (void) key32;
+ (void) xonly_pk32;
+ (void) algo16;
+ (void) data;
+
+ memset(nonce32, 0xFF, 32);
+ return 1;
+}
+
+void test_schnorrsig_sign(void) {
+ unsigned char sk[32];
+ secp256k1_keypair keypair;
+ const unsigned char msg[32] = "this is a msg for a schnorrsig..";
+ unsigned char sig[64];
+ unsigned char zeros64[64] = { 0 };
+
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL) == 1);
+
+ /* Test different nonce functions */
+ memset(sig, 1, sizeof(sig));
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_failing, NULL) == 0);
+ CHECK(memcmp(sig, zeros64, sizeof(sig)) == 0);
+ memset(&sig, 1, sizeof(sig));
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_0, NULL) == 0);
+ CHECK(memcmp(sig, zeros64, sizeof(sig)) == 0);
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_overflowing, NULL) == 1);
+ CHECK(memcmp(sig, zeros64, sizeof(sig)) != 0);
+}
+
+#define N_SIGS 3
+/* Creates N_SIGS valid signatures and verifies them with verify and
+ * verify_batch (TODO). Then flips some bits and checks that verification now
+ * fails. */
+void test_schnorrsig_sign_verify(void) {
+ unsigned char sk[32];
+ unsigned char msg[N_SIGS][32];
+ unsigned char sig[N_SIGS][64];
+ size_t i;
+ secp256k1_keypair keypair;
+ secp256k1_xonly_pubkey pk;
+ secp256k1_scalar s;
+
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
+
+ for (i = 0; i < N_SIGS; i++) {
+ secp256k1_rand256(msg[i]);
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig[i], msg[i], &keypair, NULL, NULL));
+ CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], &pk));
+ }
+
+ {
+ /* Flip a few bits in the signature and in the message and check that
+ * verify and verify_batch (TODO) fail */
+ size_t sig_idx = secp256k1_rand_int(N_SIGS);
+ size_t byte_idx = secp256k1_rand_int(32);
+ unsigned char xorbyte = secp256k1_rand_int(254)+1;
+ sig[sig_idx][byte_idx] ^= xorbyte;
+ CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
+ sig[sig_idx][byte_idx] ^= xorbyte;
+
+ byte_idx = secp256k1_rand_int(32);
+ sig[sig_idx][32+byte_idx] ^= xorbyte;
+ CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
+ sig[sig_idx][32+byte_idx] ^= xorbyte;
+
+ byte_idx = secp256k1_rand_int(32);
+ msg[sig_idx][byte_idx] ^= xorbyte;
+ CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
+ msg[sig_idx][byte_idx] ^= xorbyte;
+
+ /* Check that above bitflips have been reversed correctly */
+ CHECK(secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
+ }
+
+ /* Test overflowing s */
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL, NULL));
+ CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
+ memset(&sig[0][32], 0xFF, 32);
+ CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
+
+ /* Test negative s */
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL, NULL));
+ CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
+ secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
+ secp256k1_scalar_negate(&s, &s);
+ secp256k1_scalar_get_b32(&sig[0][32], &s);
+ CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
+}
+#undef N_SIGS
+
+void test_schnorrsig_taproot(void) {
+ unsigned char sk[32];
+ secp256k1_keypair keypair;
+ secp256k1_xonly_pubkey internal_pk;
+ unsigned char internal_pk_bytes[32];
+ secp256k1_xonly_pubkey output_pk;
+ unsigned char output_pk_bytes[32];
+ unsigned char tweak[32];
+ int pk_parity;
+ unsigned char msg[32];
+ unsigned char sig[64];
+
+ /* Create output key */
+ secp256k1_rand256(sk);
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1);
+ /* In actual taproot the tweak would be hash of internal_pk */
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, tweak, &internal_pk) == 1);
+ CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
+ CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1);
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk) == 1);
+
+ /* Key spend */
+ secp256k1_rand256(msg);
+ CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL) == 1);
+ /* Verify key spend */
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1);
+ CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, &output_pk) == 1);
+
+ /* Script spend */
+ CHECK(secp256k1_xonly_pubkey_serialize(ctx, internal_pk_bytes, &internal_pk) == 1);
+ /* Verify script spend */
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &internal_pk, internal_pk_bytes) == 1);
+ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1);
+}
+
+void run_schnorrsig_tests(void) {
+ int i;
+ run_nonce_function_bip340_tests();
+
+ test_schnorrsig_api();
+ test_schnorrsig_sha256_tagged();
+ test_schnorrsig_bip_vectors();
+ for (i = 0; i < count; i++) {
+ test_schnorrsig_sign();
+ test_schnorrsig_sign_verify();
+ }
+ test_schnorrsig_taproot();
+}
+
+#endif
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index 2a74703523..95d3e326c9 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -8,6 +8,7 @@
#define SECP256K1_SCALAR_H
#include "num.h"
+#include "util.h"
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -15,12 +16,12 @@
#if defined(EXHAUSTIVE_TEST_ORDER)
#include "scalar_low.h"
-#elif defined(USE_SCALAR_4X64)
+#elif defined(SECP256K1_WIDEMUL_INT128)
#include "scalar_4x64.h"
-#elif defined(USE_SCALAR_8X32)
+#elif defined(SECP256K1_WIDEMUL_INT64)
#include "scalar_8x32.h"
#else
-#error "Please select scalar implementation"
+#error "Please select wide multiplication implementation"
#endif
/** Clear a scalar to prevent the leak of sensitive data. */
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index 8f539c4bc6..7f39927861 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -192,9 +192,9 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
- th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \
+ th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
c1 += th; /* overflow is handled on the next line */ \
- c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \
+ c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK((c1 >= th) || (c2 != 0)); \
}
@@ -207,7 +207,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
- th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \
+ th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
c1 += th; /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK(c1 >= th); \
}
@@ -221,16 +221,16 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
tl = t; \
} \
th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \
- c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
+ c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \
- th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \
+ th2 += (tl2 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
c0 += tl2; /* overflow is handled on the next line */ \
- th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \
+ th2 += (c0 < tl2); /* second overflow is handled on the next line */ \
c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
c1 += th2; /* overflow is handled on the next line */ \
- c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
+ c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
}
@@ -238,15 +238,15 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
#define sumadd(a) { \
unsigned int over; \
c0 += (a); /* overflow is handled on the next line */ \
- over = (c0 < (a)) ? 1 : 0; \
+ over = (c0 < (a)); \
c1 += over; /* overflow is handled on the next line */ \
- c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \
+ c2 += (c1 < over); /* never overflows by contract */ \
}
/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */
#define sumadd_fast(a) { \
c0 += (a); /* overflow is handled on the next line */ \
- c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
+ c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \
VERIFY_CHECK(c2 == 0); \
}
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index 3c372f34fe..f8c7fa7efa 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -271,9 +271,9 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
- th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \
+ th += (c0 < tl); /* at most 0xFFFFFFFF */ \
c1 += th; /* overflow is handled on the next line */ \
- c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \
+ c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK((c1 >= th) || (c2 != 0)); \
}
@@ -286,7 +286,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
tl = t; \
} \
c0 += tl; /* overflow is handled on the next line */ \
- th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \
+ th += (c0 < tl); /* at most 0xFFFFFFFF */ \
c1 += th; /* never overflows by contract (verified in the next line) */ \
VERIFY_CHECK(c1 >= th); \
}
@@ -300,16 +300,16 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
tl = t; \
} \
th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \
- c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
+ c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \
- th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \
+ th2 += (tl2 < tl); /* at most 0xFFFFFFFF */ \
c0 += tl2; /* overflow is handled on the next line */ \
- th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \
+ th2 += (c0 < tl2); /* second overflow is handled on the next line */ \
c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
c1 += th2; /* overflow is handled on the next line */ \
- c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
+ c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
}
@@ -317,15 +317,15 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
#define sumadd(a) { \
unsigned int over; \
c0 += (a); /* overflow is handled on the next line */ \
- over = (c0 < (a)) ? 1 : 0; \
+ over = (c0 < (a)); \
c1 += over; /* overflow is handled on the next line */ \
- c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \
+ c2 += (c1 < over); /* never overflows by contract */ \
}
/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */
#define sumadd_fast(a) { \
c0 += (a); /* overflow is handled on the next line */ \
- c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \
+ c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \
VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \
VERIFY_CHECK(c2 == 0); \
}
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 70cd73db06..2ec04b1ae9 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -16,12 +16,12 @@
#if defined(EXHAUSTIVE_TEST_ORDER)
#include "scalar_low_impl.h"
-#elif defined(USE_SCALAR_4X64)
+#elif defined(SECP256K1_WIDEMUL_INT128)
#include "scalar_4x64_impl.h"
-#elif defined(USE_SCALAR_8X32)
+#elif defined(SECP256K1_WIDEMUL_INT64)
#include "scalar_8x32_impl.h"
#else
-#error "Please select scalar implementation"
+#error "Please select wide multiplication implementation"
#endif
static const secp256k1_scalar secp256k1_scalar_one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
diff --git a/src/secp256k1/src/scratch_impl.h b/src/secp256k1/src/scratch_impl.h
index 4cee700001..b205620224 100644
--- a/src/secp256k1/src/scratch_impl.h
+++ b/src/secp256k1/src/scratch_impl.h
@@ -11,7 +11,7 @@
#include "scratch.h"
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) {
- const size_t base_alloc = ((sizeof(secp256k1_scratch) + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
+ const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch));
void *alloc = checked_malloc(error_callback, base_alloc + size);
secp256k1_scratch* ret = (secp256k1_scratch *)alloc;
if (ret != NULL) {
@@ -60,6 +60,10 @@ static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_c
secp256k1_callback_call(error_callback, "invalid scratch space");
return 0;
}
+ /* Ensure that multiplication will not wrap around */
+ if (ALIGNMENT > 1 && objects > SIZE_MAX/(ALIGNMENT - 1)) {
+ return 0;
+ }
if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) {
return 0;
}
@@ -68,7 +72,14 @@ static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_c
static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) {
void *ret;
- size = ROUND_TO_ALIGN(size);
+ size_t rounded_size;
+
+ rounded_size = ROUND_TO_ALIGN(size);
+ /* Check that rounding did not wrap around */
+ if (rounded_size < size) {
+ return NULL;
+ }
+ size = rounded_size;
if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index b03a6e6345..eaafb3a21d 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -7,6 +7,7 @@
#include "include/secp256k1.h"
#include "include/secp256k1_preallocated.h"
+#include "assumptions.h"
#include "util.h"
#include "num_impl.h"
#include "field_impl.h"
@@ -19,6 +20,7 @@
#include "eckey_impl.h"
#include "hash_impl.h"
#include "scratch_impl.h"
+#include "selftest.h"
#if defined(VALGRIND)
# include <valgrind/memcheck.h>
@@ -117,6 +119,9 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne
size_t prealloc_size;
secp256k1_context* ret;
+ if (!secp256k1_selftest()) {
+ secp256k1_callback_call(&default_error_callback, "self test failed");
+ }
VERIFY_CHECK(prealloc != NULL);
prealloc_size = secp256k1_context_preallocated_size(flags);
ret = (secp256k1_context*)manual_alloc(&prealloc, sizeof(secp256k1_context), base, prealloc_size);
@@ -226,7 +231,7 @@ void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scr
* of the software. This is setup for use with valgrind but could be substituted with
* the appropriate instrumentation for other analysis tools.
*/
-static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, void *p, size_t len) {
+static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) {
#if defined(VALGRIND)
if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len);
#else
@@ -291,7 +296,7 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(outputlen != NULL);
- ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));
+ ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u));
len = *outputlen;
*outputlen = 0;
ARG_CHECK(output != NULL);
@@ -548,10 +553,21 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char
return ret;
}
-int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) {
+static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_scalar *seckey_scalar, secp256k1_ge *p, const unsigned char *seckey) {
secp256k1_gej pj;
+ int ret;
+
+ ret = secp256k1_scalar_set_b32_seckey(seckey_scalar, seckey);
+ secp256k1_scalar_cmov(seckey_scalar, &secp256k1_scalar_one, !ret);
+
+ secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar);
+ secp256k1_ge_set_gej(p, &pj);
+ return ret;
+}
+
+int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) {
secp256k1_ge p;
- secp256k1_scalar sec;
+ secp256k1_scalar seckey_scalar;
int ret = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkey != NULL);
@@ -559,15 +575,11 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(seckey != NULL);
- ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
- secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !ret);
-
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
- secp256k1_ge_set_gej(&p, &pj);
+ ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey);
secp256k1_pubkey_save(pubkey, &p);
memczero(pubkey, sizeof(*pubkey), !ret);
- secp256k1_scalar_clear(&sec);
+ secp256k1_scalar_clear(&seckey_scalar);
return ret;
}
@@ -605,24 +617,31 @@ int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *p
return ret;
}
-int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
+
+static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak) {
secp256k1_scalar term;
+ int overflow = 0;
+ int ret = 0;
+
+ secp256k1_scalar_set_b32(&term, tweak, &overflow);
+ ret = (!overflow) & secp256k1_eckey_privkey_tweak_add(sec, &term);
+ secp256k1_scalar_clear(&term);
+ return ret;
+}
+
+int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
secp256k1_scalar sec;
int ret = 0;
- int overflow = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(tweak != NULL);
- secp256k1_scalar_set_b32(&term, tweak, &overflow);
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
-
- ret &= (!overflow) & secp256k1_eckey_privkey_tweak_add(&sec, &term);
+ ret &= secp256k1_ec_seckey_tweak_add_helper(&sec, tweak);
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
secp256k1_scalar_get_b32(seckey, &sec);
secp256k1_scalar_clear(&sec);
- secp256k1_scalar_clear(&term);
return ret;
}
@@ -630,25 +649,26 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *
return secp256k1_ec_seckey_tweak_add(ctx, seckey, tweak);
}
+static int secp256k1_ec_pubkey_tweak_add_helper(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge *p, const unsigned char *tweak) {
+ secp256k1_scalar term;
+ int overflow = 0;
+ secp256k1_scalar_set_b32(&term, tweak, &overflow);
+ return !overflow && secp256k1_eckey_pubkey_tweak_add(ecmult_ctx, p, &term);
+}
+
int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {
secp256k1_ge p;
- secp256k1_scalar term;
int ret = 0;
- int overflow = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(pubkey != NULL);
ARG_CHECK(tweak != NULL);
- secp256k1_scalar_set_b32(&term, tweak, &overflow);
- ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
+ ret = secp256k1_pubkey_load(ctx, &p, pubkey);
memset(pubkey, 0, sizeof(*pubkey));
+ ret = ret && secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &p, tweak);
if (ret) {
- if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) {
- secp256k1_pubkey_save(pubkey, &p);
- } else {
- ret = 0;
- }
+ secp256k1_pubkey_save(pubkey, &p);
}
return ret;
@@ -741,3 +761,11 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
#ifdef ENABLE_MODULE_RECOVERY
# include "modules/recovery/main_impl.h"
#endif
+
+#ifdef ENABLE_MODULE_EXTRAKEYS
+# include "modules/extrakeys/main_impl.h"
+#endif
+
+#ifdef ENABLE_MODULE_SCHNORRSIG
+# include "modules/schnorrsig/main_impl.h"
+#endif
diff --git a/src/secp256k1/src/selftest.h b/src/secp256k1/src/selftest.h
new file mode 100644
index 0000000000..885983aa20
--- /dev/null
+++ b/src/secp256k1/src/selftest.h
@@ -0,0 +1,32 @@
+/**********************************************************************
+ * Copyright (c) 2020 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef SECP256K1_SELFTEST_H
+#define SECP256K1_SELFTEST_H
+
+#include "hash.h"
+
+#include <string.h>
+
+static int secp256k1_selftest_sha256(void) {
+ static const char *input63 = "For this sample, this 63-byte string will be used as input data";
+ static const unsigned char output32[32] = {
+ 0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e,
+ 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42,
+ };
+ unsigned char out[32];
+ secp256k1_sha256 hasher;
+ secp256k1_sha256_initialize(&hasher);
+ secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63);
+ secp256k1_sha256_finalize(&hasher, out);
+ return memcmp(out, output32, 32) == 0;
+}
+
+static int secp256k1_selftest(void) {
+ return secp256k1_selftest_sha256();
+}
+
+#endif /* SECP256K1_SELFTEST_H */
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index f1f9be077e..bcbe15a6f1 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -35,4 +35,7 @@ static void secp256k1_rand256_test(unsigned char *b32);
/** Generate pseudorandom bytes with long sequences of zero and one bits. */
static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len);
+/** Flip a single random bit in a byte array */
+static void secp256k1_rand_flip(unsigned char *b, size_t len);
+
#endif /* SECP256K1_TESTRAND_H */
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index 30a91e5296..dfb658d9c6 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -107,4 +107,8 @@ static void secp256k1_rand256_test(unsigned char *b32) {
secp256k1_rand_bytes_test(b32, 32);
}
+static void secp256k1_rand_flip(unsigned char *b, size_t len) {
+ b[secp256k1_rand_int(len)] ^= (1 << secp256k1_rand_int(8));
+}
+
#endif /* SECP256K1_TESTRAND_IMPL_H */
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 374ed7dc12..4780e9319b 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -182,8 +182,10 @@ void run_context_tests(int use_prealloc) {
ecount2 = 10;
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2);
- secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL);
- CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
+ /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */
+ secp256k1_context_set_error_callback(sign, secp256k1_default_illegal_callback_fn, NULL);
+ CHECK(sign->error_callback.fn != vrfy->error_callback.fn);
+ CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn);
/* check if sizes for cloning are consistent */
CHECK(secp256k1_context_preallocated_clone_size(none) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
@@ -239,7 +241,8 @@ void run_context_tests(int use_prealloc) {
}
/* Verify that the error callback makes it across the clone. */
- CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
+ CHECK(sign->error_callback.fn != vrfy->error_callback.fn);
+ CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn);
/* And that it resets back to default. */
secp256k1_context_set_error_callback(sign, NULL, NULL);
CHECK(vrfy->error_callback.fn == sign->error_callback.fn);
@@ -361,8 +364,8 @@ void run_scratch_tests(void) {
CHECK(scratch->alloc_size != 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
- /* Allocating another 500 bytes fails */
- CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
+ /* Allocating another 501 bytes fails */
+ CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 501) == NULL);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
CHECK(scratch->alloc_size != 0);
@@ -395,6 +398,18 @@ void run_scratch_tests(void) {
secp256k1_scratch_space_destroy(none, scratch);
CHECK(ecount == 5);
+ /* Test that large integers do not wrap around in a bad way */
+ scratch = secp256k1_scratch_space_create(none, 1000);
+ /* Try max allocation with a large number of objects. Only makes sense if
+ * ALIGNMENT is greater than 1 because otherwise the objects take no extra
+ * space. */
+ CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&none->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1));
+ /* Try allocating SIZE_MAX to test wrap around which only happens if
+ * ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch
+ * space is too small. */
+ CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, SIZE_MAX) == NULL);
+ secp256k1_scratch_space_destroy(none, scratch);
+
/* cleanup */
secp256k1_scratch_space_destroy(none, NULL); /* no-op */
secp256k1_context_destroy(none);
@@ -2215,6 +2230,9 @@ void test_ge(void) {
/* Normal doubling. */
secp256k1_gej_double_var(&resj, &gej[i2], NULL);
ge_equals_gej(&ref, &resj);
+ /* Constant-time doubling. */
+ secp256k1_gej_double(&resj, &gej[i2]);
+ ge_equals_gej(&ref, &resj);
}
/* Test adding opposites. */
@@ -2300,6 +2318,39 @@ void test_ge(void) {
free(zinv);
}
+
+void test_intialized_inf(void) {
+ secp256k1_ge p;
+ secp256k1_gej pj, npj, infj1, infj2, infj3;
+ secp256k1_fe zinv;
+
+ /* Test that adding P+(-P) results in a fully initalized infinity*/
+ random_group_element_test(&p);
+ secp256k1_gej_set_ge(&pj, &p);
+ secp256k1_gej_neg(&npj, &pj);
+
+ secp256k1_gej_add_var(&infj1, &pj, &npj, NULL);
+ CHECK(secp256k1_gej_is_infinity(&infj1));
+ CHECK(secp256k1_fe_is_zero(&infj1.x));
+ CHECK(secp256k1_fe_is_zero(&infj1.y));
+ CHECK(secp256k1_fe_is_zero(&infj1.z));
+
+ secp256k1_gej_add_ge_var(&infj2, &npj, &p, NULL);
+ CHECK(secp256k1_gej_is_infinity(&infj2));
+ CHECK(secp256k1_fe_is_zero(&infj2.x));
+ CHECK(secp256k1_fe_is_zero(&infj2.y));
+ CHECK(secp256k1_fe_is_zero(&infj2.z));
+
+ secp256k1_fe_set_int(&zinv, 1);
+ secp256k1_gej_add_zinv_var(&infj3, &npj, &p, &zinv);
+ CHECK(secp256k1_gej_is_infinity(&infj3));
+ CHECK(secp256k1_fe_is_zero(&infj3.x));
+ CHECK(secp256k1_fe_is_zero(&infj3.y));
+ CHECK(secp256k1_fe_is_zero(&infj3.z));
+
+
+}
+
void test_add_neg_y_diff_x(void) {
/* The point of this test is to check that we can add two points
* whose y-coordinates are negatives of each other but whose x
@@ -2373,6 +2424,7 @@ void run_ge(void) {
test_ge();
}
test_add_neg_y_diff_x();
+ test_intialized_inf();
}
void test_ec_combine(void) {
@@ -2967,14 +3019,16 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
secp256k1_scalar szero;
- secp256k1_scalar sc[32];
- secp256k1_ge pt[32];
+ secp256k1_scalar sc;
+ secp256k1_ge pt;
secp256k1_gej r;
ecmult_multi_data data;
secp256k1_scratch *scratch_empty;
- data.sc = sc;
- data.pt = pt;
+ random_group_element_test(&pt);
+ random_scalar_order(&sc);
+ data.sc = &sc;
+ data.pt = &pt;
secp256k1_scalar_set_int(&szero, 0);
/* Try to multiply 1 point, but scratch space is empty.*/
@@ -3232,6 +3286,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
int skew;
int bits = 256;
secp256k1_scalar num = *number;
+ secp256k1_scalar scalar_skew;
secp256k1_scalar_set_int(&x, 0);
secp256k1_scalar_set_int(&shift, 1 << w);
@@ -3262,7 +3317,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar_add(&x, &x, &t);
}
/* Skew num because when encoding numbers as odd we use an offset */
- secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
+ secp256k1_scalar_set_int(&scalar_skew, 1 << (skew == 2));
+ secp256k1_scalar_add(&num, &num, &scalar_skew);
CHECK(secp256k1_scalar_eq(&x, &num));
}
@@ -3374,13 +3430,32 @@ void run_wnaf(void) {
int i;
secp256k1_scalar n = {{0}};
+ test_constant_wnaf(&n, 4);
/* Sanity check: 1 and 2 are the smallest odd and even numbers and should
* have easier-to-diagnose failure modes */
n.d[0] = 1;
test_constant_wnaf(&n, 4);
n.d[0] = 2;
test_constant_wnaf(&n, 4);
- /* Test 0 */
+ /* Test -1, because it's a special case in wnaf_const */
+ n = secp256k1_scalar_one;
+ secp256k1_scalar_negate(&n, &n);
+ test_constant_wnaf(&n, 4);
+
+ /* Test -2, which may not lead to overflows in wnaf_const */
+ secp256k1_scalar_add(&n, &secp256k1_scalar_one, &secp256k1_scalar_one);
+ secp256k1_scalar_negate(&n, &n);
+ test_constant_wnaf(&n, 4);
+
+ /* Test (1/2) - 1 = 1/-2 and 1/2 = (1/-2) + 1
+ as corner cases of negation handling in wnaf_const */
+ secp256k1_scalar_inverse(&n, &n);
+ test_constant_wnaf(&n, 4);
+
+ secp256k1_scalar_add(&n, &n, &secp256k1_scalar_one);
+ test_constant_wnaf(&n, 4);
+
+ /* Test 0 for fixed wnaf */
test_fixed_wnaf_small();
/* Random tests */
for (i = 0; i < count; i++) {
@@ -5277,6 +5352,14 @@ void run_ecdsa_openssl(void) {
# include "modules/recovery/tests_impl.h"
#endif
+#ifdef ENABLE_MODULE_EXTRAKEYS
+# include "modules/extrakeys/tests_impl.h"
+#endif
+
+#ifdef ENABLE_MODULE_SCHNORRSIG
+# include "modules/schnorrsig/tests_impl.h"
+#endif
+
void run_memczero_test(void) {
unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
unsigned char buf2[sizeof(buf1)];
@@ -5583,6 +5666,14 @@ int main(int argc, char **argv) {
run_recovery_tests();
#endif
+#ifdef ENABLE_MODULE_EXTRAKEYS
+ run_extrakeys_tests();
+#endif
+
+#ifdef ENABLE_MODULE_SCHNORRSIG
+ run_schnorrsig_tests();
+#endif
+
/* util tests */
run_memczero_test();
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index 8cca1cef21..681ed80bd0 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -22,6 +22,7 @@
#endif
#include "include/secp256k1.h"
+#include "assumptions.h"
#include "group.h"
#include "secp256k1.c"
#include "testrand_impl.h"
@@ -141,10 +142,8 @@ void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *gr
/* Check doubling */
for (i = 0; i < order; i++) {
secp256k1_gej tmp;
- if (i > 0) {
- secp256k1_gej_double_nonzero(&tmp, &groupj[i]);
- ge_equals_gej(&group[(2 * i) % order], &tmp);
- }
+ secp256k1_gej_double(&tmp, &groupj[i]);
+ ge_equals_gej(&group[(2 * i) % order], &tmp);
secp256k1_gej_double_var(&tmp, &groupj[i], NULL);
ge_equals_gej(&group[(2 * i) % order], &tmp);
}
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index 8289e23e0c..a5cbe03ef5 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -170,13 +170,35 @@ static SECP256K1_INLINE void *manual_alloc(void** prealloc_ptr, size_t alloc_siz
# define I64uFORMAT "llu"
#endif
-#if defined(HAVE___INT128)
-# if defined(__GNUC__)
-# define SECP256K1_GNUC_EXT __extension__
-# else
-# define SECP256K1_GNUC_EXT
+#if defined(__GNUC__)
+# define SECP256K1_GNUC_EXT __extension__
+#else
+# define SECP256K1_GNUC_EXT
+#endif
+
+/* If SECP256K1_{LITTLE,BIG}_ENDIAN is not explicitly provided, infer from various other system macros. */
+#if !defined(SECP256K1_LITTLE_ENDIAN) && !defined(SECP256K1_BIG_ENDIAN)
+/* Inspired by https://github.com/rofl0r/endianness.h/blob/9853923246b065a3b52d2c43835f3819a62c7199/endianness.h#L52L73 */
+# if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
+ defined(_X86_) || defined(__x86_64__) || defined(__i386__) || \
+ defined(__i486__) || defined(__i586__) || defined(__i686__) || \
+ defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) || \
+ defined(__ARMEL__) || defined(__AARCH64EL__) || \
+ (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
+ (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN == 1) || \
+ defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) /* MSVC */
+# define SECP256K1_LITTLE_ENDIAN
# endif
-SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
+# if (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
+ defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) || \
+ defined(__MICROBLAZEEB__) || defined(__ARMEB__) || defined(__AARCH64EB__) || \
+ (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
+ (defined(_BIG_ENDIAN) && _BIG_ENDIAN == 1)
+# define SECP256K1_BIG_ENDIAN
+# endif
+#endif
+#if defined(SECP256K1_LITTLE_ENDIAN) == defined(SECP256K1_BIG_ENDIAN)
+# error Please make sure that either SECP256K1_LITTLE_ENDIAN or SECP256K1_BIG_ENDIAN is set, see src/util.h.
#endif
/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */
@@ -197,10 +219,15 @@ static SECP256K1_INLINE void memczero(void *s, size_t len, int flag) {
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/
static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) {
unsigned int mask0, mask1, r_masked, a_masked;
+ /* Access flag with a volatile-qualified lvalue.
+ This prevents clang from figuring out (after inlining) that flag can
+ take only be 0 or 1, which leads to variable time code. */
+ volatile int vflag = flag;
+
/* Casting a negative int to unsigned and back to int is implementation defined behavior */
VERIFY_CHECK(*r >= 0 && *a >= 0);
- mask0 = (unsigned int)flag + ~0u;
+ mask0 = (unsigned int)vflag + ~0u;
mask1 = ~mask0;
r_masked = ((unsigned int)*r & mask0);
a_masked = ((unsigned int)*a & mask1);
@@ -208,4 +235,21 @@ static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag)
*r = (int)(r_masked | a_masked);
}
+/* If USE_FORCE_WIDEMUL_{INT128,INT64} is set, use that wide multiplication implementation.
+ * Otherwise use the presence of __SIZEOF_INT128__ to decide.
+ */
+#if defined(USE_FORCE_WIDEMUL_INT128)
+# define SECP256K1_WIDEMUL_INT128 1
+#elif defined(USE_FORCE_WIDEMUL_INT64)
+# define SECP256K1_WIDEMUL_INT64 1
+#elif defined(__SIZEOF_INT128__)
+# define SECP256K1_WIDEMUL_INT128 1
+#else
+# define SECP256K1_WIDEMUL_INT64 1
+#endif
+#if defined(SECP256K1_WIDEMUL_INT128)
+SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
+SECP256K1_GNUC_EXT typedef __int128 int128_t;
+#endif
+
#endif /* SECP256K1_UTIL_H */
diff --git a/src/secp256k1/src/valgrind_ctime_test.c b/src/secp256k1/src/valgrind_ctime_test.c
index 60a82d599e..e676a8326c 100644
--- a/src/secp256k1/src/valgrind_ctime_test.c
+++ b/src/secp256k1/src/valgrind_ctime_test.c
@@ -6,6 +6,7 @@
#include <valgrind/memcheck.h>
#include "include/secp256k1.h"
+#include "assumptions.h"
#include "util.h"
#if ENABLE_MODULE_ECDH
@@ -16,6 +17,14 @@
# include "include/secp256k1_recovery.h"
#endif
+#if ENABLE_MODULE_EXTRAKEYS
+# include "include/secp256k1_extrakeys.h"
+#endif
+
+#if ENABLE_MODULE_SCHNORRSIG
+#include "include/secp256k1_schnorrsig.h"
+#endif
+
int main(void) {
secp256k1_context* ctx;
secp256k1_ecdsa_signature signature;
@@ -32,6 +41,9 @@ int main(void) {
secp256k1_ecdsa_recoverable_signature recoverable_signature;
int recid;
#endif
+#if ENABLE_MODULE_EXTRAKEYS
+ secp256k1_keypair keypair;
+#endif
if (!RUNNING_ON_VALGRIND) {
fprintf(stderr, "This test can only usefully be run inside valgrind.\n");
@@ -49,7 +61,9 @@ int main(void) {
msg[i] = i + 1;
}
- ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_DECLASSIFY);
+ ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN
+ | SECP256K1_CONTEXT_VERIFY
+ | SECP256K1_CONTEXT_DECLASSIFY);
/* Test keygen. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
@@ -114,6 +128,30 @@ int main(void) {
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
CHECK(ret);
+ /* Test keypair_create and keypair_xonly_tweak_add. */
+#if ENABLE_MODULE_EXTRAKEYS
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ ret = secp256k1_keypair_create(ctx, &keypair, key);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+
+ /* The tweak is not treated as a secret in keypair_tweak_add */
+ VALGRIND_MAKE_MEM_DEFINED(msg, 32);
+ ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+#endif
+
+#if ENABLE_MODULE_SCHNORRSIG
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ ret = secp256k1_keypair_create(ctx, &keypair, key);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+ ret = secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+#endif
+
secp256k1_context_destroy(ctx);
return 0;
}
diff --git a/src/signet.cpp b/src/signet.cpp
new file mode 100644
index 0000000000..a29f89b58e
--- /dev/null
+++ b/src/signet.cpp
@@ -0,0 +1,149 @@
+// Copyright (c) 2019-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 <signet.h>
+
+#include <array>
+#include <cstdint>
+#include <vector>
+
+#include <consensus/merkle.h>
+#include <consensus/params.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <hash.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <span.h>
+#include <script/interpreter.h>
+#include <script/standard.h>
+#include <streams.h>
+#include <util/strencodings.h>
+#include <util/system.h>
+#include <uint256.h>
+
+static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
+
+static constexpr unsigned int BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
+
+static bool FetchAndClearCommitmentSection(const Span<const uint8_t> header, CScript& witness_commitment, std::vector<uint8_t>& result)
+{
+ CScript replacement;
+ bool found_header = false;
+ result.clear();
+
+ opcodetype opcode;
+ CScript::const_iterator pc = witness_commitment.begin();
+ std::vector<uint8_t> pushdata;
+ while (witness_commitment.GetOp(pc, opcode, pushdata)) {
+ if (pushdata.size() > 0) {
+ if (!found_header && pushdata.size() > (size_t) header.size() && Span<const uint8_t>(pushdata.data(), header.size()) == header) {
+ // pushdata only counts if it has the header _and_ some data
+ result.insert(result.end(), pushdata.begin() + header.size(), pushdata.end());
+ pushdata.erase(pushdata.begin() + header.size(), pushdata.end());
+ found_header = true;
+ }
+ replacement << pushdata;
+ } else {
+ replacement << opcode;
+ }
+ }
+
+ if (found_header) witness_commitment = replacement;
+ return found_header;
+}
+
+static uint256 ComputeModifiedMerkleRoot(const CMutableTransaction& cb, const CBlock& block)
+{
+ std::vector<uint256> leaves;
+ leaves.resize(block.vtx.size());
+ leaves[0] = cb.GetHash();
+ for (size_t s = 1; s < block.vtx.size(); ++s) {
+ leaves[s] = block.vtx[s]->GetHash();
+ }
+ return ComputeMerkleRoot(std::move(leaves));
+}
+
+SignetTxs SignetTxs::Create(const CBlock& block, const CScript& challenge)
+{
+ CMutableTransaction tx_to_spend;
+ tx_to_spend.nVersion = 0;
+ tx_to_spend.nLockTime = 0;
+ tx_to_spend.vin.emplace_back(COutPoint(), CScript(OP_0), 0);
+ tx_to_spend.vout.emplace_back(0, challenge);
+
+ CMutableTransaction tx_spending;
+ tx_spending.nVersion = 0;
+ tx_spending.nLockTime = 0;
+ tx_spending.vin.emplace_back(COutPoint(), CScript(), 0);
+ tx_spending.vout.emplace_back(0, CScript(OP_RETURN));
+
+ // can't fill any other fields before extracting signet
+ // responses from block coinbase tx
+
+ // find and delete signet signature
+ if (block.vtx.empty()) return invalid(); // no coinbase tx in block; invalid
+ CMutableTransaction modified_cb(*block.vtx.at(0));
+
+ const int cidx = GetWitnessCommitmentIndex(block);
+ if (cidx == NO_WITNESS_COMMITMENT) {
+ return invalid(); // require a witness commitment
+ }
+
+ CScript& witness_commitment = modified_cb.vout.at(cidx).scriptPubKey;
+
+ std::vector<uint8_t> signet_solution;
+ if (!FetchAndClearCommitmentSection(SIGNET_HEADER, witness_commitment, signet_solution)) {
+ // no signet solution -- allow this to support OP_TRUE as trivial block challenge
+ } else {
+ try {
+ VectorReader v(SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0);
+ v >> tx_spending.vin[0].scriptSig;
+ v >> tx_spending.vin[0].scriptWitness.stack;
+ if (!v.empty()) return invalid(); // extraneous data encountered
+ } catch (const std::exception&) {
+ return invalid(); // parsing error
+ }
+ }
+ uint256 signet_merkle = ComputeModifiedMerkleRoot(modified_cb, block);
+
+ std::vector<uint8_t> block_data;
+ CVectorWriter writer(SER_NETWORK, INIT_PROTO_VERSION, block_data, 0);
+ writer << block.nVersion;
+ writer << block.hashPrevBlock;
+ writer << signet_merkle;
+ writer << block.nTime;
+ tx_to_spend.vin[0].scriptSig << block_data;
+ tx_spending.vin[0].prevout = COutPoint(tx_to_spend.GetHash(), 0);
+
+ return {tx_to_spend, tx_spending};
+}
+
+// Signet block solution checker
+bool CheckSignetBlockSolution(const CBlock& block, const Consensus::Params& consensusParams)
+{
+ if (block.GetHash() == consensusParams.hashGenesisBlock) {
+ // genesis block solution is always valid
+ return true;
+ }
+
+ const CScript challenge(consensusParams.signet_challenge.begin(), consensusParams.signet_challenge.end());
+ const SignetTxs signet_txs(block, challenge);
+
+ if (!signet_txs.m_valid) {
+ LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution parse failure)\n");
+ return false;
+ }
+
+ const CScript& scriptSig = signet_txs.m_to_sign.vin[0].scriptSig;
+ const CScriptWitness& witness = signet_txs.m_to_sign.vin[0].scriptWitness;
+
+ TransactionSignatureChecker sigcheck(&signet_txs.m_to_sign, /*nIn=*/ 0, /*amount=*/ signet_txs.m_to_spend.vout[0].nValue);
+
+ if (!VerifyScript(scriptSig, signet_txs.m_to_spend.vout[0].scriptPubKey, &witness, BLOCK_SCRIPT_VERIFY_FLAGS, sigcheck)) {
+ LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution invalid)\n");
+ return false;
+ }
+ return true;
+}
diff --git a/src/signet.h b/src/signet.h
new file mode 100644
index 0000000000..5694716fb6
--- /dev/null
+++ b/src/signet.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2019-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_SIGNET_H
+#define BITCOIN_SIGNET_H
+
+#include <consensus/params.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+
+/**
+ * Extract signature and check whether a block has a valid solution
+ */
+bool CheckSignetBlockSolution(const CBlock& block, const Consensus::Params& consensusParams);
+
+/**
+ * Generate the signet tx corresponding to the given block
+ *
+ * The signet tx commits to everything in the block except:
+ * 1. It hashes a modified merkle root with the signet signature removed.
+ * 2. It skips the nonce.
+ */
+class SignetTxs {
+private:
+ struct invalid {};
+ SignetTxs(invalid i) : m_to_spend(), m_to_sign(), m_valid(false) { }
+
+ template<class T1, class T2>
+ SignetTxs(const T1& to_spend, const T2& to_sign) : m_to_spend{to_spend}, m_to_sign{to_sign}, m_valid(true) { }
+
+ static SignetTxs Create(const CBlock& block, const CScript& challenge);
+
+public:
+ SignetTxs(const CBlock& block, const CScript& challenge) : SignetTxs(Create(block, challenge)) { }
+
+ const CTransaction m_to_spend;
+ const CTransaction m_to_sign;
+ const bool m_valid;
+};
+
+#endif // BITCOIN_SIGNET_H
diff --git a/src/sync.cpp b/src/sync.cpp
index 4be13a3c48..322198a852 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -238,12 +238,15 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
template void AssertLockHeldInternal(const char*, const char*, int, Mutex*);
template void AssertLockHeldInternal(const char*, const char*, int, RecursiveMutex*);
-void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
+template <typename MutexType>
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs)
{
if (!LockHeld(cs)) return;
tfm::format(std::cerr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld());
abort();
}
+template void AssertLockNotHeldInternal(const char*, const char*, int, Mutex*);
+template void AssertLockNotHeldInternal(const char*, const char*, int, RecursiveMutex*);
void DeleteLock(void* cs)
{
diff --git a/src/sync.h b/src/sync.h
index 05ff2ee8a9..7b397a8003 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -53,8 +53,9 @@ void LeaveCritical();
void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
std::string LocksHeld();
template <typename MutexType>
-void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) ASSERT_EXCLUSIVE_LOCK(cs);
-void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
+void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
+template <typename MutexType>
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs);
void DeleteLock(void* cs);
bool LockStackEmpty();
@@ -69,8 +70,9 @@ inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, v
inline void LeaveCritical() {}
inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
template <typename MutexType>
-inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) ASSERT_EXCLUSIVE_LOCK(cs) {}
-inline void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
+inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}
+template <typename MutexType>
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) {}
inline void DeleteLock(void* cs) {}
inline bool LockStackEmpty() { return true; }
#endif
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index b3cc8cefd9..0ad5066603 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -12,6 +12,7 @@
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
+#include <crypto/sha3.h>
#include <crypto/sha512.h>
#include <random.h>
#include <test/util/setup_common.h>
@@ -750,4 +751,110 @@ BOOST_AUTO_TEST_CASE(sha256d64)
}
}
+static void TestSHA3_256(const std::string& input, const std::string& output)
+{
+ const auto in_bytes = ParseHex(input);
+ const auto out_bytes = ParseHex(output);
+
+ SHA3_256 sha;
+ // Hash the whole thing.
+ unsigned char out[SHA3_256::OUTPUT_SIZE];
+ sha.Write(in_bytes).Finalize(out);
+ assert(out_bytes.size() == sizeof(out));
+ BOOST_CHECK(std::equal(std::begin(out_bytes), std::end(out_bytes), out));
+
+ // Reset and split randomly in 3
+ sha.Reset();
+ int s1 = InsecureRandRange(in_bytes.size() + 1);
+ int s2 = InsecureRandRange(in_bytes.size() + 1 - s1);
+ int s3 = in_bytes.size() - s1 - s2;
+ sha.Write(MakeSpan(in_bytes).first(s1)).Write(MakeSpan(in_bytes).subspan(s1, s2));
+ sha.Write(MakeSpan(in_bytes).last(s3)).Finalize(out);
+ BOOST_CHECK(std::equal(std::begin(out_bytes), std::end(out_bytes), out));
+}
+
+BOOST_AUTO_TEST_CASE(keccak_tests)
+{
+ // Start with the zero state.
+ uint64_t state[25] = {0};
+ CSHA256 tester;
+ for (int i = 0; i < 262144; ++i) {
+ KeccakF(state);
+ for (int j = 0; j < 25; ++j) {
+ unsigned char buf[8];
+ WriteLE64(buf, state[j]);
+ tester.Write(buf, 8);
+ }
+ }
+ uint256 out;
+ tester.Finalize(out.begin());
+ // Expected hash of the concatenated serialized states after 1...262144 iterations of KeccakF.
+ // Verified against an independent implementation.
+ BOOST_CHECK_EQUAL(out.ToString(), "5f4a7f2eca7d57740ef9f1a077b4fc67328092ec62620447fe27ad8ed5f7e34f");
+}
+
+BOOST_AUTO_TEST_CASE(sha3_256_tests)
+{
+ // Test vectors from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/sha3/sha-3bytetestvectors.zip
+
+ // SHA3-256 Short test vectors (SHA3_256ShortMsg.rsp)
+ TestSHA3_256("", "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a");
+ TestSHA3_256("e9", "f0d04dd1e6cfc29a4460d521796852f25d9ef8d28b44ee91ff5b759d72c1e6d6");
+ TestSHA3_256("d477", "94279e8f5ccdf6e17f292b59698ab4e614dfe696a46c46da78305fc6a3146ab7");
+ TestSHA3_256("b053fa", "9d0ff086cd0ec06a682c51c094dc73abdc492004292344bd41b82a60498ccfdb");
+ TestSHA3_256("e7372105", "3a42b68ab079f28c4ca3c752296f279006c4fe78b1eb79d989777f051e4046ae");
+ TestSHA3_256("0296f2c40a", "53a018937221081d09ed0497377e32a1fa724025dfdc1871fa503d545df4b40d");
+ TestSHA3_256("e6fd42037f80", "2294f8d3834f24aa9037c431f8c233a66a57b23fa3de10530bbb6911f6e1850f");
+ TestSHA3_256("37b442385e0538", "cfa55031e716bbd7a83f2157513099e229a88891bb899d9ccd317191819998f8");
+ TestSHA3_256("8bca931c8a132d2f", "dbb8be5dec1d715bd117b24566dc3f24f2cc0c799795d0638d9537481ef1e03e");
+ TestSHA3_256("fb8dfa3a132f9813ac", "fd09b3501888445ffc8c3bb95d106440ceee469415fce1474743273094306e2e");
+ TestSHA3_256("71fbacdbf8541779c24a", "cc4e5a216b01f987f24ab9cad5eb196e89d32ed4aac85acb727e18e40ceef00e");
+ TestSHA3_256("7e8f1fd1882e4a7c49e674", "79bef78c78aa71e11a3375394c2562037cd0f82a033b48a6cc932cc43358fd9e");
+ TestSHA3_256("5c56a6b18c39e66e1b7a993a", "b697556cb30d6df448ee38b973cb6942559de4c2567b1556240188c55ec0841c");
+ TestSHA3_256("9c76ca5b6f8d1212d8e6896ad8", "69dfc3a25865f3535f18b4a7bd9c0c69d78455f1fc1f4bf4e29fc82bf32818ec");
+ TestSHA3_256("687ff7485b7eb51fe208f6ff9a1b", "fe7e68ae3e1a91944e4d1d2146d9360e5333c099a256f3711edc372bc6eeb226");
+ TestSHA3_256("4149f41be1d265e668c536b85dde41", "229a7702448c640f55dafed08a52aa0b1139657ba9fc4c5eb8587e174ecd9b92");
+ TestSHA3_256("d83c721ee51b060c5a41438a8221e040", "b87d9e4722edd3918729ded9a6d03af8256998ee088a1ae662ef4bcaff142a96");
+ TestSHA3_256("266e8cbd3e73d80df2a49cfdaf0dc39cd1", "6c2de3c95900a1bcec6bd4ca780056af4acf3aa36ee640474b6e870187f59361");
+ TestSHA3_256("a1d7ce5104eb25d6131bb8f66e1fb13f3523", "ee9062f39720b821b88be5e64621d7e0ca026a9fe7248d78150b14bdbaa40bed");
+ TestSHA3_256("d751ccd2cd65f27db539176920a70057a08a6b", "7aaca80dbeb8dc3677d18b84795985463650d72f2543e0ec709c9e70b8cd7b79");
+ TestSHA3_256("b32dec58865ab74614ea982efb93c08d9acb1bb0", "6a12e535dbfddab6d374058d92338e760b1a211451a6c09be9b61ee22f3bb467");
+ TestSHA3_256("4e0cc4f5c6dcf0e2efca1f9f129372e2dcbca57ea6", "d2b7717864e9438dd02a4f8bb0203b77e2d3cd8f8ffcf9dc684e63de5ef39f0d");
+ TestSHA3_256("d16d978dfbaecf2c8a04090f6eebdb421a5a711137a6", "7f497913318defdc60c924b3704b65ada7ca3ba203f23fb918c6fb03d4b0c0da");
+ TestSHA3_256("47249c7cb85d8f0242ab240efd164b9c8b0bd3104bba3b", "435e276f06ae73aa5d5d6018f58e0f009be351eada47b677c2f7c06455f384e7");
+ TestSHA3_256("cf549a383c0ac31eae870c40867eeb94fa1b6f3cac4473f2", "cdfd1afa793e48fd0ee5b34dfc53fbcee43e9d2ac21515e4746475453ab3831f");
+ TestSHA3_256("9b3fdf8d448680840d6284f2997d3af55ffd85f6f4b33d7f8d", "25005d10e84ff97c74a589013be42fb37f68db64bdfc7626efc0dd628077493a");
+ TestSHA3_256("6b22fe94be2d0b2528d9847e127eb6c7d6967e7ec8b9660e77cc", "157a52b0477639b3bc179667b35c1cdfbb3eef845e4486f0f84a526e940b518c");
+ TestSHA3_256("d8decafdad377904a2789551135e782e302aed8450a42cfb89600c", "3ddecf5bba51643cd77ebde2141c8545f862067b209990d4cb65bfa65f4fa0c0");
+ TestSHA3_256("938fe6afdbf14d1229e03576e532f078898769e20620ae2164f5abfa", "9511abd13c756772b852114578ef9b96f9dc7d0f2b8dcde6ea7d1bd14c518890");
+ TestSHA3_256("66eb5e7396f5b451a02f39699da4dbc50538fb10678ec39a5e28baa3c0", "540acf81810a199996a612e885781308802fe460e9c638cc022e17076be8597a");
+ TestSHA3_256("de98968c8bd9408bd562ac6efbca2b10f5769aacaa01365763e1b2ce8048", "6b2f2547781449d4fa158180a178ef68d7056121bf8a2f2f49891afc24978521");
+ TestSHA3_256("94464e8fafd82f630e6aab9aa339d981db0a372dc5c1efb177305995ae2dc0", "ea7952ad759653cd47a18004ac2dbb9cf4a1e7bba8a530cf070570c711a634ea");
+ TestSHA3_256("c178ce0f720a6d73c6cf1caa905ee724d5ba941c2e2628136e3aad7d853733ba", "64537b87892835ff0963ef9ad5145ab4cfce5d303a0cb0415b3b03f9d16e7d6b");
+ TestSHA3_256("14365d3301150d7c5ba6bb8c1fc26e9dab218fc5d01c9ed528b72482aadee9c27bef667907797d55514468f68791f053daa2df598d7db7d54beea493bdcbb0c75c7b36ad84b9996dca96354190bd96d9d7fbe8ff54ffaf77c55eb92985da50825ee3b4179f5ec88b6fa60bb361d0caf9493494fe4d28ef843f0f498a2a9331b82a", "9b690531dee948a9c559a2e0efab2ec824151a9175f2730a030b748d07cbaa7f");
+ TestSHA3_256("4a757db93f6d4c6529211d70d5f8491799c0f73ae7f24bbd2138db2eaf2c63a85063b9f7adaa03fc348f275323248334e3ffdf9798859f9cf6693d29566ff7d50976c505ecb58e543c459b39acdf4ce4b5e80a682eaa7c1f1ce5fe4acb864ff91eb6892b23165735ea49626898b40ceeb78161f5d0ea4a103cb404d937f9d1dc362b", "1ac7cc7e2e8ea14fb1b90096f41265100712c5dd41519d78b2786cfb6355af72");
+ TestSHA3_256("da11c39c77250f6264dda4b096341ff9c4cc2c900633b20ea1664bf32193f790a923112488f882450cf334819bbaca46ffb88eff0265aa803bc79ca42739e4347c6bff0bb9aa99780261ffe42be0d3b5135d03723338fb2776841a0b4bc26360f9ef769b34c2bec5ed2feb216e2fa30fa5c37430c0360ecbfba3af6fb6b8dedacbb95c", "c163cd43de224ac5c262ae39db746cfcad66074ebaec4a6da23d86b310520f21");
+ TestSHA3_256("3341ca020d4835838b0d6c8f93aaaebb7af60730d208c85283f6369f1ee27fd96d38f2674f316ef9c29c1b6b42dd59ec5236f65f5845a401adceaa4cf5bbd91cac61c21102052634e99faedd6cdddcd4426b42b6a372f29a5a5f35f51ce580bb1845a3c7cfcd447d269e8caeb9b320bb731f53fe5c969a65b12f40603a685afed86bfe53", "6c3e93f2b49f493344cc3eb1e9454f79363032beee2f7ea65b3d994b5cae438f");
+ TestSHA3_256("989fc49594afc73405bacee4dbbe7135804f800368de39e2ea3bbec04e59c6c52752927ee3aa233ba0d8aab5410240f4c109d770c8c570777c928fce9a0bec9bc5156c821e204f0f14a9ab547e0319d3e758ae9e28eb2dbc3d9f7acf51bd52f41bf23aeb6d97b5780a35ba08b94965989744edd3b1d6d67ad26c68099af85f98d0f0e4fff9", "b10adeb6a9395a48788931d45a7b4e4f69300a76d8b716c40c614c3113a0f051");
+ TestSHA3_256("e5022f4c7dfe2dbd207105e2f27aaedd5a765c27c0bc60de958b49609440501848ccf398cf66dfe8dd7d131e04f1432f32827a057b8904d218e68ba3b0398038d755bd13d5f168cfa8a11ab34c0540873940c2a62eace3552dcd6953c683fdb29983d4e417078f1988c560c9521e6f8c78997c32618fc510db282a985f868f2d973f82351d11", "3293a4b9aeb8a65e1014d3847500ffc8241594e9c4564cbd7ce978bfa50767fe");
+ TestSHA3_256("b1f6076509938432145bb15dbe1a7b2e007934be5f753908b50fd24333455970a7429f2ffbd28bd6fe1804c4688311f318fe3fcd9f6744410243e115bcb00d7e039a4fee4c326c2d119c42abd2e8f4155a44472643704cc0bc72403b8a8ab0fd4d68e04a059d6e5ed45033b906326abb4eb4147052779bad6a03b55ca5bd8b140e131bed2dfada", "f82d9602b231d332d902cb6436b15aef89acc591cb8626233ced20c0a6e80d7a");
+ TestSHA3_256("56ea14d7fcb0db748ff649aaa5d0afdc2357528a9aad6076d73b2805b53d89e73681abfad26bee6c0f3d20215295f354f538ae80990d2281be6de0f6919aa9eb048c26b524f4d91ca87b54c0c54aa9b54ad02171e8bf31e8d158a9f586e92ffce994ecce9a5185cc80364d50a6f7b94849a914242fcb73f33a86ecc83c3403630d20650ddb8cd9c4", "4beae3515ba35ec8cbd1d94567e22b0d7809c466abfbafe9610349597ba15b45");
+
+ // SHA3-256 Long test vectors (SHA3_256LongMsg.rsp)
+ TestSHA3_256("b1caa396771a09a1db9bc20543e988e359d47c2a616417bbca1b62cb02796a888fc6eeff5c0b5c3d5062fcb4256f6ae1782f492c1cf03610b4a1fb7b814c057878e1190b9835425c7a4a0e182ad1f91535ed2a35033a5d8c670e21c575ff43c194a58a82d4a1a44881dd61f9f8161fc6b998860cbe4975780be93b6f87980bad0a99aa2cb7556b478ca35d1f3746c33e2bb7c47af426641cc7bbb3425e2144820345e1d0ea5b7da2c3236a52906acdc3b4d34e474dd714c0c40bf006a3a1d889a632983814bbc4a14fe5f159aa89249e7c738b3b73666bac2a615a83fd21ae0a1ce7352ade7b278b587158fd2fabb217aa1fe31d0bda53272045598015a8ae4d8cec226fefa58daa05500906c4d85e7567", "cb5648a1d61c6c5bdacd96f81c9591debc3950dcf658145b8d996570ba881a05");
+ TestSHA3_256("712b03d9ebe78d3a032a612939c518a6166ca9a161183a7596aa35b294d19d1f962da3ff64b57494cb5656e24adcf3b50e16f4e52135d2d9de76e94aa801cf49db10e384035329c54c9455bb3a9725fd9a44f44cb9078d18d3783d46ce372c31281aecef2f8b53d5702b863d71bc5786a33dd15d9256103b5ff7572f703d5cde6695e6c84f239acd1d6512ef581330590f4ab2a114ea064a693d5f8df5d908587bc7f998cde4a8b43d8821595566597dc8b3bf9ea78b154bd8907ee6c5d4d8a851f94be510962292b7ddda04d17b79fab4c022deb400e5489639dbc448f573d5cf72073a8001b36f73ac6677351b39d9bdb900e9a1121f488a7fa0aee60682e7dc7c531c85ec0154593ded3ae70e4121cae58445d8896b549cacf22d07cdace7625d57158721b44851d796d6511c38dac28dd37cbf2d7073b407fbc813149adc485e3dacee66755443c389d2d90dc70d8ff91816c0c5d7adbad7e30772a1f3ce76c72a6a2284ec7f174aefb6e9a895c118717999421b470a9665d2728c3c60c6d3e048d58b43c0d1b5b2f00be8b64bfe453d1e8fadf5699331f9", "095dcd0bc55206d2e1e715fb7173fc16a81979f278495dfc69a6d8f3174eba5a");
+ TestSHA3_256("2a459282195123ebc6cf5782ab611a11b9487706f7795e236df3a476404f4b8c1e9904e2dc5ef29c5e06b179b8649707928c3913d1e53164747f1fa9bba6eeaf8fb759d71e32adc8c611d061345882f1cdeee3ab4cab3554adb2e43f4b01c37b4546994b25f4dcd6c497bc206865643930157cb5b2f4f25be235fa223688535907efcc253bcd083021407ea09cb1c34684aa0c1849e7efe2d9af6938c46525af9e5afb4da6e5b83da4b61dc718672a8090549cbe5aadb44f5bc93a6b3fbdc2e6d32e2eaaae637465179ea17f23ad1e4f1ebc328e2c6dc90c302b74a1edbbb0676c136b269d70c41040a313af06ab291bf489d9700950b77f207c1fc41884799931b3bca8b93331a6e96b7a3f0a8bd24cdb64964c377e0512f36444bb0643a4e3ecb328194cd5428fd89ede167472a14a9bf5730aff1e3b2c708de96eff1ebaaf63beb75f9c7d8034d6e5471e8f8a1f7efce37793a958e134619c19c54d3d42645f7a7263f25471fbaae8be3ea2fbd34ec6d7aacd7d5680948c3cd9a837c9c469a88f600d95829f4d1e4e4a5ef4ed4623c07815a1c33d9fb3b91333ff04eac92806a68a46cf2e9293f8bff466ce87fe66b46fbff7c238c7f9b2c92eb2fdc7d8084167f6f4e680d03301e5c33f78f1857d6863b1b8c36c7fce3e07d2a96a8979712079ae0023a1e3970165bfcf3a5463d2a4fdf1ca0e044f9a247528cd935734cb6d85ba53ceb95325c0eaf0ff5cd81ecb32e58917eb26bfc52dba3704bf5a927fee3220", "cb1c691c87244c0caf733aacd427f83412cd48820b358c1b15dd9fadee54e5af");
+ TestSHA3_256("32659902674c94473a283be00835eb86339d394a189a87da41dad500db27da6b6a4753b2bb219c961a227d88c6df466ba2fc1e9a2d4c982db4398778c76714d5e9940da48bc3808f3c9989131a07683b8c29d6af336e9aee1dfa57d83c48a86f17146edec07869bb06550689ebf4788159ed0a921048b4a6e3e3ec272413bec15d8e1f6a40897fa0e11d9df223ef9fc270106249ae220fdc6ebdef6d6611805421ccc850f53ee9c836baf657a94005883b5a85def344d218264f07b2ea8714afcc941096c6ded0bb6bf5b8bf652fd15a21931c58c9f526e27363ddff98c0a25bc7af9f469ab35bffea948b333f042cc18a82cec0177f33c3bdbf185b580353de79e51e675b03b31e195f19ba1f063d44def0441dc52820426c2c61cf12974ec249fd3502f017ffa06220075ced7e2d6b86a52677ba3916e8e8726062aec5bc8ea1c18b1e4137680b2c9d002191b423bee8691bd7e0f93c3b9959bc1c14d5c5cbe8f7c9c336aa16e9de9faa12f3f048c66d04cb441eb2bbc5e8a91e052c0f9000856896f9b7ba30c1e2eead36fc7ac30a7d3ddfc65caaba0e3b292d26dfba46b5e2dc9bc9acadde1c9f52b2969299bd1281ddff65822b629cfba2928613200e73661b803afdcc4a817d9361389e975e67dfadd22a797bdaf991ddf42db18711c079ecec55925f9978e478612609bacd900172011c27e24bad639ffc24a23877278318872153aef6893ccb5b68b94b33154df7334375aadd3edbb35272cc7b672dec68faa62900873ded52f6049891b77f2d0311a84b19b73660e09d1f1998095c1da1edecfa9f741b5fd6db048dd68255085d43529279021d59ed853470d6863b7c8e07fcb0d1e6acfb1eb16f7f60bb1f46ce70493010e57930a3b4b8b87e065272f6f1dd31df057627f4214e58798b664e1e40960f2789d44ccacfb3dbd8b02a68a053976711f8034c1ed3a8", "5ac9275e02543410359a3f364b2ae3b85763321fd6d374d13fe54314e5561b01");
+ TestSHA3_256("a65da8277a3b3738432bca9822d43b3d810cdad3b0ed2468d02bd269f1a416cd77392190c2dde8630eeb28a297bda786017abe9cf82f14751422ac9fff6322d5d9a33173db49792d3bc37fff501af667f7ca3dd335d028551e04039ef5a9d42a9443e1b80ea872fd945ad8999514ae4a29a35f60b0f7e971b67ae04d1ba1b53470c03847a3225c3ddf593a57aed3599661ae2d2bb1cddd2fa62c4a94b8704c5c35c33e08e2debe54e567ae21e27e7eb36593ae1c807a8ef8b5c1495b15412108aaf3fce4130520aa6e2d3bdf7b3ea609fdf9ea1c64258435aae2e58a7b3abda198f979c17dbe0aa74253e979bf3a5800f388ea11a7f7454c4e36270a3083a790c77cbe89693205b32880c0d8f79b1c000ee9b5e58f175ba7696616c17c45673cff25d1221f899836e95cc9e26a887a7115c4537e65ad4eacc319ba98a9a8860c089cbc76e7ea4c984d900b80622afbbbd1c0cdc670e3a4c523f81c77fed38b6aa988876b097da8411cc48e9b25a826460a862aa3fadfe75952aa4347c2effebdac9138ebcc6c34991e9f5b19fc2b847a87be72ff49c99ecf19d837ee3e23686cd760d9dd7adc78091bca79e42fdb9bc0120faec1a6ca52913e2a0156ba9850e1f39d712859f7fdf7daedf0e206dff67e7121e5d1590a8a068947a8657d753e83c7f009b6b2e54acc24afc9fdc9601a1d6d9d1f17aab0ce96c4d83405d1e3baba1dffa86ecccee7f1c1b80b1bbf859106ce2b647ae1e4a6a9b584ae1dfc0a4deebb755638f1d95dcc79b1be263177e2a05c72bde545d09ba726f41d9547117e876af81bfc672e33c71442eb05675d9552df1b313d1f9934f9ddd08955fa21d6edf23000a277f6f149591299a0a96032861ecdc96bb76afa05a2bffb445d61dc891bc70c13695920b911cad0df3fa842a3e2318c57556974343f69794cb8fa18c1ad624835857e4781041198aa705c4d11f3ef82e941be2aee7a770e54521312fe6facbaf1138eee08fa90fae986a5d93719aeb30ac292a49c1d91bf4574d553a92a4a6c305ab09db6bbeffd84c7aa707f1c1628a0220d6ba4ee5e960566686228a6e766d8a30dddf30ed5aa637c949950c3d0e894a7560670b6879a7d70f3c7e5ab29aed236cc3527bdea076fec8add12d784fbcf9a", "68f62c418a6b97026cc70f6abf8419b671ee373709fa13074e37bd39f0a50fcb");
+ TestSHA3_256("460f8c7aac921fa9a55800b1d04cf981717c78217cd43f98f02c5c0e66865c2eea90bcce0971a0d22bc1c74d24d9bfea054e558b38b8502fccb85f190d394f2f58f581a02d3b9cc986f07f5a67d57ab4b707bd964ecc10f94f8cc538b81eeb743746c537407b7b575ced0e1ec4c691a72eb0978be798e8be22b278b390be99c730896fdc69b6a44456be5ee261366e8b1351cbb22aa53e45ec325ed2bca0bfeeebc867d7d07681581b6d56ed66ac78280df04053407a7b57561261dd644cc7b20f0a95709e42795b5402dd89fcb11746c597e0b650a008bc085c681bb24b17db4458e1effba3f414a883ddfc4bccb3ace24d9223839d4b3ca9185ad5cc24193134b9339b0e205a4cc0fa3d8f7a85b4230d1b3ee101fbae9ee14c2153da5f337c853573bd004114cb436ee58ab1648373ee07cc39f14198ac5a02a4dd0585cf83dfd4899df88e8859dae8bc351af286642c1c25737bf8712cb941cbbb741d540feb9f5d831f901fbe2d6facd7dab626bd705f2fd7c9a7a0e7a9127e3451af2ae8509dd7b79dce41c1e30b9dba1c38cb4861dad3ac00d68fa5d07ba591c1c3b9d6b7d6e08099d0572ca4c475240601decba894fa3c4b0ea52ed687281beee268a1c8535e283b1fc7c51aa31d5ec098c50fec958acdd0d54a49643bef170093a1102a1b3bf5ad42fb55ebaf7db07385eadcd6e66da8b7b6e6c022a1e3d01f5fccec86365d3014c159a3bff17d614751b3fa0e8e89152936e159b7c0ea8d71cd4ffd83adae209b254b793f6f06bb63838a303b95c85b4edfa4ddcca0ed952165930bca87140f67f5389d1233fe04f0a3d647050410c44d389513084ad53155af00de02cc7943a3b988d8e1454f85153aff0816e24b964ec91dc514c588a93634ff3dd485c40575faa2f254abdf86fbcf6d381337601a7b1ba5b99719f045eb7bf6f2e8b9dd9d053ef0b3126f984fc9ea87a2a70b3798fab593b83a4ff44d9c0c4ec3e570ac537c10d9e3c4996027a813b70d7867b858f31f508aa56e7b087370707974b2186f02f5c549112f2158c0d365402e52cba18fe245f77f7e6fbf952ec2dc3c880b38be771caea23bc22838b1f70472d558bdf585d9c77088b7ba2dceaeb3e6f96df7d91d47da1ec42be03936d621ecf747f24f9073c122923b4161d99bc8190e24f57b6fac952ed344c7eae86a5f43c08089c28c7daf3aa7e39c59d6f1e17ece1977caf6b4a77a6ff52774521b861f38ebc978005e5763cc97123e4d17c7bc4134c8f139c7d7a9a02646fef9525d2a6871fc99747e81430b3fec38c677427c6f5e2f16c14eee646ebf6eb16775ad0957f8684c7045f7826bc3736eca", "7d495ddf961cbff060f80b509f2b9e20bed95319eef61c7adb5edeec18e64713");
+ TestSHA3_256("c8a2a26587d0126abe9ba8031f37d8a7d18219c41fe639bc7281f32d7c83c376b7d8f9770e080d98d95b320c0f402d57b7ef680da04e42dd5211aacf4426ecca5050ca596312cfae79cee0e8c92e14913cc3c66b24ece86c2bfa99078991faad7b513e94f0b601b7853ddb1eb3c9345f47445a651389d070e482ea5db48d962820257daf1cbe4bb8e5f04a3637d836c8c1bc4d83d6eda5f165f2c2592be268412712ae324ef054bb812f56b8bc25c1d59071c64dd3e00df896924c84575817027861faa5f016c5c74142272daa767e8c9dacee4c732ab08b5fa9ad65a0b74c73fb5a889169f645e50d70e41d689415f7d0b4ec071e9238b5a88110856fc6ae9b9944817e21597d1ccd03b60e60472d1e11d3e9063de24a7b59609b6a2a4ee68238690cf2800614746941c48af9566e07494f0dd236e091e75a8f769e3b179b30c10f5277eec7b3f5c97337189b8b82bc5e717ff27355b2009356caa908e976ae1d7f7a94d36202a8d5e03641aeac0e453a8168ee5a0858ceecfcbf11fb8c1f033201add297a0a89476d2ea8b9a82bda8c3c7ef4f55c3295a4ecb7c607ac73d37eadc13b7a2494ec1928f7a80c8d534efe38a3d9ccb4ccdab9f092a1def6478532c5ad3cd5c259b3812600fa89e6d1e228114795d246cedc9c9fff0d1c1297a5ddfc1169c2efb3800df8dd18a8511214785abcc1bc7eb31bdb2f5f70358dfe860ed5a03ab7e95cc21df5ee7aee68be568d6985e5c1e91408e4432663b1c4e6d613d6dc382b5b900a4fc1b7a9c27a1138c5e2356ab9026c34465006602753daf6ab7427da93c307c901d0bb1ddb21c53bc0493dd8d857161e8ffa51fdecb75568243205aa979c2e7ed2a77b5f8edc34cffb0321a8c653bc381f96ab85a86bf0bb2c9518208d636eac40aa7ad754260a75d4a46362f994c90173b975afb0ee17601311b1c51ba562c1ca7e3c2dd18b90bdebb1858fe876c71b3ad742c4bcba33e7763c750098de856fde8731cb6d698218be9f0a98298630e5b374957d126cf0b1c489c48bab6b50f6fb59ee28be6c3916bbd16514234f80e1ac15d0215852b87f9c6e429eb9f85007bf6ae3de1af0202861fd177c7c4f51af533f956a051815815c6e51e25af20d02893e95442991f1de5f86a4397ae20d9f675657bf9f397267831e94cef4e4d287f759850350ce0898f2e29de3c5c41f4246fe998a8d1359a2bed36ded1e4d6b08682025843700fee8cab56703e342212870acdd53655255b35e414fa53d9810f47a37195f22d72f6e555392023a08adc282c585b2ae62e129efccdc9fe9617eecac12b2ecdabd247a1161a17750740f90ebed3520ceb17676f1fa87259815ff415c2794c5953f689c8d5407dbbd10d1241a986e265cea901af34ec1ded0323ca3290a317208ba865637af4797e65b9cfcad3b931bbf6ac896623e2f4408529172911f1b6a9bcae8279ec7e33452d0cd7b026b46a99cbe8a69cd4d21cdc6d3a84002fab527c4fd18a121526d49890ced3fb89beb384b524015a2e03c049241eb9", "b8d4b29b086ef6d6f73802b9e7a4f2001e384c8258e7046e6779662fd958517e");
+ TestSHA3_256("3a86a182b54704a3af811e3e660abcfbaef2fb8f39bab09115c1068976ff694bb6f5a3839ae44590d73e4996d45af5ceb26b03218ab3fef6f5f4ef48d22839fb4371c270f9535357b22142c4ffb54e854b64cab41932fe888d41ca702e908c63eae244715bfbf69f481250f16f848dc881c6996e6f9d76f0e491de2c129f2a2ab22e72b04644f610a2fabc45aa2d7b3e5d77b87a135d2fd502ca74a207bddaf9a43e945245961a53c7bfcfe73a1ae090e6606ffe8ddbf1e0f0d6d4fa94526578c6faf282dd592b10bf4bce00a7b1846625690623667e83b9b59b465d42c6944e224ad36698f5f2ee938404b7775c2e66207bc41025adaf07590312f398812d24c0178126fdd334964a54b8353482a83be17cf2ee52d23b72e5f57fe31eebf8a1a64742eb9459bcb0eca231a1658ab88b7056d8e47554f0a46058d6565c6cbf6edec45fdde6f051e38255b82493de27ffd3efbe1b179b9642d2166073db6d4832707420237a00bad7125795e645e5bc3e1431ecbabf0ff5f74416626322545c966241cce6d8f2c035a78f100e030741f13b02a9eaf618d468bc40274db98bc342be12ad4d892c2ba546e571c556ac7cbf4e4c3fd3431efd40457cf65a297845dd8cce09811418c3cef941ff32c43c375157f6f49c2e893625e4b216b1f985aa0fd25f29a9011d4f59c78b037ed71f384e5de8116e3fc148c0a3cad07cb119b9829aac55eed9a299edb9abc5d017be485f690add70ff2efbb889ac6ce0da9b3bdbeb9dd47823116733d58a8d510b7f2e2c8244a2cbf53816b59e413207fb75f9c5ce1af06e67d182d3250ea3283bcbb45cb07ea6a6aa486361eb6f69199c0eb8e6490beff82e4ab274b1204e7f2f0ba097fba0332aa4c4a861771f5b3d45ce43e667581a40fee4bebe7fa9d87b70a5bb876c928f7e6d16ae604b3a4e9c7f1d616e2deab96b6207705b9a8f87468503cdd20a3c02cc8da43d046da68b5ed163d926a5a714a4df1b8ef007bca408f68b9e20de86d6398ad81df5e74d5aaac40874b5d6787211ff88e128cf1676e84ca7f51aee5951efee1915dcc11502a8df74fac4c8451dda49b631a8fb87470f0ebe9b67449bbd1640ceee6101e8cd82aa1033fa84f75b28450e461b93f65da5c43759b0e83660d50961702bb1ad015dad42e600117475237cf6e7279d4a02d1f67cf59de0108355d03963e3d84ce7647173dd7d77a6b3f275d7de74236d7bbb2df437d536136dbe1dbe8f307facc7bc7d0cde1abf745cbeb81af1ab2c46138cf007e901f22668377958bcbbadb7e9905973b27ff0c5baaece25e974c1bd116cc81dd1c81a30bae86a6fb12c6a5494068e122153128313eb3e628d76e9babc823c9eb9d3b81bacfa7a6b372abe6b1246a350f23e2e95b09c9037a75aac255ef7d4f267cad3ce869531b4165db2e5a9792094efea4ae3d9ea4d0efdc712e63df21882a353743190e016b2166e4da8a2c78e48defc7155d5fdfc4e596624e6a19c91b43719a22c1204b1cefe05989d455773d3881fa8d3eefc255f81dfe90bd41dc6f1e9c265a753298a6e98c999acd9525a9db5f9f9456a0f51a93dd9693e1d9c3fa283f7c58a9c752afcaa635abea8dfc80e2c326b939260069457fdad68c341852dcb5fcbbd351318defd7ae3b9f827478eb77306a5ae14cf8895f2bc6f0f361ffc8aa37e286629dc7e59b73a8712525e851c64d363065631edc1609f3d49a09575876a", "b71ec00c0fcc4f8663312711540df1cd236eb52f237409415b749ff9436dc331");
+ TestSHA3_256("c041e23b6d55998681802114abc73d2776967cab715572698d3d497ec66a790b0531d32f45b3c432f5b2d8039ea47de5c6060a6514f3ff8fb5f58e61fd1b5b80524c812a46dad56c035a6e95ecb465ea8176d99b836e36f65977b7dbb3932a706d3af415b6f2549b7120ecb0db1e7d9e6f8df23607eda006436bccd32ef96d431fa434d9de22ca2608ab593eb50b4d6a57f45c1ce698c3283a77d330b876ad6030324a5c0693be7790a4bd26c0a25eb403531f37689829c20546d6dc97327131688b3d88766db8f5d1b22050450c37e53951446dd7155a3e6d7edcbe1354411d8f58154475d74008937e8ba48b706066c296d1a87936dd023ac8eebe7605a58c6c40da774cf9df189db0050adcf7629e66cbd1cf9824397834cb13c4066c26e6c8ec950b44fc1c8db8ef976a7ec8c4f4ec9849ca7a07f906223053b80db24b946b034ee7a30880d0ace348acba0d0ed21ea443816706a216ce9eb682d1fe9dfc1d2e0bf3b1449247413520b8d8ebc99fc298c6dca949be0ffebe450b9b79a387a615d617b8d9da5b3e8d2776208c7cc2a11bdbc387f9d4597b380739b24ae59dcd5fb63bfeefe0746d9266cfda18afa583d6891e483e6d5c0db305f5609beba75bb5b447ccac2dfb94ede4a94db6eaaf3070d8d5353f107f7bd74528eb913e0b19bed6236a3b48567c46a9eec28fb6486f92d0d09625452d8f4dd1b89c566533cc2326b820c2b9efed43be8481cb9ad809e47af7b31795cb0fbdb18fbb12e8853f8bacec366a092daf8f2a55d2911fc7c70ddd33d33e86c2c4ceeb9390ec506b399f6fa8f35abf7789d0f547fd09cb7e6fb6016a3fc2a27a762989ae620d234c810777d5a1bb633744af2844495d2963c986ef8540ca715bed7692c77b9dec90e06acc5986b47dd4a8d3ca3300b2bedf9f26ae6d1c7e7acef05c0fc521c3309e1e70771eea6e96b67de5e3fb6833145bb73d46081b074539498307929da779e003c27f0a171035458b8c7c86c905b23dda74c040878d5a05be94821537724ebd5608ec0754c3e3e99a719bbb6d5320eed07323fca637429b18378936364c389de1e9c6fce8af270a713b4b829b43e7d761e17724c22e84611e1322dde45cbee86a0e16d01cfb8910d99391c39afd8e5f5567c59f219aa8c19ad158f287cb6807ba1fe46d38d091639a217766b3aa9ded73ac14570ba236225218305d68c0be6099c336ba8455c86b7c8c04542e729ceb84596c33ca6eb7ec1091b406cf64495ccfa2169f47b3b590477d4073537c14c05015d51ba527b3869ae4ebd603df906323658b04cb11e13bc29b34ac69f18dd49f8958f7e3f5b05ab8b8ddb34e581bde5eb49dd15698d2d2b68fe7e8baf88d8f395cfcafcdff38cf34b59386f6f77333483655ee316f12bfeb00610d8cba9e59e637ca2cab6ed24dd584143844e61fcca994ba44a4c029682997ab04285f479a6dc2c854c569073c62cd68af804aa70f4976d5b9f6b09d3738fcccb6d60e11ba97a4001062195d05a43798d5f24e9466f082ac367169f892dfd6cc0adeef82212c867a49cba65e0e636bab91e2176d3865634aa45b13c1e3e7cdb4e7872b2437f40f3de5493792c06611a9ca97d0baed71bfb4e9fdd58191198a8b371aea7f65b6e851ce22f4808377d09b6a5a9f04eddc3ff4ef9fd8bf043bb559e1df5319113cb8beea9e06b0c05c50885873acd19f6e8a109c894403a415f627cd1e8f7ca54c288c230795aaddde3a787c2a20ac6dee4913da0240d6d971f3fce31fc53087afe0c45fa3c8f744c53673bec6231abe2623029053f4be0b1557e00b291ebb212d876e88bcc81e5bd9eb820691dca5fbdcc1e7a6c58945a2cac8db2d86c2a7d98dc5908598bda78ce202ac3cd174d48ad9cac9039e27f30658eef6317cd87c199944343e7fce1b3ea7", "ad635385a289163fbaf04b5850285bfe3759774aee7fd0211d770f63985e1b44");
+ TestSHA3_256("01ec0bfc6cc56e4964808e2f1e516416717dad133061e30cb6b66b1dc213103b86b3b017fa7935457631c79e801941e3e3a0e1a3016d435e69a390eaac64f3166d944c8eb8df29fe95fdf27adc34631e4a1f3ff1d5af430f3d6f5908e40c0f83df1447274dfe30bbe76b758bd9abb40ed18331c7552dcc6959a1303e11134ec904bd0aab62de33c39703b99920851afd9d531eeb28f1c4b2e6c17c55db8296320316fbe19e881b5fcb4d266c58ca7f31d9176e26f70315330b58a516ec60d10404a78393aa03ced7acd225cb2a83caf3ab5888406a69a534f1ed1346e9b5e68831f90b872d57367361191c803eb7e38b3b9cd601282d5efdbf082db07d89bd06b093f986d08d3a7b12aa74513b6eb241b26ebf31da5726d59e315d1b4ee53ec6a9fdb6583bacc136e90e9607cab01e5d3853ab9727ede706b6f10b4e04d0510f45c0abc515bcb5ed0bcce86a92861126f4d502fcb8f988d62ecf9d124853de2bab633f9506c6fde8a36cd4413cf773e50f7b2d283482f18e2f547c2fc275cd60056ed98fb8d0816fd777c1566f0c2ae3b1cd92e344910a75e006106d193e06f7786ae37dd0e529cacf74176fd4cc1f6500549af5902dbbd56a70c194f5b671372edec425f90add40b4eb3d55123f3ab62797ad25bf5eecf4f417f86b00e6f76a4f52e44fd949851aae649dd0d26d641d4c1f343c7a2c851ca7851bbbdfd57ed6024eabc518a909a1e4689ea7bc5f83e19872950368a06e93ab41944c3d8befc5705b814e5f33511a7f7ea8a4771c804b321a3a3f32c18fa127d3c9e6c011337dc100ceb156ed45d0a62f238dacac44a3429f89bb7f98d09043c42451106e30471cc6fab7a4e1ce0a8202772b0218b631f287ec3ef82b1aa6299a0b54d6aad06aa9346d28f117d20f3b7f0d462267bd3c685cca8f4584532dfee0e8b9bacefa3092d28fcce7953a28f82e4ba6b3a1430ecca58b770dab656bed1b224663e196dffc28c96a2c65ef9de1989a125ecf2fed47eb96bef8a636a91bd521c47aeb8bc011bf81cc688fd8b620446353cbf7692201b5552cb07fb02eb3954dfaa6f5c31bf91e20b84419dcbbdaba0c31a124d8f4218b2f88da3eba44dbe40eb290052538dccd0ff7670de5f33a83ff74895b66adcff58c9c21e93b31bb49ccb2e026995ee155b5517b72daa76526a2e42aa6fa94357cd42e2a8a1d3e7d4cefc33d5d07d6303d798d2551a21f862b5f492d0c7cf078a77007a02847b34675dfad4fb457e9f20dc5750fb127a3c31b9d6a3996d50ac3ffc6ef29cca1d8414d0438bf3271dc4f4e00cfe19a507b447dc310f74aeb2a3c0b3fae6d7d13f4935bc72c35df3efa6e879164421505ee32d93b030e32a7970b53430b1643855167278e5058c4a48a7840e2fcdb282e45b5b86c0b2756f19b595f3bcfc926df35e33ac26dd1e88cd394015a5f54deb4c9f4a0bef0eabcb27c4eb88dc2302f09e92f1bcc4b4754df1eeb536154543c7dbf181c9979fe6ed08311e5a3acf365ebb5745212b2630e83b3a5bd5fa4834c727248b165700c7435f8cb6ee455bad16ee0da68fe6acd2062dae9c8bc178b157b29ade98a9bbbd4c723a3dcb7852c7978b488e4f73a2c9163dbdffae175119f812b6f4b70c2b498704bc2b58603f167f277a74e64ec296a6dfdb0de3486c0f36ac1b55f80af9fc817ba4f84b898b2a3c5725e2faf466bb26a8a84f91e123d182033a7ae2029236aa4b673ceb50c1733d7edd60e3f119b7141c882d508e0331689c96fbfb9f7e888fe88561de427c721123036737c1460b0da00d3f958b948f68fcb321ab4e297290f781ff8afb06b755d82a7e6ce1963761d799eed786524bf19801b4877b2d856becdf7e87d71aa359f2d51f09de64bcbf27d0c3aceac70790e314fd06c2f5216f3d10574b7302d6bc2775b185145c1b741524567c456d42c5826f93afa20ae7196ca7224c3b69b1eada9eee752fb6d43f24170fcc02af7e1dea73f0f884f936f900165800acb9d57480a31e409d3f676ed92b6812cf182a088fc49d68082aa19c7be0711f436db1d7be44d97dc9405591a8d3e7f6f731c6f3e6c401749829b7624497f5eeac1fc782e7d6988340541f2617a317e", "2a6283b1c02c6aaf74c4155091ff54a904bb700077f96a9c4bd84e8e51b54d01");
+ TestSHA3_256("9271fd111dcf260c04cf4b748f269ac80f7485c41f7724352a7ed40b2e2125b0bf30f3984ee9d21aab6eb07ec976b557c2426e131ad32bd0485aa57172f0e4f1798760f8352067ac023fbeca7b9c8bf5851c724e90ffff44195b44ae73c9c317c85e8e585bddac6d0f2abf812d02e44b62eadb9d0765683aa56af8e9b91588c7b49dc3e146866a02dc18f9ca680f88006094ef29096c2d5af5700b4aca3dfcab462c48bb8085691671efb5ceb22b3ebd8702f71a1d7c184b1053c3fa30a7e76b85f3650d9140714fd4993bb496becf2ae01d3a98ccfdefb6fefd692173bd11af7adb61ffff214a550ffcd3a5993004ee72cb02ca9c577b42c85444e619e6411e2bca86bb548ebbd12a02c5c945eaa3b246f595d817f3849875429e72ac894160a2a91a6617f18e6b2b9258472152741d62843cebc537d25f0daebdedb410d71ee761662bd1b189ca1c93d648b5d141d8d05e3f2b2d8c2c40997fea7eb7e2cc0000d8b2300936759704ef85f38ad0d08a986de6bfd75b5be3209f6d4d3f67e7adf7f8469d47e81979ec8dae7127b5eadcc09779cf4b0a28efaaf58e83d307f2ced4a8699b142f3f19db5598e914e9577652c63f851203580d40699548fc2ab30a9dcf6452f673ad1ed92f8d84dad5dfff55e18107b3acb6e4e8e3c9c34038f40a5c577fe9771c2c31ef03d36a00e04a20d2d0877db66f091dac4b741d2a997b75182702881f9284fa23b9b3c20e715f80d07b9910a4b3185f9489dc7d3fb510f4da273559753d7d207f3975b48df2e7c857caffe703dfac53a786490c09f57d2fa93f60810186df4c0b6b616a04caab9f70a5002c5e5d8da0ed2805f20fbf89cd8d57ca2b4bd37125ce38bf09fb6170ae21f4e6043a9483ef6e585756d97cfb778e57bc7ddc8dfc54d086d6bcfa1f019c749ff79921ec56e833ff8660f0959cd4b5277e9f3b1d4880193fefa98a6c2512718e7c139acdcd324303db3adb70348d09b058baf0e91d52b24952f832b0a3b81fa9bc9a2e9fb276a64e9e0922778b4992d892f6845b4372a28e47d27b53443586d9015463cacb5b65c617f84e1168b15988737a7eda8187f1f4165fecbdd032ae04916cc4b6e18a87558d2ce6a5946c65a9446f66cda139a76506c60d560f56a013b508d6ccbbaa14e24ad0729dd823bf214efcc59e6932cdc860306687c84a63efb551237223641554940a7a60fa7e6ddad64a21b4a2176b046dc480b6c5b5ff7ed96e3211df609195b4028756c22479ba278105771493870372abe24dcc407daa69878b12b845908cf2e220e7fabeeaab88c8f64f864c2bacba0c14b2a693e45aacc6b7db76bc1a2195cfce7b68f3c99440477ea4c1ea5ee78c109f4f1b553c76eb513dd6e16c383ce7f3187ad66c1d5c982724de8e16299c2fde0a8af22e8de56e50a56ac0fef1c52e76864c0ad1eeedd8907065b37892b3eca0ddcdf5c8e0917dec78fedd194ea4b380a059ccc9452e48a9eba2f8b7a4150b7ba17feac83c61604c3cfcfe6655c2be37ef0ae6fc29072f9b1cfb277b64a8d499dd079ad9aa3d5e9a7ccbec8c100596c6fac51e13a260d78d8cd9066edc558e2219cfcda1310dc1fbbdd36f348756855349f33eb6b82186a8c1a55f361305833edd3e4ac8d9b9cf99897c4e06c19ed10765fd0c8c7433851445c5f87b119ef913b2bcdbf7aa2ad19c672e53a9c6c3c309d549513edd7c1cf8a0a399e6df0939cc1fb146d6ad460e2ce05144c69eafa3822141d473fbe5927c58a50c1e842f8b8fad85540ce9f6d06f7b4dea045248b999d24c5fd4d75631caf73518cc08f73684e2a1cd4266235d90c08a0d0ce8784c776fd1b80978b83f0705ba8498744884d5496b791f2db3ffb5377175856b25a643803aa8b9e7f1055e089c1929cf0cbba7674c204c4590fb076968e918e0390d268eeef78c2aebcbf58a429f28212a2425c6ad8970b6a09cadddd8336d519bca4820556d2c4b8cd9f41216de3c728a0774edf47d3489cd29cf1b2a192bc53325d0bed7d23e51be7684297f9d0ecb14acbf648bc440c5fde997acc464fb45e965e6f0dced6d4568ebcd55e5a64633b05a2cb4d8263b721a252b1710dc84d8a5d4b43fcc875e2e7281f621b0bf8bb3465be364456bcd990b26b3e474486f864fb85f320f68bc14c37d271249b18552bef50dfc385a9f41b831589c5a716357cf5a12520d582d00452a8ab21643dd180071d2041bbc5972099141c6292009540d02f3252f1f59f8dfcf4488803f3b0df41759055559a334e68c98ea491b0984f2f82a35db84ea0779b3801cf06b463a832e", "4e75bf3c580474575c96ec7faa03feb732379f95660b77149974133644f5d2a0");
+ TestSHA3_256("075997f09ab1980a3179d4da78c2e914a1ff48f34e5d3c2ab157281ef1841052d0b45a228c3cd6b5028efd2d190d76205e1fdf4cec83c9868fe504f429af1e7c5423267c48a7b5bc005f30a1980147a3fae5c100b95c7cb23d43af9f21d87311d9cc826598993e077015f59ebc476383bb7a78787d915c97039ab188a2a618f7a8d7f64542ba787e9dd7d48c4c87d2aaea068c1b00c9711b2812901673c11418096d0a850fb36b0acece56d311689dfeceb0835009adc427f6d2d6b05ed26f5a43b6478bc72c1f914a2202dbd393cb69b1a1e78162e55ca4b3030ac0298131a7a0d934c032cc9dfc5afa600c59b064d2d9013f15d1184278a8ccb5ad9d7563e666fe5a8c173cec34467ef9cf6d6671208ff714741fee7c8d1d565edf82570dffde4f3f584024142056d8548ad55df83d1babed06141114c95ac88dbea0ce35d950f16d8a732a1ea7d22dfaa75a3e0410c546523277261116a64bcbb2be83e55e040f6c8c79f911b301a8718cc4b19a81d5f0cb6312d87c5b4b079e23a61d247541cfc2c41a37f52b2c6e43a3db5dc47892d0e1feabcc5c808f2391791e45fb065159f99c1d8dd2f69baaf75267eb89dd460f1b6c0badb96cbbc8291cefa370fa7ad6997a4ca2b1fe968216032f02f29837d40215fa219c09161df074e1de8e37056e28c86d1f992a651e271dfc4b0592ad481c613fd00c3eea4b6deabb9f5aa63a4830ed49ab93624fa7b208966eccb1f293f4b9a46411f37d7928e4478dde2f608d3851a8efa68e9d45402bc5124fde4ddc0f83ef82b31019d0aacb4b5121bbc064c95c5292da97981f58f051df9502054bf728e9d4fb7e04787a0890922b30a3f66a760e3d3763855e82be017fa603630a33115a02f02386982001def905784f6ba307a598c6dbaf2946fe9e978acbaf3e4ba50ab49ae8e9582520fc2eb6790deafc77e04a8ee75da92d16f0d249403112c74bc09102b573e110ccb4d8461d249bfe2e85fc9770d606be6fbfd5ec4c30ac306d46412f736e5b696ccc9fbe4adea730955c55ea5c63678271d34b7bd6f6340e72626d290820eeb96a0d2d25ea81361a122ffe8e954cf4ff84f4dafcc5c9d3e7c2ddbdf95ed2c0862d3f2783e4566f450ec49e8b01d9d7bf11e92a7903f2b045c57ed8a65ccbfc5b1d2a38e020a57b38f2e4deea8a52354a7e7be4f977b8f5afe30f6738e955c8bda295064586b6827b245766b217fe39263572b0850965c7ae845611b8efb64c36244a39b9fed0ab970ee5ddeb8f2608dd9c963524a14050c9101d7f2d5537b24d0b0f7a45703c1e131656ec9edc12cdf71dae1cde2790b888ef2a589f03201f8bbfad71f0c4430477a6713ad2e50aaefa1f840cbb839e277389454517e0b9bd76a8ecc5c2e22b854c25ff708f9256d3700adeaec49eb2c4134638ee9bd649b4982f931ec3b23cc819fbc835ddcb3d65e04585aa005e13b7ef8fcafa36cc1a2c79ba6c26fc1dc0f6668f9432c578088cd33a41a778ac0b298fcac212edab724c9fb33d827409fd36bc4b2b0e4e81006fd050d94d3271e0427c61e9ddca599a3c9480cfdd33603cb1a196557281ce6a375fef17463893db293dba0704d4bfda25e08beadd4208c58ea0d8d9066448910b087fc13792fc44075a3fe42e13c5792f093a552aa8ebe0f63e7a807102d5bc145468a0cb469263035c5647049054c18199f7da6d6defd51105e2125c605e327aca137ca85e3f7f46ca69f92d5252f84418293f4e9afeeb067c79576e88cc3c64f3e61d76e1e9e2f72cdfc35261a9679f0c374d7436ff6cfe2ba71650810522fa554a4aded87ad23f0b206b1bc63f56bbff8bcc8849d99e209bd519a953f32c667aa8cd874ad99846ed94b92f88fe0dbf788c8431dc76ca9553692622077da2cdea666c1b3fee7c335da37737afccd3d400a23d18f5bd3784dbcd0663a38acb5a2beef03fc0a1c52ee0b56bda4493f2221e35bee59f962f16bc6781133204f032c7a6209dd3dabd6100325ec14e3ab0d05aadd03fdfe9f8737da15edab9d2598046f8c6dd8381aaf244821994d5a956073c733bcebf9edbc2a6e2676242dc4e6a2e4ba8a7d57ed509340d61fae2c82bee4dedc73b469e202cc0916250d40a1718090690a1d3b986cf593b019b7b7f79ae14843b2e7ccf0fd85218184f7844fbb35e934476841b056b3a75bf20abb6866e19a0614e6a1af0eee4de510535724363b6598cccf08a99066021653177559c57e5aaff4417670a98fe4bd41a137c384f98c0324c20ef8bc851a9b975e9440191ff08deb78c9fa6fc29c76b371a4a1fa08c30fc9d1b3323d897738495086bfd43ef24c650cfa80c42ecbadc0453c4437d1a11b467e93ca95fbae98d38dcb2da953e657fb7ea6c8493d08cf028c5d3eb0fcbcb205493f4658440719e076e02deb07332d093e4d256175ca56f4c785d5e7e26c6090a20429f70b3757daac54153bc16f5828dc6c1c9f5186e2117754be5f1b46b3631980d9e4a9a5c", "2e07737d271b9a0162eb2f4be1be54887118c462317eb6bd9f9baf1e24111848");
+ TestSHA3_256("119a356f8c0790bbd5e9f3b4c5c4a70e97f462364c88cad04d5435645342b35484e94e12df61908fd95546f74859849b817ee92fbd242435c210b7b9bfbffb3f77f965faa1a9073e8feb5a380f673add8fde32208402fa680c8b3e41d187a15131f1028f9d86feaf3fd4b6e0e094d2ba0839c67267c9535173ec51645343ad74fcfaae389aa17cca3137e2588488531c36ba2b8e2f2238d8415c798a0b9a258f1e3cef605fa18977ad3d6707c3ecc5ea5f86ebdaa4b4b0e5bc023d1bc335138ae0de506cb52f2d9efa0ecc546468310cccc88ec08d28c3602e07257f41bb7e4d8a0956c564f3712761d199a931a39e69c5a69aa7b3257931dd92b91e4ed56fbf64e48bd334945cfa2aaf576df04614eb914899f7df54db4012cc8261b12bedcab69876feedbbf7009dcf8d076af89b797ad71217d75cf07514dc07ae34640055c74c9faf560f491f015ac3e167623cfbc67b8e7163e7c1b92debd06e9d28b049e0298f4c38395a40a0778162af2cfe5abe5b946c4d9a54f2a321660ab521068c4957cd3f5be0324cc04f50f209fdea7caaa0ac705c1fb30abfa550e844f509074afde1ee87adda29aa09b7f93e7d064ad2715ee5571ee6e7c9a01672124cc2a22b4354c3844759c1a6ce3fdf17555cac7df73334073ef3730939410fe6cf37463352ad241958b7fafbc66e0d592df48bf55ab2c33428e494c6995826892572d9ab52747b1085fcbef318cfe9cfacd4cd80c164fba584c1344ae7e321c4f77b44db6b322f2f7831f4d4ede7dc407b065c6754cf4424f9903adb4c6b675ded58700bc36da83fd95e84e76c404f7342921ef23d7d07772f5b8ec2f077601cae13448385b04e074f895574be61a831a87efd68a1f6aa67cf291847fa8f74cbe3b4a78ad780895183bc51c30ad2514255d4e013abc097bc8103c0b1933b0b303341836ae167c1e31dfe5f1b791cb06ef29cae398065343eecf06e4ae2048d1547c4bf69ccec5e86c45867c633c62f7d27dc51234b6debb5b9f80a5810716240c64443d0c098c80220d0520a5f5834369b9eb019325e23e88f237c24440bf27959caf7e7e4f1671fda710630255a2962f7e9b3625dc243a0177aacf6a758a68aa85dc3f56181a4a59a406c7fae5575c9e2c64248f520b5a5f904821661e2e43a5a058f445fd0e55b07476c4122d18033053b45112201e0bfdcc9e7cb9931155018ca431a0564930aca8defbca954b2680753a4060bec2cb668d2c15e77cba29589b5c7c07bc7177a8b1adb3a6968732f9213476fd96901514626fa17243af1d156cd037eea81d773f1f71a018d942b524b851794b300c7591ecd783ec8066ccb261bdf9b7a183dbda42b92593b614297dcb0fabcc23ae69797d0251b8ab57a4da2a544615216b01f4dbe2d8c9b5520c7ed9cd9312e9ec6d05a36e7f693d1821d727518169b03976394b9d1e1d7fa2daa25529d391eb5d0cf0f07a8160be2ee043d9345037c655c4f2023689f14d8d2072dd92c1dba056a5b5d4c4fc4196e25caab05b1701ec666ac9a04d90f7d7575a7ac3970252c18fd3bec0cc448e5ff8f3765d546a4a8ad1d41a9640c79375b80534b7b50989976f238654fefea981c9413130beae943a3e9d8f64ce9256d1259d1b2a6b3c02ca5af1a701db8f25a4e9c255dad8785172f323728c3585a45206ae988c283e30a2f9ea9b47f07a7521b0f36e9c504c14bd96027e8d24161e70f196576d8a74a5e9c26acda7cc452a90e550e625a49e50829db70de808c827c67d00c23ee073d4e72aeed891dd73b86acd6756e753e3975a80cdab1d521052caef6a5380f8b03023ba0326a6928aa127ffb33b51dcb05bbdd592d0ad9e8321e6ef2f95c401be6a37e634425689fe7750e2a0fe05ad89001502b309095ca517b2e2ed0388b9f2c59c45feb61222539d6e1ccd397344d23708aebacec10ada96a7711f173f7ff1e4b94fceec6a0a0ea5d814a4581b412063012ff6ac5527b8314d00326b68c2304a276a217fde9fa4034750a2e47e10f816870d12fc4641a27a1c16c35a953f32685f2b92cae0519848045765591c42ddc402dc7c6914d74dd38d2b5e7f35358cb1d91a9f681fde7fd6c7af5840663525ee1d04bf6d3156fed018c44043d95383d92dada3d1cd84af51d9bee814ec8675073e1c48632c5f59e257682542e1f7dc20b56b5c92a9e2cb2be30cb1512fb55fa1de99a3f5864ed3acc19d79e6ffb0da3b08ba0615157747d75c1f308fa0202a4086f34e9eafa3e071dfbacaca731d228aa0304cf390c0a9e6ad7ce22ade758965cfbfc4c9390d24e41a667447fc7b29821464ad98bc5d65dc7f9c42bd4b23e174015592ff92c905660a2722f9fc7973d3cdad848ef88bf02b1b03dea16699b71dc46b35bc4d96069a0753335ae38685d244918e30c5fb0d45283a1281c1659ea591573999d9c2acd2ca9141d55230d41011b70748b518e1cd2fa58ad8dc05fcbdf0bffaf2c7fd6cb2ac67bb13b8f6d31fad64ac113664223599dca411270955c95aec06518894dabc352d2b70984727437040d944da7b42e0ef560ac532de3e4a4891e8509c275b51ed780f8660b0354e12c21b3e11bcc88198980b5f7ff31ad342182d5a933373164dced3cfb2a081720d7eee676cb7378a3e19326a7ee67fd6c00521f9de37c66bcea814b6feb6a061b8cdcf7b4bd8f45d48602c5", "c26d0b064e409df64819cd7c1a3b8076f19815b9823adac4e3ce0b4d3a29de18");
+ TestSHA3_256("72c57c359e10684d0517e46653a02d18d29eff803eb009e4d5eb9e95add9ad1a4ac1f38a70296f3a369a16985ca3c957de2084cdc9bdd8994eb59b8815e0debad4ec1f001feac089820db8becdaf896aaf95721e8674e5d476b43bd2b873a7d135cd685f545b438210f9319e4dcd55986c85303c1ddf18dc746fe63a409df0a998ed376eb683e16c09e6e9018504152b3e7628ef350659fb716e058a5263a18823d2f2f6ee6a8091945a48ae1c5cb1694cf2c1fe76ef9177953afe8899cfa2b7fe0603bfa3180937dadfb66fbbdd119bbf8063338aa4a699075a3bfdbae8db7e5211d0917e9665a702fc9b0a0a901d08bea97654162d82a9f05622b060b634244779c33427eb7a29353a5f48b07cbefa72f3622ac5900bef77b71d6b314296f304c8426f451f32049b1f6af156a9dab702e8907d3cd72bb2c50493f4d593e731b285b70c803b74825b3524cda3205a8897106615260ac93c01c5ec14f5b11127783989d1824527e99e04f6a340e827b559f24db9292fcdd354838f9339a5fa1d7f6b2087f04835828b13463dd40927866f16ae33ed501ec0e6c4e63948768c5aeea3e4f6754985954bea7d61088c44430204ef491b74a64bde1358cecb2cad28ee6a3de5b752ff6a051104d88478653339457ac45ba44cbb65f54d1969d047cda746931d5e6a8b48e211416aefd5729f3d60b56b54e7f85aa2f42de3cb69419240c24e67139a11790a709edef2ac52cf35dd0a08af45926ebe9761f498ff83bfe263d6897ee97943a4b982fe3404ef0b4a45e06113c60340e0664f14799bf59cb4b3934b465fabefd87155905ee5309ba41e9e402973311831ea600b16437f71df39ee77130490c4d0227e5d1757fdc66af3ae6b9953053ed9aafca0160209858a7d4dd38fe10e0cb153672d08633ed6c54977aa0a6e67f9ff2f8c9d22dd7b21de08192960fd0e0da68d77c8d810db11dcaa61c725cd4092cbff76c8e1debd8d0361bb3f2e607911d45716f53067bdc0d89dd4889177765166a424e9fc0cb711201099dda213355e6639ac7eb86eca2ae0ab38b7f674f37ef8a6fcca1a6f52f55d9e1dcd631d2c3c82bba129172feb991d5af51afecd9d61a88b6832e4107480e392aed61a8644f551665ebff6b20953b635737a4f895e429fddcfe801f606fbda74b3bf6f5767d0fac14907fcfd0aa1d4c11b9e91b01d68052399b51a29f1ae6acd965109977c14a555cbcbd21ad8cb9f8853506d4bc21c01e62d61d7b21be1b923be54914e6b0a7ca84dd11f1159193e1184568a6134a6bbadf5b4df986edcf2019390ae841cfaa44435e28ce877d3dae4177992fa5d4e5c005876dbe3d1e63bec7dcc0942762b48b1ecc6c1a918409a8a72812a1e245c0c67be6e729c2b49bc6ee4d24a8f63e78e75db45655c26a9a78aff36fcd67117f26b8f654dca664b9f0e30681874cb749e1a692720078856286c2560b0292cc837933423147569350955c9571bf8941ba128fd339cb4268f46b94bc6ee203eb7026813706ea51c4f24c91866fc23a724bf2501327e6ae89c29f8db315dc28d2c7c719514036367e018f4835f63fdecd71f9bdced7132b6c4f8b13c69a517026fcd3622d67cb632320d5e7308f78f4b7cea11f6291b137851dc6cd6366f2785c71c3f237f81a7658b2a8d512b61e0ad5a4710b7b124151689fcb2116063fbff7e9115fed7b93de834970b838e49f8f8ba5f1f874c354078b5810a55ae289a56da563f1da6cd80a3757d6073fa55e016e45ac6cec1f69d871c92fd0ae9670c74249045e6b464787f9504128736309fed205f8df4d90e332908581298d9c75a3fa36ab0c3c9272e62de53ab290c803d67b696fd615c260a47bffad16746f18ba1a10a061bacbea9369693b3c042eec36bed289d7d12e52bca8aa1c2dff88ca7816498d25626d0f1e106ebb0b4a12138e00f3df5b1c2f49d98b1756e69b641b7c6353d99dbff050f4d76842c6cf1c2a4b062fc8e6336fa689b7c9d5c6b4ab8c15a5c20e514ff070a602d85ae52fa7810c22f8eeffd34a095b93342144f7a98d024216b3d68ed7bea047517bfcd83ec83febd1ba0e5858e2bdc1d8b1f7b0f89e90ccc432a3f930cb8209462e64556c5054c56ca2a85f16b32eb83a10459d13516faa4d23302b7607b9bd38dab2239ac9e9440c314433fdfb3ceadab4b4f87415ed6f240e017221f3b5f7ac196cdf54957bec42fe6893994b46de3d27dc7fb58ca88feb5b9e79cf20053d12530ac524337b22a3629bea52f40b06d3e2128f32060f9105847daed81d35f20e2002817434659baff64494c5b5c7f9216bfda38412a0f70511159dc73bb6bae1f8eaa0ef08d99bcb31f94f6be12c29c83df45926430b366c99fca3270c15fc4056398fdf3135b7779e3066a006961d1ac0ad1c83179ce39e87a96b722ec23aabc065badf3e188347a360772ca6a447abac7e6a44f0d4632d52926332e44a0a86bff5ce699fd063bdda3ffd4c41b53ded49fecec67f40599b934e16e3fd1bc063ad7026f8d71bfd4cbaf56599586774723194b692036f1b6bb242e2ffb9c600b5215b412764599476ce475c9e5b396fbcebd6be323dcf4d0048077400aac7500db41dc95fc7f7edbe7c9c2ec5ea89943fe13b42217eef530bbd023671509e12dfce4e1c1c82955d965e6a68aa66f6967dba48feda572db1f099d9a6dc4bc8edade852b5e824a06890dc48a6a6510ecaf8cf7620d757290e3166d431abecc624fa9ac2234d2eb783308ead45544910c633a94964b2ef5fbc409cb8835ac4147d384e12e0a5e13951f7de0ee13eafcb0ca0c04946d7804040c0a3cd088352424b097adb7aad1ca4495952f3e6c0158c02d2bcec33bfda69301434a84d9027ce02c0b9725dad118", "d894b86261436362e64241e61f6b3e6589daf64dc641f60570c4c0bf3b1f2ca3");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 93bfa88024..712567ac0d 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -47,7 +47,6 @@ struct CConnmanTest : public CConnman {
extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);
extern void EraseOrphansFor(NodeId peer);
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
-extern void Misbehaving(NodeId nodeid, int howmuch, const std::string& message="");
struct COrphanTx {
CTransactionRef tx;
@@ -79,13 +78,14 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
// work.
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
+ const CChainParams& chainparams = Params();
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(*connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ auto peerLogic = MakeUnique<PeerManager>(chainparams, *connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool);
// Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::OUTBOUND);
- dummyNode1.SetSendVersion(PROTOCOL_VERSION);
+ CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::OUTBOUND_FULL_RELAY);
+ dummyNode1.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
@@ -133,12 +133,12 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
}
-static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic, CConnmanTest* connman)
+static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerManager &peerLogic, CConnmanTest* connman)
{
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
- vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", ConnectionType::OUTBOUND));
+ vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", ConnectionType::OUTBOUND_FULL_RELAY));
CNode &node = *vNodes.back();
- node.SetSendVersion(PROTOCOL_VERSION);
+ node.SetCommonVersion(PROTOCOL_VERSION);
peerLogic.InitializeNode(&node);
node.nVersion = 1;
@@ -149,10 +149,10 @@ static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidat
BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{
+ const CChainParams& chainparams = Params();
auto connman = MakeUnique<CConnmanTest>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(*connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ auto peerLogic = MakeUnique<PeerManager>(chainparams, *connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool);
- const Consensus::Params& consensusParams = Params().GetConsensus();
constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
CConnman::Options options;
options.nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
@@ -167,18 +167,18 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
AddRandomOutboundPeer(vNodes, *peerLogic, connman.get());
}
- peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+ peerLogic->CheckForStaleTipAndEvictPeers();
// No nodes should be marked for disconnection while we have no extra peers
for (const CNode *node : vNodes) {
BOOST_CHECK(node->fDisconnect == false);
}
- SetMockTime(GetTime() + 3*consensusParams.nPowTargetSpacing + 1);
+ SetMockTime(GetTime() + 3 * chainparams.GetConsensus().nPowTargetSpacing + 1);
// Now tip should definitely be stale, and we should look for an extra
// outbound peer
- peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+ peerLogic->CheckForStaleTipAndEvictPeers();
BOOST_CHECK(connman->GetTryNewOutboundPeer());
// Still no peers should be marked for disconnection
@@ -191,8 +191,8 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
// required time connected check should be satisfied).
AddRandomOutboundPeer(vNodes, *peerLogic, connman.get());
- peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
- for (int i=0; i<max_outbound_full_relay; ++i) {
+ peerLogic->CheckForStaleTipAndEvictPeers();
+ for (int i = 0; i < max_outbound_full_relay; ++i) {
BOOST_CHECK(vNodes[i]->fDisconnect == false);
}
// Last added node should get marked for eviction
@@ -204,8 +204,8 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
// peer, and check that the next newest node gets evicted.
UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime());
- peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
- for (int i=0; i<max_outbound_full_relay-1; ++i) {
+ peerLogic->CheckForStaleTipAndEvictPeers();
+ for (int i = 0; i < max_outbound_full_relay - 1; ++i) {
BOOST_CHECK(vNodes[i]->fDisconnect == false);
}
BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true);
@@ -221,18 +221,19 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
BOOST_AUTO_TEST_CASE(peer_discouragement)
{
+ const CChainParams& chainparams = Params();
auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(*connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ auto peerLogic = MakeUnique<PeerManager>(chainparams, *connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
banman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::INBOUND);
- dummyNode1.SetSendVersion(PROTOCOL_VERSION);
+ dummyNode1.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
dummyNode1.fSuccessfullyConnected = true;
- Misbehaving(dummyNode1.GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged
+ peerLogic->Misbehaving(dummyNode1.GetId(), DISCOURAGEMENT_THRESHOLD, /* message */ ""); // Should be discouraged
{
LOCK(dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
@@ -242,18 +243,18 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", ConnectionType::INBOUND);
- dummyNode2.SetSendVersion(PROTOCOL_VERSION);
+ dummyNode2.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode2);
dummyNode2.nVersion = 1;
dummyNode2.fSuccessfullyConnected = true;
- Misbehaving(dummyNode2.GetId(), DISCOURAGEMENT_THRESHOLD - 1);
+ peerLogic->Misbehaving(dummyNode2.GetId(), DISCOURAGEMENT_THRESHOLD - 1, /* message */ "");
{
LOCK(dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
}
BOOST_CHECK(!banman->IsDiscouraged(addr2)); // 2 not discouraged yet...
BOOST_CHECK(banman->IsDiscouraged(addr1)); // ... but 1 still should be
- Misbehaving(dummyNode2.GetId(), 1); // 2 reaches discouragement threshold
+ peerLogic->Misbehaving(dummyNode2.GetId(), 1, /* message */ ""); // 2 reaches discouragement threshold
{
LOCK(dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
@@ -268,9 +269,10 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
+ const CChainParams& chainparams = Params();
auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(*connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ auto peerLogic = MakeUnique<PeerManager>(chainparams, *connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
banman->ClearBanned();
int64_t nStartTime = GetTime();
@@ -278,12 +280,12 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
CAddress addr(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", ConnectionType::INBOUND);
- dummyNode.SetSendVersion(PROTOCOL_VERSION);
+ dummyNode.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode);
dummyNode.nVersion = 1;
dummyNode.fSuccessfullyConnected = true;
- Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
+ peerLogic->Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD, /* message */ "");
{
LOCK(dummyNode.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp
index 3edcf96495..664e65accc 100644
--- a/src/test/fuzz/crypto.cpp
+++ b/src/test/fuzz/crypto.cpp
@@ -7,6 +7,7 @@
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
+#include <crypto/sha3.h>
#include <crypto/sha512.h>
#include <hash.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -32,6 +33,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
CSHA1 sha1;
CSHA256 sha256;
CSHA512 sha512;
+ SHA3_256 sha3;
CSipHasher sip_hasher{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
while (fuzzed_data_provider.ConsumeBool()) {
@@ -51,6 +53,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(void)ripemd160.Write(data.data(), data.size());
(void)sha1.Write(data.data(), data.size());
(void)sha256.Write(data.data(), data.size());
+ (void)sha3.Write(data);
(void)sha512.Write(data.data(), data.size());
(void)sip_hasher.Write(data.data(), data.size());
@@ -65,11 +68,12 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(void)ripemd160.Reset();
(void)sha1.Reset();
(void)sha256.Reset();
+ (void)sha3.Reset();
(void)sha512.Reset();
break;
}
case 2: {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 8)) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 9)) {
case 0: {
data.resize(CHash160::OUTPUT_SIZE);
hash160.Finalize(data);
@@ -115,9 +119,21 @@ void test_one_input(const std::vector<uint8_t>& buffer)
data[0] = sip_hasher.Finalize() % 256;
break;
}
+ case 9: {
+ data.resize(SHA3_256::OUTPUT_SIZE);
+ sha3.Finalize(data);
+ break;
+ }
}
break;
}
}
}
+ if (fuzzed_data_provider.ConsumeBool()) {
+ uint64_t state[25];
+ for (size_t i = 0; i < 25; ++i) {
+ state[i] = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
+ }
+ KeccakF(state);
+ }
}
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index 1ff9d6b286..a85c353243 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -46,9 +46,9 @@ void test_one_input(const std::vector<uint8_t>& buffer)
fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
*address_bind,
fuzzed_data_provider.ConsumeRandomLengthString(32),
- fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH})};
+ fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH})};
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 12)) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) {
case 0: {
node.CloseSocketDisconnect();
break;
@@ -58,7 +58,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
break;
}
case 2: {
- node.SetSendVersion(fuzzed_data_provider.ConsumeIntegral<int>());
+ node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral<int>());
break;
}
case 3: {
@@ -71,21 +71,17 @@ void test_one_input(const std::vector<uint8_t>& buffer)
break;
}
case 4: {
- node.SetRecvVersion(fuzzed_data_provider.ConsumeIntegral<int>());
- break;
- }
- case 5: {
const CNode* add_ref_node = node.AddRef();
assert(add_ref_node == &node);
break;
}
- case 6: {
+ case 5: {
if (node.GetRefCount() > 0) {
node.Release();
}
break;
}
- case 7: {
+ case 6: {
if (node.m_addr_known == nullptr) {
break;
}
@@ -96,7 +92,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.AddAddressKnown(*addr_opt);
break;
}
- case 8: {
+ case 7: {
if (node.m_addr_known == nullptr) {
break;
}
@@ -108,7 +104,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.PushAddress(*addr_opt, fast_random_context);
break;
}
- case 9: {
+ case 8: {
const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
if (!inv_opt) {
break;
@@ -116,11 +112,11 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.AddKnownTx(inv_opt->hash);
break;
}
- case 10: {
+ case 9: {
node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider));
break;
}
- case 11: {
+ case 10: {
const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (!service_opt) {
break;
@@ -128,7 +124,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
node.SetAddrLocal(*service_opt);
break;
}
- case 12: {
+ case 11: {
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
bool complete;
node.ReceiveMsgBytes((const char*)b.data(), b.size(), complete);
@@ -143,11 +139,10 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(void)node.GetLocalNonce();
(void)node.GetLocalServices();
(void)node.GetMyStartingHeight();
- (void)node.GetRecvVersion();
const int ref_count = node.GetRefCount();
assert(ref_count >= 0);
- (void)node.GetSendVersion();
- (void)node.IsAddrRelayPeer();
+ (void)node.GetCommonVersion();
+ (void)node.RelayAddrsWithConn();
const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ?
fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({NetPermissionFlags::PF_NONE, NetPermissionFlags::PF_BLOOMFILTER, NetPermissionFlags::PF_RELAY, NetPermissionFlags::PF_FORCERELAY, NetPermissionFlags::PF_NOBAN, NetPermissionFlags::PF_MEMPOOL, NetPermissionFlags::PF_ISIMPLICIT, NetPermissionFlags::PF_ALL}) :
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index ec09acc6c6..3ef03137ec 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -68,16 +68,15 @@ void test_one_input(const std::vector<uint8_t>& buffer)
return;
}
CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION};
- CNode& p2p_node = *MakeUnique<CNode>(0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND).release();
+ CNode& p2p_node = *MakeUnique<CNode>(0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY).release();
p2p_node.fSuccessfullyConnected = true;
p2p_node.nVersion = PROTOCOL_VERSION;
- p2p_node.SetSendVersion(PROTOCOL_VERSION);
+ p2p_node.SetCommonVersion(PROTOCOL_VERSION);
connman.AddTestNode(p2p_node);
- g_setup->m_node.peer_logic->InitializeNode(&p2p_node);
+ g_setup->m_node.peerman->InitializeNode(&p2p_node);
try {
- g_setup->m_node.peer_logic->ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream,
- GetTime<std::chrono::microseconds>(), Params(),
- std::atomic<bool>{false});
+ g_setup->m_node.peerman->ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream,
+ GetTime<std::chrono::microseconds>(), std::atomic<bool>{false});
} catch (const std::ios_base::failure&) {
}
SyncWithValidationInterfaceQueue();
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index ef427442e9..f722eeac3a 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -44,15 +44,15 @@ void test_one_input(const std::vector<uint8_t>& buffer)
const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3);
for (int i = 0; i < num_peers_to_add; ++i) {
const ServiceFlags service_flags = ServiceFlags(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH});
+ const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH});
peers.push_back(MakeUnique<CNode>(i, service_flags, 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, conn_type).release());
CNode& p2p_node = *peers.back();
p2p_node.fSuccessfullyConnected = true;
p2p_node.fPauseSend = false;
p2p_node.nVersion = PROTOCOL_VERSION;
- p2p_node.SetSendVersion(PROTOCOL_VERSION);
- g_setup->m_node.peer_logic->InitializeNode(&p2p_node);
+ p2p_node.SetCommonVersion(PROTOCOL_VERSION);
+ g_setup->m_node.peerman->InitializeNode(&p2p_node);
connman.AddTestNode(p2p_node);
}
diff --git a/src/test/fuzz/signet.cpp b/src/test/fuzz/signet.cpp
new file mode 100644
index 0000000000..4736ae27f5
--- /dev/null
+++ b/src/test/fuzz/signet.cpp
@@ -0,0 +1,34 @@
+// 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 <chainparams.h>
+#include <consensus/validation.h>
+#include <primitives/block.h>
+#include <signet.h>
+#include <streams.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <optional>
+#include <vector>
+
+void initialize()
+{
+ InitializeFuzzingContext(CBaseChainParams::SIGNET);
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const std::optional<CBlock> block = ConsumeDeserializable<CBlock>(fuzzed_data_provider);
+ if (!block) {
+ return;
+ }
+ (void)CheckSignetBlockSolution(*block, Params().GetConsensus());
+ if (GetWitnessCommitmentIndex(*block) != NO_WITNESS_COMMITMENT) {
+ (void)SignetTxs(*block, ConsumeScript(fuzzed_data_provider));
+ }
+}
diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp
index d465ee6759..611e9f2623 100644
--- a/src/test/key_io_tests.cpp
+++ b/src/test/key_io_tests.cpp
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(key_io_invalid)
std::string exp_base58string = test[0].get_str();
// must be invalid as public and as private key
- for (const auto& chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::REGTEST }) {
+ for (const auto& chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST }) {
SelectParams(chain);
destination = DecodeDestination(exp_base58string);
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest);
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 917ae571f5..85ebc89673 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -183,10 +183,20 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
std::string pszDest;
- std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, ConnectionType::OUTBOUND);
+ std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY);
+ BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
+ BOOST_CHECK(pnode1->IsManualConn() == false);
+ BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
+ BOOST_CHECK(pnode1->IsFeelerConn() == false);
+ BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
BOOST_CHECK(pnode1->IsInboundConn() == false);
std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, ConnectionType::INBOUND);
+ BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
+ BOOST_CHECK(pnode2->IsManualConn() == false);
+ BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
+ BOOST_CHECK(pnode2->IsFeelerConn() == false);
+ BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
BOOST_CHECK(pnode2->IsInboundConn() == true);
}
@@ -283,7 +293,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
in_addr ipv4AddrPeer;
ipv4AddrPeer.s_addr = 0xa0b0c001;
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
- std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND);
+ std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY);
pnode->fSuccessfullyConnected.store(true);
// the peer claims to be reaching us via IPv6
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index 0f9872f434..ca49b89ad8 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -135,4 +135,51 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
}
}
+void sanity_check_chainparams(std::string chainName)
+{
+ const auto chainParams = CreateChainParams(chainName);
+ const auto consensus = chainParams->GetConsensus();
+
+ // hash genesis is correct
+ BOOST_CHECK_EQUAL(consensus.hashGenesisBlock, chainParams->GenesisBlock().GetHash());
+
+ // target timespan is an even multiple of spacing
+ BOOST_CHECK_EQUAL(consensus.nPowTargetTimespan % consensus.nPowTargetSpacing, 0);
+
+ // genesis nBits is positive, doesn't overflow and is lower than powLimit
+ arith_uint256 pow_compact;
+ bool neg, over;
+ pow_compact.SetCompact(chainParams->GenesisBlock().nBits, &neg, &over);
+ BOOST_CHECK(!neg && pow_compact != 0);
+ BOOST_CHECK(!over);
+ BOOST_CHECK(UintToArith256(consensus.powLimit) >= pow_compact);
+
+ // check max target * 4*nPowTargetTimespan doesn't overflow -- see pow.cpp:CalculateNextWorkRequired()
+ if (!consensus.fPowNoRetargeting) {
+ arith_uint256 targ_max("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+ targ_max /= consensus.nPowTargetTimespan*4;
+ BOOST_CHECK(UintToArith256(consensus.powLimit) < targ_max);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(ChainParams_MAIN_sanity)
+{
+ sanity_check_chainparams(CBaseChainParams::MAIN);
+}
+
+BOOST_AUTO_TEST_CASE(ChainParams_REGTEST_sanity)
+{
+ sanity_check_chainparams(CBaseChainParams::REGTEST);
+}
+
+BOOST_AUTO_TEST_CASE(ChainParams_TESTNET_sanity)
+{
+ sanity_check_chainparams(CBaseChainParams::TESTNET);
+}
+
+BOOST_AUTO_TEST_CASE(ChainParams_SIGNET_sanity)
+{
+ sanity_check_chainparams(CBaseChainParams::SIGNET);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 8a88e75892..08aff07448 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -141,7 +141,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
- m_node.mempool = &::mempool;
+ m_node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator);
m_node.mempool->setSanityCheck(1.0);
m_node.chainman = &::g_chainman;
@@ -169,10 +169,10 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
m_node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
- m_node.peer_logic = MakeUnique<PeerLogicValidation>(*m_node.connman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
+ m_node.peerman = MakeUnique<PeerManager>(chainparams, *m_node.connman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
{
CConnman::Options options;
- options.m_msgproc = m_node.peer_logic.get();
+ options.m_msgproc = m_node.peerman.get();
m_node.connman->Init(options);
}
}
@@ -187,8 +187,8 @@ TestingSetup::~TestingSetup()
m_node.connman.reset();
m_node.banman.reset();
m_node.args = nullptr;
- UnloadBlockIndex(m_node.mempool);
- m_node.mempool = nullptr;
+ UnloadBlockIndex(m_node.mempool.get());
+ m_node.mempool.reset();
m_node.scheduler.reset();
m_node.chainman->Reset();
m_node.chainman = nullptr;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index bf7c6c3e3e..241c56934e 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -848,8 +848,8 @@ struct ArgsMergeTestingSetup : public BasicTestingSetup {
ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
for (bool soft_set : {false, true}) {
for (bool force_set : {false, true}) {
- for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
- for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
+ for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
+ for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
for (bool net_specific : {false, true}) {
fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
}
@@ -1003,7 +1003,7 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
// Results file is formatted like:
//
// <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
- BOOST_CHECK_EQUAL(out_sha_hex, "8fd4877bb8bf337badca950ede6c917441901962f160e52514e06a60dea46cde");
+ BOOST_CHECK_EQUAL(out_sha_hex, "d1e436c1cd510d0ec44d5205d4b4e3bee6387d316e0075c58206cb16603f3d82");
}
// Similar test as above, but for ArgsManager::GetChainName function.
@@ -1106,7 +1106,7 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
// Results file is formatted like:
//
// <input> || <output>
- BOOST_CHECK_EQUAL(out_sha_hex, "f0b3a3c29869edc765d579c928f7f1690a71fbb673b49ccf39cbc4de18156a0d");
+ BOOST_CHECK_EQUAL(out_sha_hex, "f263493e300023b6509963887444c41386f44b63bc30047eb8402e8c1144854c");
}
BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index de1a3ec68f..6a525c97db 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -55,45 +55,45 @@ size_t CTxMemPoolEntry::GetTxSize() const
}
// Update the given tx for any in-mempool descendants.
-// Assumes that setMemPoolChildren is correct for the given tx and all
+// Assumes that CTxMemPool::m_children is correct for the given tx and all
// descendants.
void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set<uint256> &setExclude)
{
- setEntries stageEntries, setAllDescendants;
- stageEntries = GetMemPoolChildren(updateIt);
+ CTxMemPoolEntry::Children stageEntries, descendants;
+ stageEntries = updateIt->GetMemPoolChildrenConst();
while (!stageEntries.empty()) {
- const txiter cit = *stageEntries.begin();
- setAllDescendants.insert(cit);
- stageEntries.erase(cit);
- const setEntries &setChildren = GetMemPoolChildren(cit);
- for (txiter childEntry : setChildren) {
- cacheMap::iterator cacheIt = cachedDescendants.find(childEntry);
+ const CTxMemPoolEntry& descendant = *stageEntries.begin();
+ descendants.insert(descendant);
+ stageEntries.erase(descendant);
+ const CTxMemPoolEntry::Children& children = descendant.GetMemPoolChildrenConst();
+ for (const CTxMemPoolEntry& childEntry : children) {
+ cacheMap::iterator cacheIt = cachedDescendants.find(mapTx.iterator_to(childEntry));
if (cacheIt != cachedDescendants.end()) {
// We've already calculated this one, just add the entries for this set
// but don't traverse again.
for (txiter cacheEntry : cacheIt->second) {
- setAllDescendants.insert(cacheEntry);
+ descendants.insert(*cacheEntry);
}
- } else if (!setAllDescendants.count(childEntry)) {
+ } else if (!descendants.count(childEntry)) {
// Schedule for later processing
stageEntries.insert(childEntry);
}
}
}
- // setAllDescendants now contains all in-mempool descendants of updateIt.
+ // descendants now contains all in-mempool descendants of updateIt.
// Update and add to cached descendant map
int64_t modifySize = 0;
CAmount modifyFee = 0;
int64_t modifyCount = 0;
- for (txiter cit : setAllDescendants) {
- if (!setExclude.count(cit->GetTx().GetHash())) {
- modifySize += cit->GetTxSize();
- modifyFee += cit->GetModifiedFee();
+ for (const CTxMemPoolEntry& descendant : descendants) {
+ if (!setExclude.count(descendant.GetTx().GetHash())) {
+ modifySize += descendant.GetTxSize();
+ modifyFee += descendant.GetModifiedFee();
modifyCount++;
- cachedDescendants[updateIt].insert(cit);
+ cachedDescendants[updateIt].insert(mapTx.iterator_to(descendant));
// Update ancestor state for each descendant
- mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost()));
+ mapTx.modify(mapTx.iterator_to(descendant), update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost()));
}
}
mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount));
@@ -119,7 +119,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
// Iterate in reverse, so that whenever we are looking at a transaction
// we are sure that all in-mempool descendants have already been processed.
// This maximizes the benefit of the descendant cache and guarantees that
- // setMemPoolChildren will be updated, an assumption made in
+ // CTxMemPool::m_children will be updated, an assumption made in
// UpdateForDescendants.
for (const uint256 &hash : reverse_iterate(vHashesToUpdate)) {
// calculate children from mapNextTx
@@ -128,8 +128,8 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
continue;
}
auto iter = mapNextTx.lower_bound(COutPoint(hash, 0));
- // First calculate the children, and update setMemPoolChildren to
- // include them, and update their setMemPoolParents to include this tx.
+ // First calculate the children, and update CTxMemPool::m_children to
+ // include them, and update their CTxMemPoolEntry::m_parents to include this tx.
// we cache the in-mempool children to avoid duplicate updates
{
const auto epoch = GetFreshEpoch();
@@ -151,7 +151,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const
{
- setEntries parentHashes;
+ CTxMemPoolEntry::Parents staged_ancestors;
const CTransaction &tx = entry.GetTx();
if (fSearchForParents) {
@@ -161,8 +161,8 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr
for (unsigned int i = 0; i < tx.vin.size(); i++) {
Optional<txiter> piter = GetIter(tx.vin[i].prevout.hash);
if (piter) {
- parentHashes.insert(*piter);
- if (parentHashes.size() + 1 > limitAncestorCount) {
+ staged_ancestors.insert(**piter);
+ if (staged_ancestors.size() + 1 > limitAncestorCount) {
errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount);
return false;
}
@@ -172,16 +172,17 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr
// If we're not searching for parents, we require this to be an
// entry in the mempool already.
txiter it = mapTx.iterator_to(entry);
- parentHashes = GetMemPoolParents(it);
+ staged_ancestors = it->GetMemPoolParentsConst();
}
size_t totalSizeWithAncestors = entry.GetTxSize();
- while (!parentHashes.empty()) {
- txiter stageit = *parentHashes.begin();
+ while (!staged_ancestors.empty()) {
+ const CTxMemPoolEntry& stage = staged_ancestors.begin()->get();
+ txiter stageit = mapTx.iterator_to(stage);
setAncestors.insert(stageit);
- parentHashes.erase(stageit);
+ staged_ancestors.erase(stage);
totalSizeWithAncestors += stageit->GetTxSize();
if (stageit->GetSizeWithDescendants() + entry.GetTxSize() > limitDescendantSize) {
@@ -195,13 +196,15 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr
return false;
}
- const setEntries & setMemPoolParents = GetMemPoolParents(stageit);
- for (txiter phash : setMemPoolParents) {
+ const CTxMemPoolEntry::Parents& parents = stageit->GetMemPoolParentsConst();
+ for (const CTxMemPoolEntry& parent : parents) {
+ txiter parent_it = mapTx.iterator_to(parent);
+
// If this is a new ancestor, add it.
- if (setAncestors.count(phash) == 0) {
- parentHashes.insert(phash);
+ if (setAncestors.count(parent_it) == 0) {
+ staged_ancestors.insert(parent);
}
- if (parentHashes.size() + setAncestors.size() + 1 > limitAncestorCount) {
+ if (staged_ancestors.size() + setAncestors.size() + 1 > limitAncestorCount) {
errString = strprintf("too many unconfirmed ancestors [limit: %u]", limitAncestorCount);
return false;
}
@@ -213,10 +216,10 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr
void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors)
{
- setEntries parentIters = GetMemPoolParents(it);
+ CTxMemPoolEntry::Parents parents = it->GetMemPoolParents();
// add or remove this tx as a child of each parent
- for (txiter piter : parentIters) {
- UpdateChild(piter, it, add);
+ for (const CTxMemPoolEntry& parent : parents) {
+ UpdateChild(mapTx.iterator_to(parent), it, add);
}
const int64_t updateCount = (add ? 1 : -1);
const int64_t updateSize = updateCount * it->GetTxSize();
@@ -242,9 +245,9 @@ void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncesto
void CTxMemPool::UpdateChildrenForRemoval(txiter it)
{
- const setEntries &setMemPoolChildren = GetMemPoolChildren(it);
- for (txiter updateIt : setMemPoolChildren) {
- UpdateParent(updateIt, it, false);
+ const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst();
+ for (const CTxMemPoolEntry& updateIt : children) {
+ UpdateParent(mapTx.iterator_to(updateIt), it, false);
}
}
@@ -257,9 +260,9 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
// updateDescendants should be true whenever we're not recursively
// removing a tx and all its descendants, eg when a transaction is
// confirmed in a block.
- // Here we only update statistics and not data in mapLinks (which
- // we need to preserve until we're finished with all operations that
- // need to traverse the mempool).
+ // Here we only update statistics and not data in CTxMemPool::Parents
+ // and CTxMemPoolEntry::Children (which we need to preserve until we're
+ // finished with all operations that need to traverse the mempool).
for (txiter removeIt : entriesToRemove) {
setEntries setDescendants;
CalculateDescendants(removeIt, setDescendants);
@@ -282,24 +285,26 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
// should be a bit faster.
// However, if we happen to be in the middle of processing a reorg, then
// the mempool can be in an inconsistent state. In this case, the set
- // of ancestors reachable via mapLinks will be the same as the set of
- // ancestors whose packages include this transaction, because when we
- // add a new transaction to the mempool in addUnchecked(), we assume it
- // has no children, and in the case of a reorg where that assumption is
- // false, the in-mempool children aren't linked to the in-block tx's
- // until UpdateTransactionsFromBlock() is called.
+ // of ancestors reachable via GetMemPoolParents()/GetMemPoolChildren()
+ // will be the same as the set of ancestors whose packages include this
+ // transaction, because when we add a new transaction to the mempool in
+ // addUnchecked(), we assume it has no children, and in the case of a
+ // reorg where that assumption is false, the in-mempool children aren't
+ // linked to the in-block tx's until UpdateTransactionsFromBlock() is
+ // called.
// So if we're being called during a reorg, ie before
- // UpdateTransactionsFromBlock() has been called, then mapLinks[] will
- // differ from the set of mempool parents we'd calculate by searching,
- // and it's important that we use the mapLinks[] notion of ancestor
- // transactions as the set of things to update for removal.
+ // UpdateTransactionsFromBlock() has been called, then
+ // GetMemPoolParents()/GetMemPoolChildren() will differ from the set of
+ // mempool parents we'd calculate by searching, and it's important that
+ // we use the cached notion of ancestor transactions as the set of
+ // things to update for removal.
CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
// Note that UpdateAncestorsOf severs the child links that point to
// removeIt in the entries for the parents of removeIt.
UpdateAncestorsOf(false, removeIt, setAncestors);
}
// After updating all the ancestor sizes, we can now sever the link between each
- // transaction being removed and any mempool children (ie, update setMemPoolParents
+ // transaction being removed and any mempool children (ie, update CTxMemPoolEntry::m_parents
// for each direct child of a transaction being removed).
for (txiter removeIt : entriesToRemove) {
UpdateChildrenForRemoval(removeIt);
@@ -359,7 +364,6 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
// Used by AcceptToMemoryPool(), which DOES do
// all the appropriate checks.
indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
- mapLinks.insert(make_pair(newit, TxLinks()));
// Update transaction for any feeDelta created by PrioritiseTransaction
// TODO: refactor so that the fee delta is calculated before inserting
@@ -430,15 +434,14 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
totalTxSize -= it->GetTxSize();
cachedInnerUsage -= it->DynamicMemoryUsage();
- cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + memusage::DynamicUsage(mapLinks[it].children);
- mapLinks.erase(it);
+ cachedInnerUsage -= memusage::DynamicUsage(it->GetMemPoolParentsConst()) + memusage::DynamicUsage(it->GetMemPoolChildrenConst());
mapTx.erase(it);
nTransactionsUpdated++;
if (minerPolicyEstimator) {minerPolicyEstimator->removeTx(hash, false);}
}
// Calculates descendants of entry that are not already in setDescendants, and adds to
-// setDescendants. Assumes entryit is already a tx in the mempool and setMemPoolChildren
+// setDescendants. Assumes entryit is already a tx in the mempool and CTxMemPoolEntry::m_children
// is correct for tx and all descendants.
// Also assumes that if an entry is in setDescendants already, then all
// in-mempool descendants of it are already in setDescendants as well, so that we
@@ -457,8 +460,9 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries& setDescendants
setDescendants.insert(it);
stage.erase(it);
- const setEntries &setChildren = GetMemPoolChildren(it);
- for (txiter childiter : setChildren) {
+ const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst();
+ for (const CTxMemPoolEntry& child : children) {
+ txiter childiter = mapTx.iterator_to(child);
if (!setDescendants.count(childiter)) {
stage.insert(childiter);
}
@@ -584,7 +588,6 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
void CTxMemPool::_clear()
{
- mapLinks.clear();
mapTx.clear();
mapNextTx.clear();
totalTxSize = 0;
@@ -633,12 +636,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
checkTotal += it->GetTxSize();
innerUsage += it->DynamicMemoryUsage();
const CTransaction& tx = it->GetTx();
- txlinksMap::const_iterator linksiter = mapLinks.find(it);
- assert(linksiter != mapLinks.end());
- const TxLinks &links = linksiter->second;
- innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children);
+ innerUsage += memusage::DynamicUsage(it->GetMemPoolParentsConst()) + memusage::DynamicUsage(it->GetMemPoolChildrenConst());
bool fDependsWait = false;
- setEntries setParentCheck;
+ CTxMemPoolEntry::Parents setParentCheck;
for (const CTxIn &txin : tx.vin) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
@@ -646,7 +646,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
const CTransaction& tx2 = it2->GetTx();
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
fDependsWait = true;
- setParentCheck.insert(it2);
+ setParentCheck.insert(*it2);
} else {
assert(pcoins->HaveCoin(txin.prevout));
}
@@ -657,7 +657,11 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(it3->second == &tx);
i++;
}
- assert(setParentCheck == GetMemPoolParents(it));
+ auto comp = [](const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) -> bool {
+ return a.GetTx().GetHash() == b.GetTx().GetHash();
+ };
+ assert(setParentCheck.size() == it->GetMemPoolParentsConst().size());
+ assert(std::equal(setParentCheck.begin(), setParentCheck.end(), it->GetMemPoolParentsConst().begin(), comp));
// Verify ancestor state is correct.
setEntries setAncestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
@@ -680,17 +684,18 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(it->GetModFeesWithAncestors() == nFeesCheck);
// Check children against mapNextTx
- CTxMemPool::setEntries setChildrenCheck;
+ CTxMemPoolEntry::Children setChildrenCheck;
auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
uint64_t child_sizes = 0;
for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) {
txiter childit = mapTx.find(iter->second->GetHash());
assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
- if (setChildrenCheck.insert(childit).second) {
+ if (setChildrenCheck.insert(*childit).second) {
child_sizes += childit->GetTxSize();
}
}
- assert(setChildrenCheck == GetMemPoolChildren(it));
+ assert(setChildrenCheck.size() == it->GetMemPoolChildrenConst().size());
+ assert(std::equal(setChildrenCheck.begin(), setChildrenCheck.end(), it->GetMemPoolChildrenConst().begin(), comp));
// Also check to make sure size is greater than sum with immediate children.
// just a sanity check, not definitive that this calc is correct...
assert(it->GetSizeWithDescendants() >= child_sizes + it->GetTxSize());
@@ -852,9 +857,9 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
LogPrintf("PrioritiseTransaction: %s feerate += %s\n", hash.ToString(), FormatMoney(nFeeDelta));
}
-void CTxMemPool::ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const
+void CTxMemPool::ApplyDelta(const uint256& hash, CAmount &nFeeDelta) const
{
- LOCK(cs);
+ AssertLockHeld(cs);
std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
if (pos == mapDeltas.end())
return;
@@ -862,9 +867,9 @@ void CTxMemPool::ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const
nFeeDelta += delta;
}
-void CTxMemPool::ClearPrioritisation(const uint256 hash)
+void CTxMemPool::ClearPrioritisation(const uint256& hash)
{
- LOCK(cs);
+ AssertLockHeld(cs);
mapDeltas.erase(hash);
}
@@ -920,7 +925,7 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
size_t CTxMemPool::DynamicMemoryUsage() const {
LOCK(cs);
// Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
- return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage;
+ return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage;
}
void CTxMemPool::RemoveUnbroadcastTx(const uint256& txid, const bool unchecked) {
@@ -968,40 +973,26 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimat
void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add)
{
- setEntries s;
- if (add && mapLinks[entry].children.insert(child).second) {
+ AssertLockHeld(cs);
+ CTxMemPoolEntry::Children s;
+ if (add && entry->GetMemPoolChildren().insert(*child).second) {
cachedInnerUsage += memusage::IncrementalDynamicUsage(s);
- } else if (!add && mapLinks[entry].children.erase(child)) {
+ } else if (!add && entry->GetMemPoolChildren().erase(*child)) {
cachedInnerUsage -= memusage::IncrementalDynamicUsage(s);
}
}
void CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add)
{
- setEntries s;
- if (add && mapLinks[entry].parents.insert(parent).second) {
+ AssertLockHeld(cs);
+ CTxMemPoolEntry::Parents s;
+ if (add && entry->GetMemPoolParents().insert(*parent).second) {
cachedInnerUsage += memusage::IncrementalDynamicUsage(s);
- } else if (!add && mapLinks[entry].parents.erase(parent)) {
+ } else if (!add && entry->GetMemPoolParents().erase(*parent)) {
cachedInnerUsage -= memusage::IncrementalDynamicUsage(s);
}
}
-const CTxMemPool::setEntries & CTxMemPool::GetMemPoolParents(txiter entry) const
-{
- assert (entry != mapTx.end());
- txlinksMap::const_iterator it = mapLinks.find(entry);
- assert(it != mapLinks.end());
- return it->second.parents;
-}
-
-const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) const
-{
- assert (entry != mapTx.end());
- txlinksMap::const_iterator it = mapLinks.find(entry);
- assert(it != mapLinks.end());
- return it->second.children;
-}
-
CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
LOCK(cs);
if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
@@ -1087,12 +1078,12 @@ uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
txiter candidate = candidates.back();
candidates.pop_back();
if (!counted.insert(candidate).second) continue;
- const setEntries& parents = GetMemPoolParents(candidate);
+ const CTxMemPoolEntry::Parents& parents = candidate->GetMemPoolParentsConst();
if (parents.size() == 0) {
maximum = std::max(maximum, candidate->GetCountWithDescendants());
} else {
- for (txiter i : parents) {
- candidates.push_back(i);
+ for (const CTxMemPoolEntry& i : parents) {
+ candidates.push_back(mapTx.iterator_to(i));
}
}
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 4743e1b63a..664fb5986a 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -49,6 +49,20 @@ struct LockPoints
LockPoints() : height(0), time(0), maxInputBlock(nullptr) { }
};
+struct CompareIteratorByHash {
+ // SFINAE for T where T is either a pointer type (e.g., a txiter) or a reference_wrapper<T>
+ // (e.g. a wrapped CTxMemPoolEntry&)
+ template <typename T>
+ bool operator()(const std::reference_wrapper<T>& a, const std::reference_wrapper<T>& b) const
+ {
+ return a.get().GetTx().GetHash() < b.get().GetTx().GetHash();
+ }
+ template <typename T>
+ bool operator()(const T& a, const T& b) const
+ {
+ return a->GetTx().GetHash() < b->GetTx().GetHash();
+ }
+};
/** \class CTxMemPoolEntry
*
* CTxMemPoolEntry stores data about the corresponding transaction, as well
@@ -63,8 +77,16 @@ struct LockPoints
class CTxMemPoolEntry
{
+public:
+ typedef std::reference_wrapper<const CTxMemPoolEntry> CTxMemPoolEntryRef;
+ // two aliases, should the types ever diverge
+ typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Parents;
+ typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Children;
+
private:
const CTransactionRef tx;
+ mutable Parents m_parents;
+ mutable Children m_children;
const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
const size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
const size_t nUsageSize; //!< ... and total memory usage
@@ -127,6 +149,11 @@ public:
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }
+ const Parents& GetMemPoolParentsConst() const { return m_parents; }
+ const Children& GetMemPoolChildrenConst() const { return m_children; }
+ Parents& GetMemPoolParents() const { return m_parents; }
+ Children& GetMemPoolChildren() const { return m_children; }
+
mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes
mutable uint64_t m_epoch; //!< epoch when last touched, useful for graph algorithms
};
@@ -547,37 +574,22 @@ public:
using txiter = indexed_transaction_set::nth_index<0>::type::const_iterator;
std::vector<std::pair<uint256, txiter>> vTxHashes GUARDED_BY(cs); //!< All tx witness hashes/entries in mapTx, in random order
- struct CompareIteratorByHash {
- bool operator()(const txiter &a, const txiter &b) const {
- return a->GetTx().GetHash() < b->GetTx().GetHash();
- }
- };
typedef std::set<txiter, CompareIteratorByHash> setEntries;
- const setEntries & GetMemPoolParents(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
- const setEntries & GetMemPoolChildren(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
uint64_t CalculateDescendantMaximum(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
private:
typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;
- struct TxLinks {
- setEntries parents;
- setEntries children;
- };
-
- typedef std::map<txiter, TxLinks, CompareIteratorByHash> txlinksMap;
- txlinksMap mapLinks;
- void UpdateParent(txiter entry, txiter parent, bool add);
- void UpdateChild(txiter entry, txiter child, bool add);
+ void UpdateParent(txiter entry, txiter parent, bool add) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void UpdateChild(txiter entry, txiter child, bool add) EXCLUSIVE_LOCKS_REQUIRED(cs);
std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const EXCLUSIVE_LOCKS_REQUIRED(cs);
/**
- * track locally submitted transactions to periodically retry initial broadcast
- * map of txid -> wtxid
+ * Track locally submitted transactions to periodically retry initial broadcast.
*/
- std::map<uint256, uint256> m_unbroadcast_txids GUARDED_BY(cs);
+ std::set<uint256> m_unbroadcast_txids GUARDED_BY(cs);
public:
indirectmap<COutPoint, const CTransaction*> mapNextTx GUARDED_BY(cs);
@@ -626,8 +638,8 @@ public:
/** Affect CreateNewBlock prioritisation of transactions */
void PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta);
- void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const;
- void ClearPrioritisation(const uint256 hash);
+ void ApplyDelta(const uint256& hash, CAmount &nFeeDelta) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void ClearPrioritisation(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Get the transaction in the pool that spends the same prevout */
const CTransaction* GetConflictTx(const COutPoint& prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs);
@@ -710,9 +722,9 @@ public:
return mapTx.size();
}
- uint64_t GetTotalTxSize() const
+ uint64_t GetTotalTxSize() const EXCLUSIVE_LOCKS_REQUIRED(cs)
{
- LOCK(cs);
+ AssertLockHeld(cs);
return totalTxSize;
}
@@ -739,27 +751,29 @@ public:
size_t DynamicMemoryUsage() const;
/** Adds a transaction to the unbroadcast set */
- void AddUnbroadcastTx(const uint256& txid, const uint256& wtxid) {
+ void AddUnbroadcastTx(const uint256& txid)
+ {
LOCK(cs);
- // Sanity Check: the transaction should also be in the mempool
- if (exists(txid)) {
- m_unbroadcast_txids[txid] = wtxid;
- }
- }
+ // Sanity check the transaction is in the mempool & insert into
+ // unbroadcast set.
+ if (exists(txid)) m_unbroadcast_txids.insert(txid);
+ };
/** Removes a transaction from the unbroadcast set */
void RemoveUnbroadcastTx(const uint256& txid, const bool unchecked = false);
/** Returns transactions in unbroadcast set */
- std::map<uint256, uint256> GetUnbroadcastTxs() const {
+ std::set<uint256> GetUnbroadcastTxs() const
+ {
LOCK(cs);
return m_unbroadcast_txids;
}
/** Returns whether a txid is in the unbroadcast set */
- bool IsUnbroadcastTx(const uint256& txid) const {
- LOCK(cs);
- return (m_unbroadcast_txids.count(txid) != 0);
+ bool IsUnbroadcastTx(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
+ {
+ AssertLockHeld(cs);
+ return m_unbroadcast_txids.count(txid) != 0;
}
private:
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 999937d906..41715aac1a 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -263,6 +263,7 @@ const std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
// Section names to be recognized in the config file.
static const std::set<std::string> available_sections{
CBaseChainParams::REGTEST,
+ CBaseChainParams::SIGNET,
CBaseChainParams::TESTNET,
CBaseChainParams::MAIN
};
@@ -916,16 +917,21 @@ std::string ArgsManager::GetChainName() const
};
const bool fRegTest = get_net("-regtest");
+ const bool fSigNet = get_net("-signet");
const bool fTestNet = get_net("-testnet");
const bool is_chain_arg_set = IsArgSet("-chain");
- if ((int)is_chain_arg_set + (int)fRegTest + (int)fTestNet > 1) {
- throw std::runtime_error("Invalid combination of -regtest, -testnet and -chain. Can use at most one.");
+ if ((int)is_chain_arg_set + (int)fRegTest + (int)fSigNet + (int)fTestNet > 1) {
+ throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet and -chain. Can use at most one.");
}
if (fRegTest)
return CBaseChainParams::REGTEST;
+ if (fSigNet) {
+ return CBaseChainParams::SIGNET;
+ }
if (fTestNet)
return CBaseChainParams::TESTNET;
+
return GetArg("-chain", CBaseChainParams::MAIN);
}
diff --git a/src/validation.cpp b/src/validation.cpp
index 58af8744d9..a96913e3a0 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -33,6 +33,7 @@
#include <script/script.h>
#include <script/sigcache.h>
#include <shutdown.h>
+#include <signet.h>
#include <timedata.h>
#include <tinyformat.h>
#include <txdb.h>
@@ -148,7 +149,6 @@ arith_uint256 nMinimumChainWork;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CBlockPolicyEstimator feeEstimator;
-CTxMemPool mempool(&feeEstimator);
// Internal stuff
namespace {
@@ -476,6 +476,7 @@ public:
*/
std::vector<COutPoint>& m_coins_to_uncache;
const bool m_test_accept;
+ CAmount* m_fee_out;
};
// Single transaction acceptance
@@ -688,6 +689,11 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return false; // state filled in by CheckTxInputs
}
+ // If fee_out is passed, return the fee to the caller
+ if (args.m_fee_out) {
+ *args.m_fee_out = nFees;
+ }
+
// Check for non-standard pay-to-script-hash in inputs
if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
@@ -1062,10 +1068,10 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
/** (try to) add transaction to memory pool with a specified acceptance time **/
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ bool bypass_limits, const CAmount nAbsurdFee, bool test_accept, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
std::vector<COutPoint> coins_to_uncache;
- MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept };
+ MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept, fee_out };
bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args);
if (!res) {
// Remove coins that were not present in the coins cache before calling ATMPW;
@@ -1084,10 +1090,10 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept)
+ bool bypass_limits, const CAmount nAbsurdFee, bool test_accept, CAmount* fee_out)
{
const CChainParams& chainparams = Params();
- return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee, test_accept);
+ return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee, test_accept, fee_out);
}
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
@@ -1164,6 +1170,11 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
+ // Signet only: check block solution
+ if (consensusParams.signet_blocks && !CheckSignetBlockSolution(block, consensusParams)) {
+ return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString());
+ }
+
return true;
}
@@ -3341,6 +3352,11 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW))
return false;
+ // Signet only: check block solution
+ if (consensusParams.signet_blocks && fCheckPOW && !CheckSignetBlockSolution(block, consensusParams)) {
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-signet-blksig", "signet block signature validation failure");
+ }
+
// Check the merkle root.
if (fCheckMerkleRoot) {
bool mutated;
@@ -3404,31 +3420,11 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
return (height >= params.SegwitHeight);
}
-int GetWitnessCommitmentIndex(const CBlock& block)
-{
- int commitpos = -1;
- if (!block.vtx.empty()) {
- for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
- const CTxOut& vout = block.vtx[0]->vout[o];
- if (vout.scriptPubKey.size() >= MINIMUM_WITNESS_COMMITMENT &&
- vout.scriptPubKey[0] == OP_RETURN &&
- vout.scriptPubKey[1] == 0x24 &&
- vout.scriptPubKey[2] == 0xaa &&
- vout.scriptPubKey[3] == 0x21 &&
- vout.scriptPubKey[4] == 0xa9 &&
- vout.scriptPubKey[5] == 0xed) {
- commitpos = o;
- }
- }
- }
- return commitpos;
-}
-
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams)
{
int commitpos = GetWitnessCommitmentIndex(block);
static const std::vector<unsigned char> nonce(32, 0x00);
- if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && !block.vtx[0]->HasWitness()) {
+ if (commitpos != NO_WITNESS_COMMITMENT && IsWitnessEnabled(pindexPrev, consensusParams) && !block.vtx[0]->HasWitness()) {
CMutableTransaction tx(*block.vtx[0]);
tx.vin[0].scriptWitness.stack.resize(1);
tx.vin[0].scriptWitness.stack[0] = nonce;
@@ -3442,7 +3438,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
int commitpos = GetWitnessCommitmentIndex(block);
std::vector<unsigned char> ret(32, 0x00);
if (consensusParams.SegwitHeight != std::numeric_limits<int>::max()) {
- if (commitpos == -1) {
+ if (commitpos == NO_WITNESS_COMMITMENT) {
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
CHash256().Write(witnessroot).Write(ret).Finalize(witnessroot);
CTxOut out;
@@ -3580,7 +3576,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
bool fHaveWitness = false;
if (nHeight >= consensusParams.SegwitHeight) {
int commitpos = GetWitnessCommitmentIndex(block);
- if (commitpos != -1) {
+ if (commitpos != NO_WITNESS_COMMITMENT) {
bool malleated = false;
uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated);
// The malleation check is ignored; as the transaction tree itself
@@ -4227,6 +4223,14 @@ bool static LoadBlockIndexDB(ChainstateManager& chainman, const CChainParams& ch
return true;
}
+void CChainState::LoadMempool(const ArgsManager& args)
+{
+ if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
+ ::LoadMempool(m_mempool);
+ }
+ m_mempool.SetIsLoaded(!ShutdownRequested());
+}
+
bool CChainState::LoadChainTip(const CChainParams& chainparams)
{
AssertLockHeld(cs_main);
@@ -5116,7 +5120,7 @@ bool LoadMempool(CTxMemPool& pool)
}
// TODO: remove this try except in v0.22
- std::map<uint256, uint256> unbroadcast_txids;
+ std::set<uint256> unbroadcast_txids;
try {
file >> unbroadcast_txids;
unbroadcast = unbroadcast_txids.size();
@@ -5124,13 +5128,10 @@ bool LoadMempool(CTxMemPool& pool)
// mempool.dat files created prior to v0.21 will not have an
// unbroadcast set. No need to log a failure if parsing fails here.
}
- for (const auto& elem : unbroadcast_txids) {
- // Don't add unbroadcast transactions that didn't get back into the
- // mempool.
- const CTransactionRef& added_tx = pool.get(elem.first);
- if (added_tx != nullptr) {
- pool.AddUnbroadcastTx(elem.first, added_tx->GetWitnessHash());
- }
+ for (const auto& txid : unbroadcast_txids) {
+ // Ensure transactions were accepted to mempool then add to
+ // unbroadcast set.
+ if (pool.get(txid) != nullptr) pool.AddUnbroadcastTx(txid);
}
} catch (const std::exception& e) {
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
@@ -5147,7 +5148,7 @@ bool DumpMempool(const CTxMemPool& pool)
std::map<uint256, CAmount> mapDeltas;
std::vector<TxMempoolInfo> vinfo;
- std::map<uint256, uint256> unbroadcast_txids;
+ std::set<uint256> unbroadcast_txids;
static Mutex dump_mutex;
LOCK(dump_mutex);
diff --git a/src/validation.h b/src/validation.h
index bb59b57f6b..0da62093a3 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -93,8 +93,6 @@ static const unsigned int DEFAULT_CHECKLEVEL = 3;
// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB
// Setting the target to >= 550 MiB will make it likely we can respect the target.
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
-/** Minimum size of a witness commitment structure. Defined in BIP 141. **/
-static constexpr size_t MINIMUM_WITNESS_COMMITMENT{38};
struct BlockHasher
{
@@ -113,7 +111,6 @@ enum class SynchronizationState {
extern RecursiveMutex cs_main;
extern CBlockPolicyEstimator feeEstimator;
-extern CTxMemPool mempool;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
extern Mutex g_best_block_mutex;
extern std::condition_variable g_best_block_cv;
@@ -200,10 +197,11 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
void PruneBlockFilesManual(int nManualPruneHeight);
/** (try to) add transaction to memory pool
- * plTxnReplaced will be appended to with all transactions replaced from mempool **/
+ * plTxnReplaced will be appended to with all transactions replaced from mempool
+ * @param[out] fee_out optional argument to return tx fee to the caller **/
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
@@ -245,7 +243,7 @@ bool TestLockPointValidity(const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_mai
*
* See consensus/consensus.h for flag definitions.
*/
-bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs);
/**
* Closure representing one script verification
@@ -306,9 +304,6 @@ bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainpar
* Note that transaction witness validation rules are always enforced when P2SH is enforced. */
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
-/** Compute at which vout of the block's coinbase transaction the witness commitment occurs, or -1 if not found */
-int GetWitnessCommitmentIndex(const CBlock& block);
-
/** Update uncommitted block structures (currently: only the witness reserved value). This is safe for submitted blocks. */
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);
@@ -671,6 +666,9 @@ public:
*/
void CheckBlockIndex(const Consensus::Params& consensusParams);
+ /** Load the persisted mempool from disk */
+ void LoadMempool(const ArgsManager& args);
+
/** Update the chain tip based on database information, i.e. CoinsTip()'s best block. */
bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 24eb2ee34c..fbb3d2cac5 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -52,18 +52,6 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
return memcmp(value, &rhs.value, sizeof(value)) == 0;
}
-bool IsBDBWalletLoaded(const fs::path& wallet_path)
-{
- fs::path env_directory;
- std::string database_filename;
- SplitWalletPath(wallet_path, env_directory, database_filename);
- LOCK(cs_db);
- auto env = g_dbenvs.find(env_directory.string());
- if (env == g_dbenvs.end()) return false;
- auto database = env->second.lock();
- return database && database->IsDatabaseLoaded(database_filename);
-}
-
/**
* @param[in] wallet_path Path to wallet directory. Or (for backwards compatibility only) a path to a berkeley btree data file inside a wallet directory.
* @param[out] database_filename Filename of berkeley btree data file inside the wallet directory.
@@ -371,7 +359,6 @@ void BerkeleyDatabase::Open(const char* pszMode)
if (ret != 0) {
throw std::runtime_error(strprintf("BerkeleyDatabase: Error %d, can't open database %s", ret, strFile));
}
- m_file_path = (env->Directory() / strFile).string();
// Call CheckUniqueFileid on the containing BDB environment to
// avoid BDB data consistency bugs that happen when different data
@@ -824,3 +811,35 @@ std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(const char* mode, boo
{
return MakeUnique<BerkeleyBatch>(*this, mode, flush_on_close);
}
+
+bool ExistsBerkeleyDatabase(const fs::path& path)
+{
+ fs::path env_directory;
+ std::string data_filename;
+ SplitWalletPath(path, env_directory, data_filename);
+ return IsBerkeleyBtree(env_directory / data_filename);
+}
+
+std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
+{
+ std::unique_ptr<BerkeleyDatabase> db;
+ {
+ LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
+ std::string data_filename;
+ std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(path, data_filename);
+ if (env->m_databases.count(data_filename)) {
+ error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
+ status = DatabaseStatus::FAILED_ALREADY_LOADED;
+ return nullptr;
+ }
+ db = MakeUnique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
+ }
+
+ if (options.verify && !db->Verify(error)) {
+ status = DatabaseStatus::FAILED_VERIFY;
+ return nullptr;
+ }
+
+ status = DatabaseStatus::SUCCESS;
+ return db;
+}
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index 75546924e8..fd5a49acc3 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -63,7 +63,6 @@ public:
bool IsMock() const { return fMockDb; }
bool IsInitialized() const { return fDbEnvInit; }
- bool IsDatabaseLoaded(const std::string& db_filename) const { return m_databases.find(db_filename) != m_databases.end(); }
fs::path Directory() const { return strPath; }
bool Open(bilingual_str& error);
@@ -87,8 +86,8 @@ public:
/** Get BerkeleyEnvironment and database filename given a wallet path. */
std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
-/** Return whether a BDB wallet database is currently loaded. */
-bool IsBDBWalletLoaded(const fs::path& wallet_path);
+/** Check format of database file */
+bool IsBerkeleyBtree(const fs::path& path);
class BerkeleyBatch;
@@ -143,7 +142,10 @@ public:
void ReloadDbEnv() override;
/** Verifies the environment and database file */
- bool Verify(bilingual_str& error) override;
+ bool Verify(bilingual_str& error);
+
+ /** Return path to main database filename */
+ std::string Filename() override { return (env->Directory() / strFile).string(); }
/**
* Pointer to shared database environment.
@@ -224,4 +226,10 @@ public:
std::string BerkeleyDatabaseVersion();
+//! Check if Berkeley database exists at specified path.
+bool ExistsBerkeleyDatabase(const fs::path& path);
+
+//! Return object giving access to Berkeley database at specified path.
+std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
+
#endif // BITCOIN_WALLET_BDB_H
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 1eb82a03c7..bd1d114730 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -23,11 +23,3 @@ void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::
database_filename = "wallet.dat";
}
}
-
-fs::path WalletDataFilePath(const fs::path& wallet_path)
-{
- fs::path env_directory;
- std::string database_filename;
- SplitWalletPath(wallet_path, env_directory, database_filename);
- return env_directory / database_filename;
-}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 0afaba5fd1..617ed46141 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -9,6 +9,7 @@
#include <clientversion.h>
#include <fs.h>
#include <streams.h>
+#include <support/allocators/secure.h>
#include <util/memory.h>
#include <atomic>
@@ -17,8 +18,6 @@
struct bilingual_str;
-/** Given a wallet directory path or legacy file path, return path to main data file in the wallet database. */
-fs::path WalletDataFilePath(const fs::path& wallet_path);
void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename);
/** RAII class that provides access to a WalletDatabase */
@@ -141,16 +140,14 @@ public:
virtual void ReloadDbEnv() = 0;
+ /** Return path to main database file for logs and error messages. */
+ virtual std::string Filename() = 0;
+
std::atomic<unsigned int> nUpdateCounter;
unsigned int nLastSeen;
unsigned int nLastFlushed;
int64_t nLastWalletUpdate;
- /** Verifies the environment and database file */
- virtual bool Verify(bilingual_str& error) = 0;
-
- std::string m_file_path;
-
/** Make a DatabaseBatch connected to this database */
virtual std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) = 0;
};
@@ -191,8 +188,35 @@ public:
bool PeriodicFlush() override { return true; }
void IncrementUpdateCounter() override { ++nUpdateCounter; }
void ReloadDbEnv() override {}
- bool Verify(bilingual_str& errorStr) override { return true; }
+ std::string Filename() override { return "dummy"; }
std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); }
};
+enum class DatabaseFormat {
+ BERKELEY,
+};
+
+struct DatabaseOptions {
+ bool require_existing = false;
+ bool require_create = false;
+ uint64_t create_flags = 0;
+ SecureString create_passphrase;
+ bool verify = true;
+};
+
+enum class DatabaseStatus {
+ SUCCESS,
+ FAILED_BAD_PATH,
+ FAILED_BAD_FORMAT,
+ FAILED_ALREADY_LOADED,
+ FAILED_ALREADY_EXISTS,
+ FAILED_NOT_FOUND,
+ FAILED_CREATE,
+ FAILED_LOAD,
+ FAILED_VERIFY,
+ FAILED_ENCRYPT,
+};
+
+std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
+
#endif // BITCOIN_WALLET_DB_H
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 1456e1595e..5d8c4fba29 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -67,13 +67,13 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID and %w is replaced by wallet name. %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
#endif
argsman.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
- argsman.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
- " (1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
argsman.AddArg("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
argsman.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
argsman.AddArg("-walletrejectlongchains", strprintf("Wallet will not create transactions that violate mempool chain limits (default: %u)", DEFAULT_WALLET_REJECT_LONG_CHAINS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
+
+ argsman.AddHiddenArgs({"-zapwallettxes"});
}
bool WalletInit::ParameterInteraction() const
@@ -86,26 +86,12 @@ bool WalletInit::ParameterInteraction() const
return true;
}
- const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
-
if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
}
- bool zapwallettxes = gArgs.GetBoolArg("-zapwallettxes", false);
- // -zapwallettxes implies dropping the mempool on startup
- if (zapwallettxes && gArgs.SoftSetBoolArg("-persistmempool", false)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -persistmempool=0\n", __func__);
- }
-
- // -zapwallettxes implies a rescan
- if (zapwallettxes) {
- if (is_multiwallet) {
- return InitError(strprintf(Untranslated("%s is only allowed with a single wallet file"), "-zapwallettxes"));
- }
- if (gArgs.SoftSetBoolArg("-rescan", true)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -rescan=1\n", __func__);
- }
+ if (gArgs.IsArgSet("-zapwallettxes")) {
+ return InitError(Untranslated("-zapwallettxes has been removed. If you are attempting to remove a stuck transaction from your wallet, please use abandontransaction instead."));
}
if (gArgs.GetBoolArg("-sysperms", false))
@@ -121,16 +107,7 @@ void WalletInit::Construct(NodeContext& node) const
LogPrintf("Wallet disabled!\n");
return;
}
- // If there's no -wallet setting with a list of wallets to load, set it to
- // load the default "" wallet.
- if (!args.IsArgSet("wallet")) {
- args.LockSettings([&](util::Settings& settings) {
- util::SettingsValue wallets(util::SettingsValue::VARR);
- wallets.push_back(""); // Default wallet name is ""
- settings.rw_settings["wallet"] = wallets;
- });
- }
- auto wallet_client = interfaces::MakeWalletClient(*node.chain, args, args.GetArgs("-wallet"));
+ auto wallet_client = interfaces::MakeWalletClient(*node.chain, args);
node.wallet_client = wallet_client.get();
node.chain_clients.emplace_back(std::move(wallet_client));
}
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index ae14769edb..1b057000d2 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -5,6 +5,7 @@
#include <wallet/load.h>
+#include <fs.h>
#include <interfaces/chain.h>
#include <scheduler.h>
#include <util/string.h>
@@ -15,7 +16,7 @@
#include <univalue.h>
-bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
+bool VerifyWallets(interfaces::Chain& chain)
{
if (gArgs.IsArgSet("-walletdir")) {
fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
@@ -40,22 +41,39 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
chain.initMessage(_("Verifying wallet(s)...").translated);
+ // For backwards compatibility if an unnamed top level wallet exists in the
+ // wallets directory, include it in the default list of wallets to load.
+ if (!gArgs.IsArgSet("wallet")) {
+ DatabaseOptions options;
+ DatabaseStatus status;
+ bilingual_str error_string;
+ options.require_existing = true;
+ options.verify = false;
+ if (MakeWalletDatabase("", options, status, error_string)) {
+ gArgs.LockSettings([&](util::Settings& settings) {
+ util::SettingsValue wallets(util::SettingsValue::VARR);
+ wallets.push_back(""); // Default wallet name is ""
+ settings.rw_settings["wallet"] = wallets;
+ });
+ }
+ }
+
// Keep track of each wallet absolute path to detect duplicates.
std::set<fs::path> wallet_paths;
- for (const auto& wallet_file : wallet_files) {
- WalletLocation location(wallet_file);
+ for (const auto& wallet_file : gArgs.GetArgs("-wallet")) {
+ const fs::path path = fs::absolute(wallet_file, GetWalletDir());
- if (!wallet_paths.insert(location.GetPath()).second) {
+ if (!wallet_paths.insert(path).second) {
chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
return false;
}
+ DatabaseOptions options;
+ DatabaseStatus status;
+ options.verify = true;
bilingual_str error_string;
- std::vector<bilingual_str> warnings;
- bool verify_success = CWallet::Verify(chain, location, error_string, warnings);
- if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
- if (!verify_success) {
+ if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
chain.initError(error_string);
return false;
}
@@ -64,13 +82,17 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
return true;
}
-bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
+bool LoadWallets(interfaces::Chain& chain)
{
try {
- for (const std::string& walletFile : wallet_files) {
+ for (const std::string& name : gArgs.GetArgs("-wallet")) {
+ DatabaseOptions options;
+ DatabaseStatus status;
+ options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets()
bilingual_str error;
std::vector<bilingual_str> warnings;
- std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile), error, warnings);
+ std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
+ std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(chain, name, std::move(database), options.create_flags, error, warnings) : nullptr;
if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
if (!pwallet) {
chain.initError(error);
@@ -118,30 +140,8 @@ void UnloadWallets()
while (!wallets.empty()) {
auto wallet = wallets.back();
wallets.pop_back();
- RemoveWallet(wallet);
+ std::vector<bilingual_str> warnings;
+ RemoveWallet(wallet, nullopt, warnings);
UnloadWallet(std::move(wallet));
}
}
-
-bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
-{
- util::SettingsValue setting_value = chain.getRwSetting("wallet");
- if (!setting_value.isArray()) setting_value.setArray();
- for (const util::SettingsValue& value : setting_value.getValues()) {
- if (value.isStr() && value.get_str() == wallet_name) return true;
- }
- setting_value.push_back(wallet_name);
- return chain.updateRwSetting("wallet", setting_value);
-}
-
-bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
-{
- util::SettingsValue setting_value = chain.getRwSetting("wallet");
- if (!setting_value.isArray()) return true;
- util::SettingsValue new_value(util::SettingsValue::VARR);
- for (const util::SettingsValue& value : setting_value.getValues()) {
- if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value);
- }
- if (new_value.size() == setting_value.size()) return true;
- return chain.updateRwSetting("wallet", new_value);
-}
diff --git a/src/wallet/load.h b/src/wallet/load.h
index 30f1a4c90d..e12343de27 100644
--- a/src/wallet/load.h
+++ b/src/wallet/load.h
@@ -17,10 +17,10 @@ class Chain;
} // namespace interfaces
//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
-bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
+bool VerifyWallets(interfaces::Chain& chain);
//! Load wallet databases.
-bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
+bool LoadWallets(interfaces::Chain& chain);
//! Complete startup of wallets.
void StartWallets(CScheduler& scheduler, const ArgsManager& args);
@@ -34,10 +34,4 @@ void StopWallets();
//! Close all wallets.
void UnloadWallets();
-//! Add wallet name to persistent configuration so it will be loaded on startup.
-bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);
-
-//! Remove wallet name from persistent configuration so it will not be loaded on startup.
-bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);
-
#endif // BITCOIN_WALLET_LOAD_H
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index a43fa10266..62a3206802 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -11,6 +11,7 @@
#include <outputtype.h>
#include <policy/feerate.h>
#include <policy/fees.h>
+#include <policy/policy.h>
#include <policy/rbf.h>
#include <rpc/rawtransaction_util.h>
#include <rpc/server.h>
@@ -230,18 +231,6 @@ static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const U
}
}
-static void UpdateWalletSetting(interfaces::Chain& chain,
- const std::string& wallet_name,
- const UniValue& load_on_startup,
- std::vector<bilingual_str>& warnings)
-{
- if (load_on_startup.isTrue() && !AddWalletSetting(chain, wallet_name)) {
- warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
- } else if (load_on_startup.isFalse() && !RemoveWalletSetting(chain, wallet_name)) {
- warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
- }
-}
-
static UniValue getnewaddress(const JSONRPCRequest& request)
{
RPCHelpMan{"getnewaddress",
@@ -2495,7 +2484,7 @@ static UniValue loadwallet(const JSONRPCRequest& request)
RPCHelpMan{"loadwallet",
"\nLoads a wallet from a wallet file or directory."
"\nNote that all wallet command-line options used when starting bitcoind will be"
- "\napplied to the new wallet (eg -zapwallettxes, rescan, etc).\n",
+ "\napplied to the new wallet (eg -rescan, etc).\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
{"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
@@ -2514,24 +2503,21 @@ static UniValue loadwallet(const JSONRPCRequest& request)
}.Check(request);
WalletContext& context = EnsureWalletContext(request.context);
- WalletLocation location(request.params[0].get_str());
-
- if (!location.Exists()) {
- throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found.");
- } else if (fs::is_directory(location.GetPath())) {
- // The given filename is a directory. Check that there's a wallet.dat file.
- fs::path wallet_dat_file = location.GetPath() / "wallet.dat";
- if (fs::symlink_status(wallet_dat_file).type() == fs::file_not_found) {
- throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Directory " + location.GetName() + " does not contain a wallet.dat file.");
- }
- }
+ const std::string name(request.params[0].get_str());
+ DatabaseOptions options;
+ DatabaseStatus status;
+ options.require_existing = true;
bilingual_str error;
std::vector<bilingual_str> warnings;
- std::shared_ptr<CWallet> const wallet = LoadWallet(*context.chain, location, error, warnings);
- if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error.original);
-
- UpdateWalletSetting(*context.chain, location.GetName(), request.params[1], warnings);
+ Optional<bool> load_on_start = request.params[1].isNull() ? nullopt : Optional<bool>(request.params[1].get_bool());
+ std::shared_ptr<CWallet> const wallet = LoadWallet(*context.chain, name, load_on_start, options, status, error, warnings);
+ if (!wallet) {
+ // Map bad format to not found, since bad format is returned when the
+ // wallet directory exists, but doesn't contain a data file.
+ RPCErrorCode code = status == DatabaseStatus::FAILED_NOT_FOUND || status == DatabaseStatus::FAILED_BAD_FORMAT ? RPC_WALLET_NOT_FOUND : RPC_WALLET_ERROR;
+ throw JSONRPCError(code, error.original);
+ }
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
@@ -2660,21 +2646,19 @@ static UniValue createwallet(const JSONRPCRequest& request)
warnings.emplace_back(Untranslated("Wallet is an experimental descriptor wallet"));
}
+ DatabaseOptions options;
+ DatabaseStatus status;
+ options.require_create = true;
+ options.create_flags = flags;
+ options.create_passphrase = passphrase;
bilingual_str error;
- std::shared_ptr<CWallet> wallet;
- WalletCreationStatus status = CreateWallet(*context.chain, passphrase, flags, request.params[0].get_str(), error, warnings, wallet);
- switch (status) {
- case WalletCreationStatus::CREATION_FAILED:
- throw JSONRPCError(RPC_WALLET_ERROR, error.original);
- case WalletCreationStatus::ENCRYPTION_FAILED:
- throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error.original);
- case WalletCreationStatus::SUCCESS:
- break;
- // no default case, so the compiler can warn about missing cases
+ Optional<bool> load_on_start = request.params[6].isNull() ? nullopt : Optional<bool>(request.params[6].get_bool());
+ std::shared_ptr<CWallet> wallet = CreateWallet(*context.chain, request.params[0].get_str(), load_on_start, options, status, error, warnings);
+ if (!wallet) {
+ RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
+ throw JSONRPCError(code, error.original);
}
- UpdateWalletSetting(*context.chain, request.params[0].get_str(), request.params[6], warnings);
-
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
@@ -2717,15 +2701,13 @@ static UniValue unloadwallet(const JSONRPCRequest& request)
// Release the "main" shared pointer and prevent further notifications.
// Note that any attempt to load the same wallet would fail until the wallet
// is destroyed (see CheckUniqueFileid).
- if (!RemoveWallet(wallet)) {
+ std::vector<bilingual_str> warnings;
+ Optional<bool> load_on_start = request.params[1].isNull() ? nullopt : Optional<bool>(request.params[1].get_bool());
+ if (!RemoveWallet(wallet, load_on_start, warnings)) {
throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
}
- interfaces::Chain& chain = wallet->chain();
- std::vector<bilingual_str> warnings;
-
UnloadWallet(std::move(wallet));
- UpdateWalletSetting(chain, wallet_name, request.params[1], warnings);
UniValue result(UniValue::VOBJ);
result.pushKV("warning", Join(warnings, Untranslated("\n")).original);
@@ -2974,13 +2956,22 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
RPCTypeCheckObj(options,
{
{"add_inputs", UniValueType(UniValue::VBOOL)},
+ {"add_to_wallet", UniValueType(UniValue::VBOOL)},
{"changeAddress", UniValueType(UniValue::VSTR)},
+ {"change_address", UniValueType(UniValue::VSTR)},
{"changePosition", UniValueType(UniValue::VNUM)},
+ {"change_position", UniValueType(UniValue::VNUM)},
{"change_type", UniValueType(UniValue::VSTR)},
{"includeWatching", UniValueType(UniValue::VBOOL)},
+ {"include_watching", UniValueType(UniValue::VBOOL)},
+ {"inputs", UniValueType(UniValue::VARR)},
{"lockUnspents", UniValueType(UniValue::VBOOL)},
- {"feeRate", UniValueType()}, // will be checked below
+ {"lock_unspents", UniValueType(UniValue::VBOOL)},
+ {"locktime", UniValueType(UniValue::VNUM)},
+ {"feeRate", UniValueType()}, // will be checked below,
+ {"psbt", UniValueType(UniValue::VBOOL)},
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
+ {"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
{"replaceable", UniValueType(UniValue::VBOOL)},
{"conf_target", UniValueType(UniValue::VNUM)},
{"estimate_mode", UniValueType(UniValue::VSTR)},
@@ -2991,22 +2982,24 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
coinControl.m_add_inputs = options["add_inputs"].get_bool();
}
- if (options.exists("changeAddress")) {
- CTxDestination dest = DecodeDestination(options["changeAddress"].get_str());
+ if (options.exists("changeAddress") || options.exists("change_address")) {
+ const std::string change_address_str = (options.exists("change_address") ? options["change_address"] : options["changeAddress"]).get_str();
+ CTxDestination dest = DecodeDestination(change_address_str);
if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address");
}
coinControl.destChange = dest;
}
- if (options.exists("changePosition"))
- change_position = options["changePosition"].get_int();
+ if (options.exists("changePosition") || options.exists("change_position")) {
+ change_position = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).get_int();
+ }
if (options.exists("change_type")) {
- if (options.exists("changeAddress")) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options");
+ if (options.exists("changeAddress") || options.exists("change_address")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both change address and address type options");
}
OutputType out_type;
if (!ParseOutputType(options["change_type"].get_str(), out_type)) {
@@ -3015,10 +3008,12 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
coinControl.m_change_type.emplace(out_type);
}
- coinControl.fAllowWatchOnly = ParseIncludeWatchonly(options["includeWatching"], *pwallet);
+ const UniValue include_watching_option = options.exists("include_watching") ? options["include_watching"] : options["includeWatching"];
+ coinControl.fAllowWatchOnly = ParseIncludeWatchonly(include_watching_option, *pwallet);
- if (options.exists("lockUnspents"))
- lockUnspents = options["lockUnspents"].get_bool();
+ if (options.exists("lockUnspents") || options.exists("lock_unspents")) {
+ lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
+ }
if (options.exists("feeRate"))
{
@@ -3032,8 +3027,8 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
coinControl.fOverrideFeeRate = true;
}
- if (options.exists("subtractFeeFromOutputs"))
- subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
+ if (options.exists("subtractFeeFromOutputs") || options.exists("subtract_fee_from_outputs") )
+ subtractFeeFromOutputs = (options.exists("subtract_fee_from_outputs") ? options["subtract_fee_from_outputs"] : options["subtractFeeFromOutputs"]).get_array();
if (options.exists("replaceable")) {
coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
@@ -3876,6 +3871,185 @@ static UniValue listlabels(const JSONRPCRequest& request)
return ret;
}
+static RPCHelpMan send()
+{
+ return RPCHelpMan{"send",
+ "\nSend a transaction.\n",
+ {
+ {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
+ "That is, each address can only appear once and there can only be one 'data' object.\n"
+ "For convenience, a dictionary, which holds the key-value pairs directly, is also accepted.",
+ {
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {
+ {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
+ },
+ },
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {
+ {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
+ },
+ },
+ },
+ },
+ {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
+ {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ " \"" + FeeModes("\"\n\"") + "\""},
+ {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
+ {
+ {"add_inputs", RPCArg::Type::BOOL, /* default */ "false", "If inputs are specified, automatically include more if they are not enough."},
+ {"add_to_wallet", RPCArg::Type::BOOL, /* default */ "true", "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
+ {"change_address", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"},
+ {"change_position", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
+ {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
+ {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ " \"" + FeeModes("\"\n\"") + "\""},
+ {"include_watching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n"
+ "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
+ "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
+ {"inputs", RPCArg::Type::ARR, /* default */ "empty array", "Specify inputs instead of adding them automatically. A json array of json objects",
+ {
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+ {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
+ {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"},
+ },
+ },
+ {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
+ {"lock_unspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
+ {"psbt", RPCArg::Type::BOOL, /* default */ "automatic", "Always return a PSBT, implies add_to_wallet=false."},
+ {"subtract_fee_from_outputs", RPCArg::Type::ARR, /* default */ "empty array", "A json array of integers.\n"
+ "The fee will be equally deducted from the amount of each specified output.\n"
+ "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
+ "If no outputs are specified here, the sender pays the fee.",
+ {
+ {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
+ },
+ },
+ {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
+ " Allows this transaction to be replaced by a transaction with higher fees"},
+ },
+ "options"},
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
+ {RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of the number of addresses."},
+ {RPCResult::Type::STR_HEX, "hex", "If add_to_wallet is false, the hex-encoded raw transaction with signature(s)"},
+ {RPCResult::Type::STR, "psbt", "If more signatures are needed, or if add_to_wallet is false, the base64-encoded (partially) signed transaction"}
+ }
+ },
+ RPCExamples{""
+ "\nSend with a fee rate of 1 satoshi per byte\n"
+ + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 sat/b\n" +
+ "\nCreate a transaction that should confirm the next block, with a specific input, and return result without adding to wallet or broadcasting to the network\n")
+ + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 economical '{\"add_to_wallet\": false, \"inputs\": [{\"txid\":\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\", \"vout\":1}]}'")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+ {
+ RPCTypeCheck(request.params, {
+ UniValueType(), // ARR or OBJ, checked later
+ UniValue::VNUM,
+ UniValue::VSTR,
+ UniValue::VOBJ
+ }, true
+ );
+
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ if (!wallet) return NullUniValue;
+ CWallet* const pwallet = wallet.get();
+
+ UniValue options = request.params[3];
+ if (options.exists("feeRate") || options.exists("fee_rate") || options.exists("estimate_mode") || options.exists("conf_target")) {
+ if (!request.params[1].isNull() || !request.params[2].isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Use either conf_target and estimate_mode or the options dictionary to control fee rate");
+ }
+ } else {
+ options.pushKV("conf_target", request.params[1]);
+ options.pushKV("estimate_mode", request.params[2]);
+ }
+ if (!options["conf_target"].isNull() && (options["estimate_mode"].isNull() || (options["estimate_mode"].get_str() == "unset"))) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Specify estimate_mode");
+ }
+ if (options.exists("changeAddress")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_address");
+ }
+ if (options.exists("changePosition")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_position");
+ }
+ if (options.exists("includeWatching")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Use include_watching");
+ }
+ if (options.exists("lockUnspents")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Use lock_unspents");
+ }
+ if (options.exists("subtractFeeFromOutputs")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Use subtract_fee_from_outputs");
+ }
+
+ const bool psbt_opt_in = options.exists("psbt") && options["psbt"].get_bool();
+
+ CAmount fee;
+ int change_position;
+ bool rbf = pwallet->m_signal_rbf;
+ if (options.exists("replaceable")) {
+ rbf = options["add_to_wallet"].get_bool();
+ }
+ CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], rbf);
+ CCoinControl coin_control;
+ // Automatically select coins, unless at least one is manually selected. Can
+ // be overriden by options.add_inputs.
+ coin_control.m_add_inputs = rawTx.vin.size() == 0;
+ FundTransaction(pwallet, rawTx, fee, change_position, options, coin_control);
+
+ bool add_to_wallet = true;
+ if (options.exists("add_to_wallet")) {
+ add_to_wallet = options["add_to_wallet"].get_bool();
+ }
+
+ // Make a blank psbt
+ PartiallySignedTransaction psbtx(rawTx);
+
+ // Fill transaction with out data and sign
+ bool complete = true;
+ const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_ALL, true, false);
+ if (err != TransactionError::OK) {
+ throw JSONRPCTransactionError(err);
+ }
+
+ CMutableTransaction mtx;
+ complete = FinalizeAndExtractPSBT(psbtx, mtx);
+
+ UniValue result(UniValue::VOBJ);
+
+ // Serialize the PSBT
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ ssTx << psbtx;
+ const std::string result_str = EncodeBase64(ssTx.str());
+
+ if (psbt_opt_in || !complete || !add_to_wallet) {
+ result.pushKV("psbt", result_str);
+ }
+
+ if (complete) {
+ std::string err_string;
+ std::string hex = EncodeHexTx(CTransaction(mtx));
+ CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
+ result.pushKV("txid", tx->GetHash().GetHex());
+ if (add_to_wallet && !psbt_opt_in) {
+ pwallet->CommitTransaction(tx, {}, {} /* orderForm */);
+ } else {
+ result.pushKV("hex", hex);
+ }
+ }
+ result.pushKV("complete", complete);
+
+ return result;
+ }
+ };
+}
+
UniValue sethdseed(const JSONRPCRequest& request)
{
RPCHelpMan{"sethdseed",
@@ -4016,7 +4190,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
"\nCreates and funds a transaction in the Partially Signed Transaction format.\n"
"Implements the Creator and Updater roles.\n",
{
- {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The inputs. Leave empty to add inputs automatically. See add_inputs option.",
+ {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Leave empty to add inputs automatically. See add_inputs option.",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
@@ -4233,6 +4407,7 @@ static const CRPCCommand commands[] =
{ "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
+ { "wallet", "send", &send, {"outputs","conf_target","estimate_mode","options"} },
{ "wallet", "sendmany", &sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
{ "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","avoid_reuse"} },
{ "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp
index c0755db751..225b975067 100644
--- a/src/wallet/salvage.cpp
+++ b/src/wallet/salvage.cpp
@@ -16,8 +16,20 @@ static const char *HEADER_END = "HEADER=END";
static const char *DATA_END = "DATA=END";
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
+static bool KeyFilter(const std::string& type)
+{
+ return WalletBatch::IsKeyType(type) || type == DBKeys::HDCHAIN;
+}
+
bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
+ DatabaseOptions options;
+ DatabaseStatus status;
+ options.require_existing = true;
+ options.verify = false;
+ std::unique_ptr<WalletDatabase> database = MakeDatabase(file_path, options, status, error);
+ if (!database) return false;
+
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename);
@@ -118,7 +130,7 @@ bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::v
}
DbTxn* ptxn = env->TxnBegin();
- CWallet dummyWallet(nullptr, WalletLocation(), CreateDummyWalletDatabase());
+ CWallet dummyWallet(nullptr, "", CreateDummyWalletDatabase());
for (KeyValPair& row : salvagedData)
{
/* Filter for only private key type KV pairs to be added to the salvaged wallet */
@@ -129,9 +141,9 @@ bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::v
{
// Required in LoadKeyMetadata():
LOCK(dummyWallet.cs_wallet);
- fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, strType, strErr);
+ fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, strType, strErr, KeyFilter);
}
- if (!WalletBatch::IsKeyType(strType) && strType != DBKeys::HDCHAIN) {
+ if (!KeyFilter(strType)) {
continue;
}
if (!fReadOK)
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index a96d971734..14fb1fa89f 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -535,7 +535,7 @@ private:
//! keeps track of whether Unlock has run a thorough check before
bool m_decryption_thoroughly_checked = false;
- bool AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey);
+ bool AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
KeyMap GetKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 1deedede4c..f38ccba384 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -29,7 +29,7 @@ typedef std::set<CInputCoin> CoinSet;
static std::vector<COutput> vCoins;
static NodeContext testNode;
static auto testChain = interfaces::MakeChain(testNode);
-static CWallet testWallet(testChain.get(), WalletLocation(), CreateDummyWalletDatabase());
+static CWallet testWallet(testChain.get(), "", CreateDummyWalletDatabase());
static CAmount balance = 0;
CoinEligibilityFilter filter_standard(1, 6, 0);
@@ -283,7 +283,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
// Make sure that can use BnB when there are preset inputs
empty_wallet();
{
- std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), "", CreateMockWalletDatabase());
bool firstRun;
wallet->LoadWallet(firstRun);
wallet->SetupLegacyScriptPubKeyMan();
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index c23dea1338..c80310045a 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -10,7 +10,7 @@
InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
{
- m_wallet_client = MakeWalletClient(*m_chain, *Assert(m_node.args), {});
+ m_wallet_client = MakeWalletClient(*m_chain, *Assert(m_node.args));
std::string sep;
sep += fs::path::preferred_separator;
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
index e416f16044..d5aed99d99 100644
--- a/src/wallet/test/ismine_tests.cpp
+++ b/src/wallet/test/ismine_tests.cpp
@@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK compressed
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
@@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK uncompressed
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH compressed
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
@@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH uncompressed
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
@@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2SH (invalid)
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2WSH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH compressed
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH uncompressed
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// scriptPubKey multisig
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH multisig
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -283,7 +283,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with compressed keys
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -309,7 +309,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with uncompressed key
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -335,7 +335,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig wrapped in P2SH
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -362,7 +362,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// OP_RETURN
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -376,7 +376,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unspendable
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -390,7 +390,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unknown
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Nonstandard
{
- CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
diff --git a/src/wallet/test/scriptpubkeyman_tests.cpp b/src/wallet/test/scriptpubkeyman_tests.cpp
index 4f12079768..f7c1337b0d 100644
--- a/src/wallet/test/scriptpubkeyman_tests.cpp
+++ b/src/wallet/test/scriptpubkeyman_tests.cpp
@@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(CanProvide)
// Set up wallet and keyman variables.
NodeContext node;
std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node);
- CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
LegacyScriptPubKeyMan& keyman = *wallet.GetOrCreateLegacyScriptPubKeyMan();
// Make a 1 of 2 multisig script
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 9241470745..4d6f427618 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -6,7 +6,7 @@
WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
: TestingSetup(chainName),
- m_wallet(m_chain.get(), WalletLocation(), CreateMockWalletDatabase())
+ m_wallet(m_chain.get(), "", CreateMockWalletDatabase())
{
bool fFirstRun;
m_wallet.LoadWallet(fFirstRun);
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index 12ad13b49b..ba8a5ff1f3 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -21,7 +21,7 @@ struct WalletTestingSetup : public TestingSetup {
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(m_node);
- std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_chain, *Assert(m_node.args), {});
+ std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_chain, *Assert(m_node.args));
CWallet m_wallet;
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
};
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c46e90d64b..6b98482f98 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -37,9 +37,12 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain)
{
+ DatabaseOptions options;
+ DatabaseStatus status;
bilingual_str error;
std::vector<bilingual_str> warnings;
- auto wallet = CWallet::CreateWalletFromFile(chain, WalletLocation(""), error, warnings);
+ auto database = MakeWalletDatabase("", options, status, error);
+ auto wallet = CWallet::Create(chain, "", std::move(database), options.create_flags, error, warnings);
wallet->postInitProcess();
return wallet;
}
@@ -85,7 +88,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions fails to read an unknown start block.
{
- CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -104,7 +107,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions picks up transactions in both the old
// and new block files.
{
- CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -130,7 +133,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions only picks transactions in the new block
// file.
{
- CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -155,7 +158,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions scans no blocks.
{
- CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -194,7 +197,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
// before the missing block, and success for a key whose creation time is
// after.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(newTip->nHeight, newTip->GetBlockHash()));
AddWallet(wallet);
@@ -229,7 +232,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
"downloading and rescanning the relevant blocks (see -reindex and -rescan "
"options).\"}},{\"success\":true}]",
0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
- RemoveWallet(wallet);
+ RemoveWallet(wallet, nullopt);
}
}
@@ -259,7 +262,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Import key into wallet and call dumpwallet to create backup file.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
{
auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
@@ -275,13 +278,13 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
request.params.push_back(backup_file);
::dumpwallet().HandleRequest(request);
- RemoveWallet(wallet);
+ RemoveWallet(wallet, nullopt);
}
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
// were scanned, and no prior blocks were scanned.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
LOCK(wallet->cs_wallet);
wallet->SetupLegacyScriptPubKeyMan();
@@ -292,7 +295,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
AddWallet(wallet);
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
::importwallet().HandleRequest(request);
- RemoveWallet(wallet);
+ RemoveWallet(wallet, nullopt);
BOOST_CHECK_EQUAL(wallet->mapWallet.size(), 3U);
BOOST_CHECK_EQUAL(m_coinbase_txns.size(), 103U);
@@ -317,7 +320,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
NodeContext node;
auto chain = interfaces::MakeChain(node);
- CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
CWalletTx wtx(&wallet, m_coinbase_txns.back());
@@ -492,7 +495,7 @@ public:
ListCoinsTestingSetup()
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), CreateMockWalletDatabase());
+ wallet = MakeUnique<CWallet>(m_chain.get(), "", CreateMockWalletDatabase());
{
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -610,7 +613,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
NodeContext node;
auto chain = interfaces::MakeChain(node);
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 34a5b7b8d2..73e11a5b52 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -33,6 +33,8 @@
#include <wallet/coincontrol.h>
#include <wallet/fees.h>
+#include <univalue.h>
+
#include <algorithm>
#include <assert.h>
@@ -54,6 +56,42 @@ static RecursiveMutex cs_wallets;
static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets);
static std::list<LoadWalletFn> g_load_wallet_fns GUARDED_BY(cs_wallets);
+bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
+{
+ util::SettingsValue setting_value = chain.getRwSetting("wallet");
+ if (!setting_value.isArray()) setting_value.setArray();
+ for (const util::SettingsValue& value : setting_value.getValues()) {
+ if (value.isStr() && value.get_str() == wallet_name) return true;
+ }
+ setting_value.push_back(wallet_name);
+ return chain.updateRwSetting("wallet", setting_value);
+}
+
+bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
+{
+ util::SettingsValue setting_value = chain.getRwSetting("wallet");
+ if (!setting_value.isArray()) return true;
+ util::SettingsValue new_value(util::SettingsValue::VARR);
+ for (const util::SettingsValue& value : setting_value.getValues()) {
+ if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value);
+ }
+ if (new_value.size() == setting_value.size()) return true;
+ return chain.updateRwSetting("wallet", new_value);
+}
+
+static void UpdateWalletSetting(interfaces::Chain& chain,
+ const std::string& wallet_name,
+ Optional<bool> load_on_startup,
+ std::vector<bilingual_str>& warnings)
+{
+ if (load_on_startup == nullopt) return;
+ if (load_on_startup.get() && !AddWalletSetting(chain, wallet_name)) {
+ warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
+ } else if (!load_on_startup.get() && !RemoveWalletSetting(chain, wallet_name)) {
+ warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
+ }
+}
+
bool AddWallet(const std::shared_ptr<CWallet>& wallet)
{
LOCK(cs_wallets);
@@ -65,18 +103,32 @@ bool AddWallet(const std::shared_ptr<CWallet>& wallet)
return true;
}
-bool RemoveWallet(const std::shared_ptr<CWallet>& wallet)
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start, std::vector<bilingual_str>& warnings)
{
assert(wallet);
+
+ interfaces::Chain& chain = wallet->chain();
+ std::string name = wallet->GetName();
+
// Unregister with the validation interface which also drops shared ponters.
wallet->m_chain_notifications_handler.reset();
LOCK(cs_wallets);
std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
if (i == vpwallets.end()) return false;
vpwallets.erase(i);
+
+ // Write the wallet setting
+ UpdateWalletSetting(chain, name, load_on_start, warnings);
+
return true;
}
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start)
+{
+ std::vector<bilingual_str> warnings;
+ return RemoveWallet(wallet, load_on_start, warnings);
+}
+
std::vector<std::shared_ptr<CWallet>> GetWallets()
{
LOCK(cs_wallets);
@@ -148,43 +200,54 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
}
namespace {
-std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings)
+std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
try {
- if (!CWallet::Verify(chain, location, error, warnings)) {
+ std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
+ if (!database) {
error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
return nullptr;
}
- std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings);
+ std::shared_ptr<CWallet> wallet = CWallet::Create(chain, name, std::move(database), options.create_flags, error, warnings);
if (!wallet) {
error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error;
+ status = DatabaseStatus::FAILED_LOAD;
return nullptr;
}
AddWallet(wallet);
wallet->postInitProcess();
+
+ // Write the wallet setting
+ UpdateWalletSetting(chain, name, load_on_start, warnings);
+
return wallet;
} catch (const std::runtime_error& e) {
error = Untranslated(e.what());
+ status = DatabaseStatus::FAILED_LOAD;
return nullptr;
}
}
} // namespace
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings)
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
- auto result = WITH_LOCK(g_loading_wallet_mutex, return g_loading_wallet_set.insert(location.GetName()));
+ auto result = WITH_LOCK(g_loading_wallet_mutex, return g_loading_wallet_set.insert(name));
if (!result.second) {
error = Untranslated("Wallet already being loading.");
+ status = DatabaseStatus::FAILED_LOAD;
return nullptr;
}
- auto wallet = LoadWalletInternal(chain, location, error, warnings);
+ auto wallet = LoadWalletInternal(chain, name, load_on_start, options, status, error, warnings);
WITH_LOCK(g_loading_wallet_mutex, g_loading_wallet_set.erase(result.first));
return wallet;
}
-WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result)
+std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
+ uint64_t wallet_creation_flags = options.create_flags;
+ const SecureString& passphrase = options.create_passphrase;
+
// Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET);
@@ -193,43 +256,42 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET;
}
- // Check the wallet file location
- WalletLocation location(name);
- if (location.Exists()) {
- error = strprintf(Untranslated("Wallet %s already exists."), location.GetName());
- return WalletCreationStatus::CREATION_FAILED;
- }
-
// Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
- if (!CWallet::Verify(chain, location, error, warnings)) {
+ std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
+ if (!database) {
error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
- return WalletCreationStatus::CREATION_FAILED;
+ status = DatabaseStatus::FAILED_VERIFY;
+ return nullptr;
}
// Do not allow a passphrase when private keys are disabled
if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
- return WalletCreationStatus::CREATION_FAILED;
+ status = DatabaseStatus::FAILED_CREATE;
+ return nullptr;
}
// Make the wallet
- std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings, wallet_creation_flags);
+ std::shared_ptr<CWallet> wallet = CWallet::Create(chain, name, std::move(database), wallet_creation_flags, error, warnings);
if (!wallet) {
error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;
- return WalletCreationStatus::CREATION_FAILED;
+ status = DatabaseStatus::FAILED_CREATE;
+ return nullptr;
}
// Encrypt the wallet
if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (!wallet->EncryptWallet(passphrase)) {
error = Untranslated("Error: Wallet created but failed to encrypt.");
- return WalletCreationStatus::ENCRYPTION_FAILED;
+ status = DatabaseStatus::FAILED_ENCRYPT;
+ return nullptr;
}
if (!create_blank) {
// Unlock the wallet
if (!wallet->Unlock(passphrase)) {
error = Untranslated("Error: Wallet was encrypted but could not be unlocked");
- return WalletCreationStatus::ENCRYPTION_FAILED;
+ status = DatabaseStatus::FAILED_ENCRYPT;
+ return nullptr;
}
// Set a seed for the wallet
@@ -241,7 +303,8 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
error = Untranslated("Unable to generate initial keys");
- return WalletCreationStatus::CREATION_FAILED;
+ status = DatabaseStatus::FAILED_CREATE;
+ return nullptr;
}
}
}
@@ -253,8 +316,12 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
}
AddWallet(wallet);
wallet->postInitProcess();
- result = wallet;
- return WalletCreationStatus::SUCCESS;
+
+ // Write the wallet settings
+ UpdateWalletSetting(chain, name, load_on_start, warnings);
+
+ status = DatabaseStatus::SUCCESS;
+ return wallet;
}
const uint256 CWalletTx::ABANDON_HASH(UINT256_ONE());
@@ -2286,6 +2353,7 @@ std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const
const CTxOut& CWallet::FindNonChangeParentOutput(const CTransaction& tx, int output) const
{
+ AssertLockHeld(cs_wallet);
const CTransaction* ptx = &tx;
int n = output;
while (IsChange(ptx->vout[n]) && ptx->vin.size() > 0) {
@@ -3175,25 +3243,6 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
return DBErrors::LOAD_OK;
}
-DBErrors CWallet::ZapWalletTx(std::list<CWalletTx>& vWtx)
-{
- DBErrors nZapWalletTxRet = WalletBatch(*database,"cr+").ZapWalletTx(vWtx);
- if (nZapWalletTxRet == DBErrors::NEED_REWRITE)
- {
- if (database->Rewrite("\x04pool"))
- {
- for (const auto& spk_man_pair : m_spk_managers) {
- spk_man_pair.second->RewriteDB();
- }
- }
- }
-
- if (nZapWalletTxRet != DBErrors::LOAD_OK)
- return nZapWalletTxRet;
-
- return DBErrors::LOAD_OK;
-}
-
bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
{
bool fUpdated = false;
@@ -3223,6 +3272,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
bool CWallet::DelAddressBook(const CTxDestination& address)
{
bool is_mine;
+ WalletBatch batch(*database);
{
LOCK(cs_wallet);
// If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
@@ -3236,7 +3286,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
std::string strAddress = EncodeDestination(address);
for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
{
- WalletBatch(*database).EraseDestData(strAddress, item.first);
+ batch.EraseDestData(strAddress, item.first);
}
m_address_book.erase(address);
is_mine = IsMine(address) != ISMINE_NO;
@@ -3244,8 +3294,8 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED);
- WalletBatch(*database).ErasePurpose(EncodeDestination(address));
- return WalletBatch(*database).EraseName(EncodeDestination(address));
+ batch.ErasePurpose(EncodeDestination(address));
+ return batch.EraseName(EncodeDestination(address));
}
size_t CWallet::KeypoolCountExternalKeys() const
@@ -3729,7 +3779,7 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
return values;
}
-bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error_string, std::vector<bilingual_str>& warnings)
+std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error_string)
{
// Do some checking on wallet path. It should be either a:
//
@@ -3737,54 +3787,25 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
// 2. Path to an existing directory.
// 3. Path to a symlink to a directory.
// 4. For backwards compatibility, the name of a data file in -walletdir.
- LOCK(cs_wallets);
- const fs::path& wallet_path = location.GetPath();
+ const fs::path& wallet_path = fs::absolute(name, GetWalletDir());
fs::file_type path_type = fs::symlink_status(wallet_path).type();
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
- (path_type == fs::regular_file && fs::path(location.GetName()).filename() == location.GetName()))) {
+ (path_type == fs::regular_file && fs::path(name).filename() == name))) {
error_string = Untranslated(strprintf(
"Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
"database/log.?????????? files can be stored, a location where such a directory could be created, "
"or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
- location.GetName(), GetWalletDir()));
- return false;
- }
-
- // Make sure that the wallet path doesn't clash with an existing wallet path
- if (IsWalletLoaded(wallet_path)) {
- error_string = Untranslated(strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName()));
- return false;
- }
-
- // Keep same database environment instance across Verify/Recover calls below.
- std::unique_ptr<WalletDatabase> database = CreateWalletDatabase(wallet_path);
-
- try {
- return database->Verify(error_string);
- } catch (const fs::filesystem_error& e) {
- error_string = Untranslated(strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e)));
- return false;
+ name, GetWalletDir()));
+ status = DatabaseStatus::FAILED_BAD_PATH;
+ return nullptr;
}
+ return MakeDatabase(wallet_path, options, status, error_string);
}
-std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags)
+std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
- const std::string walletFile = WalletDataFilePath(location.GetPath()).string();
-
- // needed to restore wallet transaction meta data after -zapwallettxes
- std::list<CWalletTx> vWtx;
-
- if (gArgs.GetBoolArg("-zapwallettxes", false)) {
- chain.initMessage(_("Zapping all transactions from wallet...").translated);
-
- std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(&chain, location, CreateWalletDatabase(location.GetPath()));
- DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
- if (nZapWalletRet != DBErrors::LOAD_OK) {
- error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
- return nullptr;
- }
- }
+ const std::string& walletFile = database->Filename();
chain.initMessage(_("Loading wallet...").translated);
@@ -3792,7 +3813,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
bool fFirstRun = true;
// TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared.
- std::shared_ptr<CWallet> walletInstance(new CWallet(&chain, location, CreateWalletDatabase(location.GetPath())), ReleaseWallet);
+ std::shared_ptr<CWallet> walletInstance(new CWallet(&chain, name, std::move(database)), ReleaseWallet);
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK) {
if (nLoadWalletRet == DBErrors::CORRUPT) {
@@ -4062,30 +4083,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
}
walletInstance->chainStateFlushed(chain.getTipLocator());
walletInstance->database->IncrementUpdateCounter();
-
- // Restore wallet transaction metadata after -zapwallettxes=1
- if (gArgs.GetBoolArg("-zapwallettxes", false) && gArgs.GetArg("-zapwallettxes", "1") != "2")
- {
- WalletBatch batch(*walletInstance->database);
-
- for (const CWalletTx& wtxOld : vWtx)
- {
- uint256 hash = wtxOld.GetHash();
- std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);
- if (mi != walletInstance->mapWallet.end())
- {
- const CWalletTx* copyFrom = &wtxOld;
- CWalletTx* copyTo = &mi->second;
- copyTo->mapValue = copyFrom->mapValue;
- copyTo->vOrderForm = copyFrom->vOrderForm;
- copyTo->nTimeReceived = copyFrom->nTimeReceived;
- copyTo->nTimeSmart = copyFrom->nTimeSmart;
- copyTo->fFromMe = copyFrom->fFromMe;
- copyTo->nOrderPos = copyFrom->nOrderPos;
- batch.WriteTx(*copyTo);
- }
- }
- }
}
{
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index ebd2e91492..c54480612a 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -50,19 +50,14 @@ struct bilingual_str;
void UnloadWallet(std::shared_ptr<CWallet>&& wallet);
bool AddWallet(const std::shared_ptr<CWallet>& wallet);
-bool RemoveWallet(const std::shared_ptr<CWallet>& wallet);
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start, std::vector<bilingual_str>& warnings);
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start);
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings);
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
+std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
std::unique_ptr<interfaces::Handler> HandleLoadWallet(LoadWalletFn load_wallet);
-
-enum class WalletCreationStatus {
- SUCCESS,
- CREATION_FAILED,
- ENCRYPTION_FAILED
-};
-
-WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result);
+std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
//! -paytxfee default
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
@@ -699,8 +694,8 @@ private:
/** Interface for accessing chain state. */
interfaces::Chain* m_chain;
- /** Wallet location which includes wallet name (see WalletLocation). */
- WalletLocation m_location;
+ /** Wallet name: relative directory name or "" for default wallet. */
+ std::string m_name;
/** Internal database handle. */
std::unique_ptr<WalletDatabase> database;
@@ -754,20 +749,18 @@ public:
bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet,
const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- const WalletLocation& GetLocation() const { return m_location; }
-
/** Get a name for this wallet for logging/debugging purposes.
*/
- const std::string& GetName() const { return m_location.GetName(); }
+ const std::string& GetName() const { return m_name; }
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID = 0;
/** Construct wallet with specified name and database implementation. */
- CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database)
+ CWallet(interfaces::Chain* chain, const std::string& name, std::unique_ptr<WalletDatabase> database)
: m_chain(chain),
- m_location(location),
+ m_name(name),
database(std::move(database))
{
}
@@ -1075,7 +1068,6 @@ public:
void chainStateFlushed(const CBlockLocator& loc) override;
DBErrors LoadWallet(bool& fFirstRunRet);
- DBErrors ZapWalletTx(std::list<CWalletTx>& vWtx);
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
@@ -1153,11 +1145,8 @@ public:
/** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
- //! Verify wallet naming and perform salvage on the wallet if required
- static bool Verify(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error_string, std::vector<bilingual_str>& warnings);
-
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
- static std::shared_ptr<CWallet> CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags = 0);
+ static std::shared_ptr<CWallet> Create(interfaces::Chain& chain, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings);
/**
* Wallet post-init setup
@@ -1179,7 +1168,7 @@ public:
* Obviously holding cs_main/cs_wallet when going into this call may cause
* deadlock
*/
- void BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(cs_main, cs_wallet);
+ void BlockUntilSyncedToCurrentChain() const EXCLUSIVE_LOCKS_REQUIRED(!::cs_main, !cs_wallet);
/** set a single wallet flag */
void SetWalletFlag(uint64_t flags);
@@ -1285,7 +1274,7 @@ public:
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal);
//! Create new DescriptorScriptPubKeyMans and add them to the wallet
- void SetupDescriptorScriptPubKeyMans();
+ void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet
DescriptorScriptPubKeyMan* GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const;
@@ -1340,4 +1329,11 @@ public:
// be IsAllFromMe).
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig = false);
+
+//! Add wallet name to persistent configuration so it will be loaded on startup.
+bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);
+
+//! Remove wallet name from persistent configuration so it will not be loaded on startup.
+bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);
+
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index fa6814d0d3..5bf21eb91f 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -13,6 +13,8 @@
#include <util/bip32.h>
#include <util/system.h>
#include <util/time.h>
+#include <util/translation.h>
+#include <wallet/bdb.h>
#include <wallet/wallet.h>
#include <atomic>
@@ -263,13 +265,17 @@ public:
static bool
ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
- CWalletScanState &wss, std::string& strType, std::string& strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
+ CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
try {
// Unserialize
// Taking advantage of the fact that pair serialization
// is just the two items serialized one after the other
ssKey >> strType;
+ // If we have a filter, check if this matches the filter
+ if (filter_fn && !filter_fn(strType)) {
+ return true;
+ }
if (strType == DBKeys::NAME) {
std::string strAddress;
ssKey >> strAddress;
@@ -668,11 +674,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
return true;
}
-bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr)
+bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn)
{
CWalletScanState dummy_wss;
LOCK(pwallet->cs_wallet);
- return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr);
+ return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr, filter_fn);
}
bool WalletBatch::IsKeyType(const std::string& strType)
@@ -926,23 +932,6 @@ DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<u
return DBErrors::LOAD_OK;
}
-DBErrors WalletBatch::ZapWalletTx(std::list<CWalletTx>& vWtx)
-{
- // build list of wallet TXs
- std::vector<uint256> vTxHash;
- DBErrors err = FindWalletTx(vTxHash, vWtx);
- if (err != DBErrors::LOAD_OK)
- return err;
-
- // erase each wallet TX
- for (const uint256& hash : vTxHash) {
- if (!EraseTx(hash))
- return DBErrors::CORRUPT;
- }
-
- return DBErrors::LOAD_OK;
-}
-
void MaybeCompactWalletDB()
{
static std::atomic<bool> fOneThread(false);
@@ -1006,16 +995,41 @@ bool WalletBatch::TxnAbort()
return m_batch->TxnAbort();
}
-bool IsWalletLoaded(const fs::path& wallet_path)
+std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
{
- return IsBDBWalletLoaded(wallet_path);
-}
+ bool exists;
+ try {
+ exists = fs::symlink_status(path).type() != fs::file_not_found;
+ } catch (const fs::filesystem_error& e) {
+ error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e)));
+ status = DatabaseStatus::FAILED_BAD_PATH;
+ return nullptr;
+ }
-/** Return object for accessing database at specified path. */
-std::unique_ptr<WalletDatabase> CreateWalletDatabase(const fs::path& path)
-{
- std::string filename;
- return MakeUnique<BerkeleyDatabase>(GetWalletEnv(path, filename), std::move(filename));
+ Optional<DatabaseFormat> format;
+ if (exists) {
+ if (ExistsBerkeleyDatabase(path)) {
+ format = DatabaseFormat::BERKELEY;
+ }
+ } else if (options.require_existing) {
+ error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
+ status = DatabaseStatus::FAILED_NOT_FOUND;
+ return nullptr;
+ }
+
+ if (!format && options.require_existing) {
+ error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string()));
+ status = DatabaseStatus::FAILED_BAD_FORMAT;
+ return nullptr;
+ }
+
+ if (format && options.require_create) {
+ error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string()));
+ status = DatabaseStatus::FAILED_ALREADY_EXISTS;
+ return nullptr;
+ }
+
+ return MakeBerkeleyDatabase(path, options, status, error);
}
/** Return object for accessing dummy database with no read/write capabilities. */
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 64d60b1f44..eda810ed8a 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -257,7 +257,6 @@ public:
DBErrors LoadWallet(CWallet* pwallet);
DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx);
- DBErrors ZapWalletTx(std::list<CWalletTx>& vWtx);
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
/* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
static bool IsKeyType(const std::string& strType);
@@ -280,14 +279,11 @@ private:
//! Compacts BDB state so that wallet.dat is self-contained (if there are changes)
void MaybeCompactWalletDB();
-//! Unserialize a given Key-Value pair and load it into the wallet
-bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr);
-
-/** Return whether a wallet database is currently loaded. */
-bool IsWalletLoaded(const fs::path& wallet_path);
+//! Callback for filtering key types to deserialize in ReadKeyValue
+using KeyFilterFn = std::function<bool(const std::string&)>;
-/** Return object for accessing database at specified path. */
-std::unique_ptr<WalletDatabase> CreateWalletDatabase(const fs::path& path);
+//! Unserialize a given Key-Value pair and load it into the wallet
+bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr);
/** Return object for accessing dummy database with no read/write capabilities. */
std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase();
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index 9b51461843..4452840eb1 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -21,21 +21,9 @@ static void WalletToolReleaseWallet(CWallet* wallet)
delete wallet;
}
-static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path)
+static void WalletCreate(CWallet* wallet_instance)
{
- if (fs::exists(path)) {
- tfm::format(std::cerr, "Error: File exists already\n");
- return nullptr;
- }
- // dummy chain interface
- std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), CreateWalletDatabase(path)), WalletToolReleaseWallet);
LOCK(wallet_instance->cs_wallet);
- bool first_run = true;
- DBErrors load_wallet_ret = wallet_instance->LoadWallet(first_run);
- if (load_wallet_ret != DBErrors::LOAD_OK) {
- tfm::format(std::cerr, "Error creating %s", name);
- return nullptr;
- }
wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
@@ -46,18 +34,26 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
tfm::format(std::cout, "Topping up keypool...\n");
wallet_instance->TopUpKeyPool();
- return wallet_instance;
}
-static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path)
+static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, bool create)
{
- if (!fs::exists(path)) {
- tfm::format(std::cerr, "Error: Wallet files does not exist\n");
+ DatabaseOptions options;
+ DatabaseStatus status;
+ if (create) {
+ options.require_create = true;
+ } else {
+ options.require_existing = true;
+ }
+ bilingual_str error;
+ std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
+ if (!database) {
+ tfm::format(std::cerr, "%s\n", error.original);
return nullptr;
}
// dummy chain interface
- std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), CreateWalletDatabase(path)), WalletToolReleaseWallet);
+ std::shared_ptr<CWallet> wallet_instance{new CWallet(nullptr /* chain */, name, std::move(database)), WalletToolReleaseWallet};
DBErrors load_wallet_ret;
try {
bool first_run;
@@ -89,6 +85,8 @@ static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::pa
}
}
+ if (create) WalletCreate(wallet_instance.get());
+
return wallet_instance;
}
@@ -109,19 +107,14 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
fs::path path = fs::absolute(name, GetWalletDir());
if (command == "create") {
- std::shared_ptr<CWallet> wallet_instance = CreateWallet(name, path);
+ std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ true);
if (wallet_instance) {
WalletShowInfo(wallet_instance.get());
wallet_instance->Close();
}
} else if (command == "info" || command == "salvage") {
- if (!fs::exists(path)) {
- tfm::format(std::cerr, "Error: no wallet file at %s\n", name);
- return false;
- }
-
if (command == "info") {
- std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
+ std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ false);
if (!wallet_instance) return false;
WalletShowInfo(wallet_instance.get());
wallet_instance->Close();
diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h
index 8ee3355f02..d0b8d6812a 100644
--- a/src/wallet/wallettool.h
+++ b/src/wallet/wallettool.h
@@ -9,8 +9,6 @@
namespace WalletTool {
-std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path);
-std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path);
void WalletShowInfo(CWallet* wallet_instance);
bool ExecuteWalletToolFunc(const std::string& command, const std::string& file);
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index 8bac0608a9..e4c72aed98 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -29,7 +29,7 @@ fs::path GetWalletDir()
return path;
}
-static bool IsBerkeleyBtree(const fs::path& path)
+bool IsBerkeleyBtree(const fs::path& path)
{
if (!fs::exists(path)) return false;
@@ -91,19 +91,3 @@ std::vector<fs::path> ListWalletDir()
return paths;
}
-
-WalletLocation::WalletLocation(const std::string& name)
- : m_name(name)
- , m_path(fs::absolute(name, GetWalletDir()))
-{
-}
-
-bool WalletLocation::Exists() const
-{
- fs::path path = m_path;
- // For the default wallet, check specifically for the wallet.dat file
- if (m_name.empty()) {
- path = fs::absolute("wallet.dat", m_path);
- }
- return fs::symlink_status(path).type() != fs::file_not_found;
-}
diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h
index a4e4fda8a1..afdcb2e18a 100644
--- a/src/wallet/walletutil.h
+++ b/src/wallet/walletutil.h
@@ -67,26 +67,6 @@ fs::path GetWalletDir();
//! Get wallets in wallet directory.
std::vector<fs::path> ListWalletDir();
-//! The WalletLocation class provides wallet information.
-class WalletLocation final
-{
- std::string m_name;
- fs::path m_path;
-
-public:
- explicit WalletLocation() {}
- explicit WalletLocation(const std::string& name);
-
- //! Get wallet name.
- const std::string& GetName() const { return m_name; }
-
- //! Get wallet absolute path.
- const fs::path& GetPath() const { return m_path; }
-
- //! Return whether the wallet exists.
- bool Exists() const;
-};
-
/** Descriptor with some wallet metadata */
class WalletDescriptor
{
diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp
index aae760adde..0d0428f3c0 100644
--- a/src/zmq/zmqabstractnotifier.cpp
+++ b/src/zmq/zmqabstractnotifier.cpp
@@ -4,6 +4,8 @@
#include <zmq/zmqabstractnotifier.h>
+#include <cassert>
+
const int CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM;
CZMQAbstractNotifier::~CZMQAbstractNotifier()
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index 887dde7b27..34d7e5ef03 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -5,12 +5,16 @@
#ifndef BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
-#include <zmq/zmqconfig.h>
+#include <util/memory.h>
+
+#include <memory>
+#include <string>
class CBlockIndex;
+class CTransaction;
class CZMQAbstractNotifier;
-typedef CZMQAbstractNotifier* (*CZMQNotifierFactory)();
+using CZMQNotifierFactory = std::unique_ptr<CZMQAbstractNotifier> (*)();
class CZMQAbstractNotifier
{
@@ -21,9 +25,9 @@ public:
virtual ~CZMQAbstractNotifier();
template <typename T>
- static CZMQAbstractNotifier* Create()
+ static std::unique_ptr<CZMQAbstractNotifier> Create()
{
- return new T();
+ return MakeUnique<T>();
}
std::string GetType() const { return type; }
diff --git a/src/zmq/zmqconfig.h b/src/zmq/zmqconfig.h
deleted file mode 100644
index 5f0036206d..0000000000
--- a/src/zmq/zmqconfig.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2014-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.
-
-#ifndef BITCOIN_ZMQ_ZMQCONFIG_H
-#define BITCOIN_ZMQ_ZMQCONFIG_H
-
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
-#include <stdarg.h>
-
-#if ENABLE_ZMQ
-#include <zmq.h>
-#endif
-
-#include <primitives/transaction.h>
-
-void zmqError(const char *str);
-
-#endif // BITCOIN_ZMQ_ZMQCONFIG_H
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index d55b106e04..a22772baed 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -4,15 +4,13 @@
#include <zmq/zmqnotificationinterface.h>
#include <zmq/zmqpublishnotifier.h>
+#include <zmq/zmqutil.h>
+
+#include <zmq.h>
#include <validation.h>
#include <util/system.h>
-void zmqError(const char *str)
-{
- LogPrint(BCLog::ZMQ, "zmq: Error: %s, errno=%s\n", str, zmq_strerror(errno));
-}
-
CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(nullptr)
{
}
@@ -20,61 +18,52 @@ CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(nullptr)
CZMQNotificationInterface::~CZMQNotificationInterface()
{
Shutdown();
-
- for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i)
- {
- delete *i;
- }
}
std::list<const CZMQAbstractNotifier*> CZMQNotificationInterface::GetActiveNotifiers() const
{
std::list<const CZMQAbstractNotifier*> result;
- for (const auto* n : notifiers) {
- result.push_back(n);
+ for (const auto& n : notifiers) {
+ result.push_back(n.get());
}
return result;
}
CZMQNotificationInterface* CZMQNotificationInterface::Create()
{
- CZMQNotificationInterface* notificationInterface = nullptr;
std::map<std::string, CZMQNotifierFactory> factories;
- std::list<CZMQAbstractNotifier*> notifiers;
-
factories["pubhashblock"] = CZMQAbstractNotifier::Create<CZMQPublishHashBlockNotifier>;
factories["pubhashtx"] = CZMQAbstractNotifier::Create<CZMQPublishHashTransactionNotifier>;
factories["pubrawblock"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;
factories["pubrawtx"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
+ std::list<std::unique_ptr<CZMQAbstractNotifier>> notifiers;
for (const auto& entry : factories)
{
std::string arg("-zmq" + entry.first);
if (gArgs.IsArgSet(arg))
{
- CZMQNotifierFactory factory = entry.second;
- std::string address = gArgs.GetArg(arg, "");
- CZMQAbstractNotifier *notifier = factory();
+ const auto& factory = entry.second;
+ const std::string address = gArgs.GetArg(arg, "");
+ std::unique_ptr<CZMQAbstractNotifier> notifier = factory();
notifier->SetType(entry.first);
notifier->SetAddress(address);
notifier->SetOutboundMessageHighWaterMark(static_cast<int>(gArgs.GetArg(arg + "hwm", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM)));
- notifiers.push_back(notifier);
+ notifiers.push_back(std::move(notifier));
}
}
if (!notifiers.empty())
{
- notificationInterface = new CZMQNotificationInterface();
- notificationInterface->notifiers = notifiers;
+ std::unique_ptr<CZMQNotificationInterface> notificationInterface(new CZMQNotificationInterface());
+ notificationInterface->notifiers = std::move(notifiers);
- if (!notificationInterface->Initialize())
- {
- delete notificationInterface;
- notificationInterface = nullptr;
+ if (notificationInterface->Initialize()) {
+ return notificationInterface.release();
}
}
- return notificationInterface;
+ return nullptr;
}
// Called at startup to conditionally set up ZMQ socket(s)
@@ -95,26 +84,15 @@ bool CZMQNotificationInterface::Initialize()
return false;
}
- std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin();
- for (; i!=notifiers.end(); ++i)
- {
- CZMQAbstractNotifier *notifier = *i;
- if (notifier->Initialize(pcontext))
- {
+ for (auto& notifier : notifiers) {
+ if (notifier->Initialize(pcontext)) {
LogPrint(BCLog::ZMQ, "zmq: Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress());
- }
- else
- {
+ } else {
LogPrint(BCLog::ZMQ, "zmq: Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress());
- break;
+ return false;
}
}
- if (i!=notifiers.end())
- {
- return false;
- }
-
return true;
}
@@ -124,9 +102,7 @@ void CZMQNotificationInterface::Shutdown()
LogPrint(BCLog::ZMQ, "zmq: Shutdown notification interface\n");
if (pcontext)
{
- for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i)
- {
- CZMQAbstractNotifier *notifier = *i;
+ for (auto& notifier : notifiers) {
LogPrint(BCLog::ZMQ, "zmq: Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress());
notifier->Shutdown();
}
@@ -136,45 +112,43 @@ void CZMQNotificationInterface::Shutdown()
}
}
-void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
-{
- if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones
- return;
+namespace {
- for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
- {
- CZMQAbstractNotifier *notifier = *i;
- if (notifier->NotifyBlock(pindexNew))
- {
- i++;
- }
- else
- {
+template <typename Function>
+void TryForEachAndRemoveFailed(std::list<std::unique_ptr<CZMQAbstractNotifier>>& notifiers, const Function& func)
+{
+ for (auto i = notifiers.begin(); i != notifiers.end(); ) {
+ CZMQAbstractNotifier* notifier = i->get();
+ if (func(notifier)) {
+ ++i;
+ } else {
notifier->Shutdown();
i = notifiers.erase(i);
}
}
}
+} // anonymous namespace
+
+void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
+{
+ if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones
+ return;
+
+ TryForEachAndRemoveFailed(notifiers, [pindexNew](CZMQAbstractNotifier* notifier) {
+ return notifier->NotifyBlock(pindexNew);
+ });
+}
+
void CZMQNotificationInterface::TransactionAddedToMempool(const CTransactionRef& ptx)
{
// Used by BlockConnected and BlockDisconnected as well, because they're
// all the same external callback.
const CTransaction& tx = *ptx;
- for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
- {
- CZMQAbstractNotifier *notifier = *i;
- if (notifier->NotifyTransaction(tx))
- {
- i++;
- }
- else
- {
- notifier->Shutdown();
- i = notifiers.erase(i);
- }
- }
+ TryForEachAndRemoveFailed(notifiers, [&tx](CZMQAbstractNotifier* notifier) {
+ return notifier->NotifyTransaction(tx);
+ });
}
void CZMQNotificationInterface::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected)
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index 60f3b6148a..0686960ed4 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -7,6 +7,7 @@
#include <validationinterface.h>
#include <list>
+#include <memory>
class CBlockIndex;
class CZMQAbstractNotifier;
@@ -34,7 +35,7 @@ private:
CZMQNotificationInterface();
void *pcontext;
- std::list<CZMQAbstractNotifier*> notifiers;
+ std::list<std::unique_ptr<CZMQAbstractNotifier>> notifiers;
};
extern CZMQNotificationInterface* g_zmq_notification_interface;
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index 04806903c2..d4d21b05ba 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -2,13 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <zmq/zmqpublishnotifier.h>
+
#include <chain.h>
#include <chainparams.h>
+#include <rpc/server.h>
#include <streams.h>
-#include <zmq/zmqpublishnotifier.h>
-#include <validation.h>
#include <util/system.h>
-#include <rpc/server.h>
+#include <validation.h>
+#include <zmq/zmqutil.h>
+
+#include <zmq.h>
+
+#include <cstdarg>
+#include <cstddef>
+#include <map>
+#include <string>
+#include <utility>
static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
@@ -86,6 +96,14 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
return false;
}
+ const int so_keepalive_option {1};
+ rc = zmq_setsockopt(psocket, ZMQ_TCP_KEEPALIVE, &so_keepalive_option, sizeof(so_keepalive_option));
+ if (rc != 0) {
+ zmqError("Failed to set SO_KEEPALIVE");
+ zmq_close(psocket);
+ return false;
+ }
+
rc = zmq_bind(psocket, address.c_str());
if (rc != 0)
{
@@ -141,7 +159,7 @@ void CZMQAbstractPublishNotifier::Shutdown()
psocket = nullptr;
}
-bool CZMQAbstractPublishNotifier::SendMessage(const char *command, const void* data, size_t size)
+bool CZMQAbstractPublishNotifier::SendZmqMessage(const char *command, const void* data, size_t size)
{
assert(psocket);
@@ -165,7 +183,7 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
char data[32];
for (unsigned int i = 0; i < 32; i++)
data[31 - i] = hash.begin()[i];
- return SendMessage(MSG_HASHBLOCK, data, 32);
+ return SendZmqMessage(MSG_HASHBLOCK, data, 32);
}
bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
@@ -175,7 +193,7 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t
char data[32];
for (unsigned int i = 0; i < 32; i++)
data[31 - i] = hash.begin()[i];
- return SendMessage(MSG_HASHTX, data, 32);
+ return SendZmqMessage(MSG_HASHTX, data, 32);
}
bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
@@ -196,7 +214,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
ss << block;
}
- return SendMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size());
+ return SendZmqMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size());
}
bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
@@ -205,5 +223,5 @@ bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &tr
LogPrint(BCLog::ZMQ, "zmq: Publish rawtx %s\n", hash.GetHex());
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ss << transaction;
- return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size());
+ return SendZmqMessage(MSG_RAWTX, &(*ss.begin()), ss.size());
}
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index 278fdb94d2..eb9ae881be 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -22,7 +22,7 @@ public:
* data
* message sequence number
*/
- bool SendMessage(const char *command, const void* data, size_t size);
+ bool SendZmqMessage(const char *command, const void* data, size_t size);
bool Initialize(void *pcontext) override;
void Shutdown() override;
diff --git a/src/zmq/zmqutil.cpp b/src/zmq/zmqutil.cpp
new file mode 100644
index 0000000000..f07a4ae9fd
--- /dev/null
+++ b/src/zmq/zmqutil.cpp
@@ -0,0 +1,14 @@
+// Copyright (c) 2014-2018 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 <zmq/zmqutil.h>
+
+#include <logging.h>
+
+#include <zmq.h>
+
+void zmqError(const char* str)
+{
+ LogPrint(BCLog::ZMQ, "zmq: Error: %s, errno=%s\n", str, zmq_strerror(errno));
+}
diff --git a/src/zmq/zmqutil.h b/src/zmq/zmqutil.h
new file mode 100644
index 0000000000..4c1df5d6db
--- /dev/null
+++ b/src/zmq/zmqutil.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2014-2018 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_ZMQ_ZMQUTIL_H
+#define BITCOIN_ZMQ_ZMQUTIL_H
+
+void zmqError(const char* str);
+
+#endif // BITCOIN_ZMQ_ZMQUTIL_H