aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt9
-rw-r--r--CMakePresets.json1
-rwxr-xr-xci/test/00_setup_env_native_msan.sh1
-rwxr-xr-xci/test/01_base_install.sh2
-rw-r--r--cmake/script/GenerateHeaderFromJson.cmake2
-rw-r--r--cmake/script/GenerateHeaderFromRaw.cmake2
-rw-r--r--contrib/guix/manifest.scm6
-rw-r--r--depends/.gitignore1
-rw-r--r--depends/hosts/netbsd.mk2
-rw-r--r--depends/packages/native_capnp.mk4
-rw-r--r--doc/build-freebsd.md2
-rw-r--r--doc/build-netbsd.md13
-rw-r--r--doc/build-openbsd.md4
-rw-r--r--doc/release-notes-28121.md2
-rw-r--r--doc/release-notes-31223.md15
-rw-r--r--src/arith_uint256.h1
-rw-r--r--src/base58.cpp2
-rw-r--r--src/bench/block_assemble.cpp13
-rw-r--r--src/chainparamsbase.cpp10
-rw-r--r--src/chainparamsbase.h6
-rw-r--r--src/consensus/merkle.cpp31
-rw-r--r--src/consensus/merkle.h4
-rw-r--r--src/crypto/chacha20.cpp18
-rw-r--r--src/crypto/common.h43
-rw-r--r--src/httpserver.h13
-rw-r--r--src/init.cpp16
-rw-r--r--src/interfaces/mining.h30
-rw-r--r--src/ipc/capnp/mining.capnp5
-rw-r--r--src/net.cpp55
-rw-r--r--src/net.h16
-rw-r--r--src/net_processing.cpp97
-rw-r--r--src/node/interfaces.cpp51
-rw-r--r--src/node/kernel_notifications.cpp8
-rw-r--r--src/node/kernel_notifications.h4
-rw-r--r--src/node/miner.cpp4
-rw-r--r--src/node/miner.h4
-rw-r--r--src/node/types.h21
-rw-r--r--src/policy/packages.h5
-rw-r--r--src/policy/rbf.cpp2
-rw-r--r--src/random.cpp2
-rw-r--r--src/rpc/blockchain.cpp10
-rw-r--r--src/rpc/mempool.cpp4
-rw-r--r--src/rpc/mining.cpp82
-rw-r--r--src/script/descriptor.cpp6
-rw-r--r--src/script/miniscript.h8
-rw-r--r--src/script/solver.h2
-rw-r--r--src/serialize.h2
-rw-r--r--src/span.h5
-rw-r--r--src/streams.h2
-rw-r--r--src/support/allocators/secure.h4
-rw-r--r--src/test/CMakeLists.txt2
-rw-r--r--src/test/blockfilter_index_tests.cpp5
-rw-r--r--src/test/descriptor_tests.cpp3
-rw-r--r--src/test/fuzz/addrman.cpp3
-rw-r--r--src/test/fuzz/banman.cpp1
-rw-r--r--src/test/fuzz/blockfilter.cpp2
-rw-r--r--src/test/fuzz/connman.cpp1
-rw-r--r--src/test/fuzz/fuzz.cpp9
-rw-r--r--src/test/fuzz/golomb_rice.cpp2
-rw-r--r--src/test/fuzz/headerssync.cpp1
-rw-r--r--src/test/fuzz/i2p.cpp1
-rw-r--r--src/test/fuzz/key.cpp2
-rw-r--r--src/test/fuzz/mini_miner.cpp6
-rw-r--r--src/test/fuzz/netaddress.cpp2
-rw-r--r--src/test/fuzz/p2p_handshake.cpp1
-rw-r--r--src/test/fuzz/p2p_headers_presync.cpp1
-rw-r--r--src/test/fuzz/package_eval.cpp8
-rw-r--r--src/test/fuzz/partially_downloaded_block.cpp1
-rw-r--r--src/test/fuzz/process_message.cpp3
-rw-r--r--src/test/fuzz/process_messages.cpp3
-rw-r--r--src/test/fuzz/psbt.cpp7
-rw-r--r--src/test/fuzz/rbf.cpp2
-rw-r--r--src/test/fuzz/rolling_bloom_filter.cpp2
-rw-r--r--src/test/fuzz/rpc.cpp1
-rw-r--r--src/test/fuzz/script_sigcache.cpp1
-rw-r--r--src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp2
-rw-r--r--src/test/fuzz/transaction.cpp2
-rw-r--r--src/test/fuzz/tx_pool.cpp9
-rw-r--r--src/test/fuzz/txdownloadman.cpp2
-rw-r--r--src/test/fuzz/util/CMakeLists.txt1
-rw-r--r--src/test/fuzz/util/check_globals.cpp41
-rw-r--r--src/test/fuzz/util/check_globals.h19
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp1
-rw-r--r--src/test/fuzz/utxo_total_supply.cpp7
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp1
-rw-r--r--src/test/merkle_tests.cpp2
-rw-r--r--src/test/miner_tests.cpp202
-rw-r--r--src/test/peerman_tests.cpp3
-rw-r--r--src/test/script_tests.cpp3
-rw-r--r--src/test/serialize_tests.cpp2
-rw-r--r--src/test/util/mining.cpp16
-rw-r--r--src/test/util/mining.h7
-rw-r--r--src/test/util/net.h4
-rw-r--r--src/test/util/random.cpp6
-rw-r--r--src/test/util/random.h4
-rw-r--r--src/test/util/setup_common.cpp8
-rw-r--r--src/test/validation_block_tests.cpp6
-rw-r--r--src/test/validation_chainstate_tests.cpp3
-rw-r--r--src/torcontrol.cpp4
-rw-r--r--src/torcontrol.h2
-rw-r--r--src/txmempool.cpp2
-rw-r--r--src/txmempool.h2
-rw-r--r--src/uint256.h29
-rw-r--r--src/univalue/CMakeLists.txt117
-rw-r--r--src/univalue/test/fail18.json2
-rw-r--r--src/univalue/test/pass2.json2
-rw-r--r--src/univalue/test/unitester.cpp246
-rw-r--r--src/util/hasher.h3
-rw-r--r--src/validation.cpp34
-rw-r--r--src/validation.h6
-rw-r--r--src/wallet/coinselection.cpp1
-rw-r--r--src/wallet/test/db_tests.cpp4
-rw-r--r--src/wallet/test/fuzz/coinselection.cpp1
-rw-r--r--src/wallet/test/fuzz/notifications.cpp1
-rw-r--r--src/wallet/test/fuzz/scriptpubkeyman.cpp1
-rwxr-xr-xtest/functional/feature_cltv.py11
-rwxr-xr-xtest/functional/feature_dersig.py11
-rwxr-xr-xtest/functional/feature_index_prune.py49
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py6
-rwxr-xr-xtest/functional/feature_port.py60
-rwxr-xr-xtest/functional/feature_rbf.py60
-rwxr-xr-xtest/functional/feature_signet.py54
-rwxr-xr-xtest/functional/mempool_accept.py2
-rwxr-xr-xtest/functional/mempool_accept_wtxid.py6
-rwxr-xr-xtest/functional/mempool_ephemeral_dust.py12
-rwxr-xr-xtest/functional/mempool_package_rbf.py4
-rwxr-xr-xtest/functional/p2p_addrv2_relay.py2
-rwxr-xr-xtest/functional/p2p_leak.py2
-rwxr-xr-xtest/functional/p2p_sendtxrcncl.py4
-rwxr-xr-xtest/functional/p2p_timeouts.py12
-rwxr-xr-xtest/functional/p2p_v2_misbehaving.py4
-rwxr-xr-xtest/functional/rpc_generate.py13
-rwxr-xr-xtest/functional/rpc_getdescriptoractivity.py4
-rwxr-xr-xtest/functional/rpc_packages.py15
-rw-r--r--test/functional/test_framework/authproxy.py7
-rwxr-xr-xtest/functional/test_framework/test_node.py5
-rw-r--r--test/functional/test_framework/util.py11
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_assumeutxo.py16
-rwxr-xr-xtest/functional/wallet_migration.py4
-rwxr-xr-xtest/fuzz/test_runner.py10
-rwxr-xr-xtest/lint/lint-assertions.py54
-rw-r--r--test/lint/test_runner/src/main.rs102
143 files changed, 1354 insertions, 717 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b21646ca1..2dba6f255d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -298,6 +298,15 @@ if(WIN32)
try_append_linker_flag("-Wl,--major-subsystem-version,6" TARGET core_interface)
try_append_linker_flag("-Wl,--minor-subsystem-version,2" TARGET core_interface)
endif()
+
+ # Workaround producing large object files, which cannot be handled by the assembler.
+ # More likely to happen with no, or lower levels of optimisation.
+ # See discussion in https://github.com/bitcoin/bitcoin/issues/28109.
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ try_append_cxx_flags("/bigobj" TARGET core_interface_debug SKIP_LINK)
+ else()
+ try_append_cxx_flags("-Wa,-mbig-obj" TARGET core_interface_debug SKIP_LINK)
+ endif()
endif()
# Use 64-bit off_t on 32-bit Linux.
diff --git a/CMakePresets.json b/CMakePresets.json
index 597907b932..da838f2b0e 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -71,7 +71,6 @@
"BUILD_GUI_TESTS": "ON",
"BUILD_KERNEL_LIB": "ON",
"BUILD_SHARED_LIBS": "ON",
- "BUILD_TESTING": "ON",
"BUILD_TESTS": "ON",
"BUILD_TX": "ON",
"BUILD_UTIL": "ON",
diff --git a/ci/test/00_setup_env_native_msan.sh b/ci/test/00_setup_env_native_msan.sh
index c6b3d68be6..cd4ac99942 100755
--- a/ci/test/00_setup_env_native_msan.sh
+++ b/ci/test/00_setup_env_native_msan.sh
@@ -27,4 +27,3 @@ export BITCOIN_CONFIG="\
-DAPPEND_CPPFLAGS='-U_FORTIFY_SOURCE' \
"
export USE_MEMORY_SANITIZER="true"
-export RUN_FUNCTIONAL_TESTS="false"
diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh
index e026b919e3..0130e820c2 100755
--- a/ci/test/01_base_install.sh
+++ b/ci/test/01_base_install.sh
@@ -49,7 +49,7 @@ if [ -n "$PIP_PACKAGES" ]; then
fi
if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
- ${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-19.1.0" /msan/llvm-project
+ ${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-19.1.6" /msan/llvm-project
cmake -G Ninja -B /msan/clang_build/ \
-DLLVM_ENABLE_PROJECTS="clang" \
diff --git a/cmake/script/GenerateHeaderFromJson.cmake b/cmake/script/GenerateHeaderFromJson.cmake
index 4a3bddb323..384ac20d10 100644
--- a/cmake/script/GenerateHeaderFromJson.cmake
+++ b/cmake/script/GenerateHeaderFromJson.cmake
@@ -6,7 +6,7 @@ cmake_path(GET JSON_SOURCE_PATH STEM json_source_basename)
file(READ ${JSON_SOURCE_PATH} hex_content HEX)
string(REGEX REPLACE "................" "\\0\n" formatted_bytes "${hex_content}")
-string(REGEX REPLACE "[^\n][^\n]" "0x\\0, " formatted_bytes "${formatted_bytes}")
+string(REGEX REPLACE "[^\n][^\n]" "'\\\\x\\0'," formatted_bytes "${formatted_bytes}")
set(header_content
"#include <string_view>
diff --git a/cmake/script/GenerateHeaderFromRaw.cmake b/cmake/script/GenerateHeaderFromRaw.cmake
index 638876ecea..d373d1c4f8 100644
--- a/cmake/script/GenerateHeaderFromRaw.cmake
+++ b/cmake/script/GenerateHeaderFromRaw.cmake
@@ -6,7 +6,7 @@ cmake_path(GET RAW_SOURCE_PATH STEM raw_source_basename)
file(READ ${RAW_SOURCE_PATH} hex_content HEX)
string(REGEX REPLACE "................" "\\0\n" formatted_bytes "${hex_content}")
-string(REGEX REPLACE "[^\n][^\n]" "std::byte{0x\\0}, " formatted_bytes "${formatted_bytes}")
+string(REGEX REPLACE "[^\n][^\n]" "std::byte{0x\\0}," formatted_bytes "${formatted_bytes}")
set(header_content
"#include <cstddef>
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 8854cfef30..3244a8dbdc 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -451,7 +451,7 @@ inspecting signatures in Mach-O binaries.")
#t))))))))
(define-public glibc-2.31
- (let ((commit "8e30f03744837a85e33d84ccd34ed3abe30d37c3"))
+ (let ((commit "7b27c450c34563a28e634cccb399cd415e71ebfe"))
(package
(inherit glibc) ;; 2.35
(version "2.31")
@@ -463,7 +463,7 @@ inspecting signatures in Mach-O binaries.")
(file-name (git-file-name "glibc" commit))
(sha256
(base32
- "1zi0s9yy5zkisw823vivn7zlj8w6g9p3mm7lmlqiixcxdkz4dbn6"))
+ "017qdpr5id7ddb4lpkzj2li1abvw916m3fc6n7nw28z4h5qbv2n0"))
(patches (search-our-patches "glibc-guix-prefix.patch"))))
(arguments
(substitute-keyword-arguments (package-arguments glibc)
@@ -474,6 +474,8 @@ inspecting signatures in Mach-O binaries.")
"--enable-cet",
"--enable-bind-now",
"--disable-werror",
+ "--disable-timezone-tools",
+ "--disable-profile",
building-on)))
((#:phases phases)
`(modify-phases ,phases
diff --git a/depends/.gitignore b/depends/.gitignore
index be6280f599..c53f7f610e 100644
--- a/depends/.gitignore
+++ b/depends/.gitignore
@@ -3,6 +3,7 @@ work/
built/
sources/
x86_64*
+amd64*
i686*
mips*
arm*
diff --git a/depends/hosts/netbsd.mk b/depends/hosts/netbsd.mk
index 838b58e7ba..d2b79f9d5b 100644
--- a/depends/hosts/netbsd.mk
+++ b/depends/hosts/netbsd.mk
@@ -7,8 +7,6 @@ netbsd_NM = $(host_toolchain)gcc-nm
netbsd_RANLIB = $(host_toolchain)gcc-ranlib
endif
-netbsd_CXXFLAGS=$(netbsd_CFLAGS)
-
netbsd_release_CFLAGS=-O2
netbsd_release_CXXFLAGS=$(netbsd_release_CFLAGS)
diff --git a/depends/packages/native_capnp.mk b/depends/packages/native_capnp.mk
index d6e6b4cadb..e67b103716 100644
--- a/depends/packages/native_capnp.mk
+++ b/depends/packages/native_capnp.mk
@@ -1,9 +1,9 @@
package=native_capnp
-$(package)_version=1.0.2
+$(package)_version=1.1.0
$(package)_download_path=https://capnproto.org/
$(package)_download_file=capnproto-c++-$($(package)_version).tar.gz
$(package)_file_name=capnproto-cxx-$($(package)_version).tar.gz
-$(package)_sha256_hash=9057dbc0223366b74bbeca33a05de164a229b0377927f1b7ef3828cdd8cb1d7e
+$(package)_sha256_hash=07167580e563f5e821e3b2af1c238c16ec7181612650c5901330fa9a0da50939
define $(package)_set_vars
$(package)_config_opts := -DBUILD_TESTING=OFF
diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md
index 2456abd57b..694224621e 100644
--- a/doc/build-freebsd.md
+++ b/doc/build-freebsd.md
@@ -96,7 +96,7 @@ There is an included test suite that is useful for testing code changes when dev
To run the test suite (recommended), you will need to have Python 3 installed:
```bash
-pkg install python3 databases/py-sqlite3
+pkg install python3 databases/py-sqlite3 net/py-pyzmq
```
---
diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md
index 63bfbd61db..988f3b93a7 100644
--- a/doc/build-netbsd.md
+++ b/doc/build-netbsd.md
@@ -1,6 +1,6 @@
# NetBSD Build Guide
-**Updated for NetBSD [10.0](https://netbsd.org/releases/formal-10/NetBSD-10.0.html)**
+**Updated for NetBSD [10.1](https://netbsd.org/releases/formal-10/NetBSD-10.1.html)**
This guide describes how to build bitcoind, command-line utilities, and GUI on NetBSD.
@@ -83,6 +83,13 @@ pkgin install qrencode
Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF` option to disable this feature in order to compile the GUI.
+#### Notifications
+###### ZeroMQ
+
+Bitcoin Core can provide notifications via ZeroMQ. If the package is installed, support will be compiled in.
+```bash
+pkgin zeromq
+```
#### Test Suite Dependencies
@@ -90,10 +97,10 @@ There is an included test suite that is useful for testing code changes when dev
To run the test suite (recommended), you will need to have Python 3 installed:
```bash
-pkgin install python39
+pkgin install python310 py310-zmq
```
-### Building Bitcoin Core
+## Building Bitcoin Core
### 1. Configuration
diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md
index d2535d2b4c..1ad90f23bc 100644
--- a/doc/build-openbsd.md
+++ b/doc/build-openbsd.md
@@ -1,6 +1,6 @@
# OpenBSD Build Guide
-**Updated for OpenBSD [7.5](https://www.openbsd.org/75.html)**
+**Updated for OpenBSD [7.6](https://www.openbsd.org/76.html)**
This guide describes how to build bitcoind, command-line utilities, and GUI on OpenBSD.
@@ -90,7 +90,7 @@ There is an included test suite that is useful for testing code changes when dev
To run the test suite (recommended), you will need to have Python 3 installed:
```bash
-pkg_add python # Select the newest version of the package.
+pkg_add python py3-zmq # Select the newest version of the python package if necessary.
```
## Building Bitcoin Core
diff --git a/doc/release-notes-28121.md b/doc/release-notes-28121.md
new file mode 100644
index 0000000000..911b7c5620
--- /dev/null
+++ b/doc/release-notes-28121.md
@@ -0,0 +1,2 @@
+The RPC `testmempoolaccept` response now includes a "reject-details" field in some cases,
+similar to the complete error messages returned by `sendrawtransaction` (#28121) \ No newline at end of file
diff --git a/doc/release-notes-31223.md b/doc/release-notes-31223.md
new file mode 100644
index 0000000000..44f0552fd9
--- /dev/null
+++ b/doc/release-notes-31223.md
@@ -0,0 +1,15 @@
+P2P and network changes
+-----------------------
+When the `-port` configuration option is used, the default onion listening port will now
+be derived to be that port + 1 instead of being set to a fixed value (8334 on mainnet).
+This re-allows setups with multiple local nodes using different `-port` and not using `-bind`,
+which would lead to a startup failure in v28.0 due to a port collision.
+
+Note that a `HiddenServicePort` manually configured in `torrc` may need adjustment if used in
+connection with the `-port` option.
+For example, if you are using `-port=5555` with a non-standard value and not using `-bind=...=onion`,
+previously Bitcoin Core would listen for incoming Tor connections on `127.0.0.1:8334`.
+Now it would listen on `127.0.0.1:5556` (`-port` plus one). If you configured the hidden service manually
+in torrc now you have to change it from `HiddenServicePort 8333 127.0.0.1:8334` to `HiddenServicePort 8333
+127.0.0.1:5556`, or configure bitcoind with `-bind=127.0.0.1:8334=onion` to get the previous behavior.
+(#31223)
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 38b7453034..60b371f6d3 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -26,6 +26,7 @@ class base_uint
protected:
static_assert(BITS / 32 > 0 && BITS % 32 == 0, "Template parameter BITS must be a positive multiple of 32.");
static constexpr int WIDTH = BITS / 32;
+ /** Big integer represented with 32-bit digits, least-significant first. */
uint32_t pn[WIDTH];
public:
diff --git a/src/base58.cpp b/src/base58.cpp
index f9165ed55f..cab99f0cb5 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -139,7 +139,7 @@ std::string EncodeBase58Check(Span<const unsigned char> input)
// add 4-byte hash check to the end
std::vector<unsigned char> vch(input.begin(), input.end());
uint256 hash = Hash(vch);
- vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
+ vch.insert(vch.end(), hash.data(), hash.data() + 4);
return EncodeBase58(vch);
}
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index 4005701cae..00102aefe2 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -20,19 +20,23 @@
#include <memory>
#include <vector>
+using node::BlockAssembler;
+
static void AssembleBlock(benchmark::Bench& bench)
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
CScriptWitness witness;
witness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE);
+ BlockAssembler::Options options;
+ options.coinbase_output_script = P2WSH_OP_TRUE;
// Collect some loose transactions that spend the coinbases of our mined blocks
constexpr size_t NUM_BLOCKS{200};
std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
for (size_t b{0}; b < NUM_BLOCKS; ++b) {
CMutableTransaction tx;
- tx.vin.emplace_back(MineBlock(test_setup->m_node, P2WSH_OP_TRUE));
+ tx.vin.emplace_back(MineBlock(test_setup->m_node, options));
tx.vin.back().scriptWitness = witness;
tx.vout.emplace_back(1337, P2WSH_OP_TRUE);
if (NUM_BLOCKS - b >= COINBASE_MATURITY)
@@ -48,7 +52,7 @@ static void AssembleBlock(benchmark::Bench& bench)
}
bench.run([&] {
- PrepareBlock(test_setup->m_node, P2WSH_OP_TRUE);
+ PrepareBlock(test_setup->m_node, options);
});
}
static void BlockAssemblerAddPackageTxns(benchmark::Bench& bench)
@@ -56,11 +60,12 @@ static void BlockAssemblerAddPackageTxns(benchmark::Bench& bench)
FastRandomContext det_rand{true};
auto testing_setup{MakeNoLogFileContext<TestChain100Setup>()};
testing_setup->PopulateMempool(det_rand, /*num_transactions=*/1000, /*submit=*/true);
- node::BlockAssembler::Options assembler_options;
+ BlockAssembler::Options assembler_options;
assembler_options.test_block_validity = false;
+ assembler_options.coinbase_output_script = P2WSH_OP_TRUE;
bench.run([&] {
- PrepareBlock(testing_setup->m_node, P2WSH_OP_TRUE, assembler_options);
+ PrepareBlock(testing_setup->m_node, assembler_options);
});
}
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index aadd04e509..060d519d92 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -41,15 +41,15 @@ std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const ChainType chain)
{
switch (chain) {
case ChainType::MAIN:
- return std::make_unique<CBaseChainParams>("", 8332, 8334);
+ return std::make_unique<CBaseChainParams>("", 8332);
case ChainType::TESTNET:
- return std::make_unique<CBaseChainParams>("testnet3", 18332, 18334);
+ return std::make_unique<CBaseChainParams>("testnet3", 18332);
case ChainType::TESTNET4:
- return std::make_unique<CBaseChainParams>("testnet4", 48332, 48334);
+ return std::make_unique<CBaseChainParams>("testnet4", 48332);
case ChainType::SIGNET:
- return std::make_unique<CBaseChainParams>("signet", 38332, 38334);
+ return std::make_unique<CBaseChainParams>("signet", 38332);
case ChainType::REGTEST:
- return std::make_unique<CBaseChainParams>("regtest", 18443, 18445);
+ return std::make_unique<CBaseChainParams>("regtest", 18443);
}
assert(false);
}
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index c75a70cb96..adbd6a5174 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -22,15 +22,13 @@ class CBaseChainParams
public:
const std::string& DataDir() const { return strDataDir; }
uint16_t RPCPort() const { return m_rpc_port; }
- uint16_t OnionServiceTargetPort() const { return m_onion_service_target_port; }
CBaseChainParams() = delete;
- CBaseChainParams(const std::string& data_dir, uint16_t rpc_port, uint16_t onion_service_target_port)
- : m_rpc_port(rpc_port), m_onion_service_target_port(onion_service_target_port), strDataDir(data_dir) {}
+ CBaseChainParams(const std::string& data_dir, uint16_t rpc_port)
+ : m_rpc_port(rpc_port), strDataDir(data_dir) {}
private:
const uint16_t m_rpc_port;
- const uint16_t m_onion_service_target_port;
std::string strDataDir;
};
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index dc32f0ab80..7dd24e1868 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -4,6 +4,7 @@
#include <consensus/merkle.h>
#include <hash.h>
+#include <util/check.h>
/* WARNING! If you're reading this because you're learning about crypto
and/or designing a new system that will use merkle trees, keep in mind
@@ -84,8 +85,10 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated)
}
/* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */
-static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector<uint256>* pbranch) {
- if (pbranch) pbranch->clear();
+static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t leaf_pos, std::vector<uint256>* path)
+{
+ if (path) path->clear();
+ Assume(leaves.size() <= UINT32_MAX);
if (leaves.size() == 0) {
if (pmutated) *pmutated = false;
if (proot) *proot = uint256();
@@ -105,18 +108,18 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
// First process all leaves into 'inner' values.
while (count < leaves.size()) {
uint256 h = leaves[count];
- bool matchh = count == branchpos;
+ bool matchh = count == leaf_pos;
count++;
int level;
// For each of the lower bits in count that are 0, do 1 step. Each
// corresponds to an inner value that existed before processing the
// current leaf, and each needs a hash to combine it.
for (level = 0; !(count & ((uint32_t{1}) << level)); level++) {
- if (pbranch) {
+ if (path) {
if (matchh) {
- pbranch->push_back(inner[level]);
+ path->push_back(inner[level]);
} else if (matchlevel == level) {
- pbranch->push_back(h);
+ path->push_back(h);
matchh = true;
}
}
@@ -144,8 +147,8 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
// If we reach this point, h is an inner value that is not the top.
// We combine it with itself (Bitcoin's special rule for odd levels in
// the tree) to produce a higher level one.
- if (pbranch && matchh) {
- pbranch->push_back(h);
+ if (path && matchh) {
+ path->push_back(h);
}
h = Hash(h, h);
// Increment count to the value it would have if two entries at this
@@ -154,11 +157,11 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
level++;
// And propagate the result upwards accordingly.
while (!(count & ((uint32_t{1}) << level))) {
- if (pbranch) {
+ if (path) {
if (matchh) {
- pbranch->push_back(inner[level]);
+ path->push_back(inner[level]);
} else if (matchlevel == level) {
- pbranch->push_back(h);
+ path->push_back(h);
matchh = true;
}
}
@@ -171,18 +174,18 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
if (proot) *proot = h;
}
-static std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position) {
+static std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& leaves, uint32_t position) {
std::vector<uint256> ret;
MerkleComputation(leaves, nullptr, nullptr, position, &ret);
return ret;
}
-std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position)
+std::vector<uint256> TransactionMerklePath(const CBlock& block, uint32_t position)
{
std::vector<uint256> leaves;
leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++) {
leaves[s] = block.vtx[s]->GetHash();
}
- return ComputeMerkleBranch(leaves, position);
+ return ComputeMerklePath(leaves, position);
}
diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h
index 363f68039c..c722cbe446 100644
--- a/src/consensus/merkle.h
+++ b/src/consensus/merkle.h
@@ -28,10 +28,10 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated = nullptr);
* Compute merkle path to the specified transaction
*
* @param[in] block the block
- * @param[in] position transaction for which to calculate the merkle path, defaults to coinbase
+ * @param[in] position transaction for which to calculate the merkle path (0 is the coinbase)
*
* @return merkle path ordered from the deepest
*/
-std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position = 0);
+std::vector<uint256> TransactionMerklePath(const CBlock& block, uint32_t position);
#endif // BITCOIN_CONSENSUS_MERKLE_H
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
index 4feed862cb..e756e0431e 100644
--- a/src/crypto/chacha20.cpp
+++ b/src/crypto/chacha20.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022 The Bitcoin Core developers
+// Copyright (c) 2017-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,14 +25,14 @@
void ChaCha20Aligned::SetKey(Span<const std::byte> key) noexcept
{
assert(key.size() == KEYLEN);
- input[0] = ReadLE32(UCharCast(key.data() + 0));
- input[1] = ReadLE32(UCharCast(key.data() + 4));
- input[2] = ReadLE32(UCharCast(key.data() + 8));
- input[3] = ReadLE32(UCharCast(key.data() + 12));
- input[4] = ReadLE32(UCharCast(key.data() + 16));
- input[5] = ReadLE32(UCharCast(key.data() + 20));
- input[6] = ReadLE32(UCharCast(key.data() + 24));
- input[7] = ReadLE32(UCharCast(key.data() + 28));
+ input[0] = ReadLE32(key.data() + 0);
+ input[1] = ReadLE32(key.data() + 4);
+ input[2] = ReadLE32(key.data() + 8);
+ input[3] = ReadLE32(key.data() + 12);
+ input[4] = ReadLE32(key.data() + 16);
+ input[5] = ReadLE32(key.data() + 20);
+ input[6] = ReadLE32(key.data() + 24);
+ input[7] = ReadLE32(key.data() + 28);
input[8] = 0;
input[9] = 0;
input[10] = 0;
diff --git a/src/crypto/common.h b/src/crypto/common.h
index d45459b1f6..f151cbb625 100644
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020 The Bitcoin Core developers
+// Copyright (c) 2014-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,82 +7,99 @@
#include <compat/endian.h>
+#include <concepts>
+#include <cstddef>
#include <cstdint>
#include <cstring>
-uint16_t static inline ReadLE16(const unsigned char* ptr)
+template <typename B>
+concept ByteType = std::same_as<B, unsigned char> || std::same_as<B, std::byte>;
+
+template <ByteType B>
+inline uint16_t ReadLE16(const B* ptr)
{
uint16_t x;
memcpy(&x, ptr, 2);
return le16toh_internal(x);
}
-uint32_t static inline ReadLE32(const unsigned char* ptr)
+template <ByteType B>
+inline uint32_t ReadLE32(const B* ptr)
{
uint32_t x;
memcpy(&x, ptr, 4);
return le32toh_internal(x);
}
-uint64_t static inline ReadLE64(const unsigned char* ptr)
+template <ByteType B>
+inline uint64_t ReadLE64(const B* ptr)
{
uint64_t x;
memcpy(&x, ptr, 8);
return le64toh_internal(x);
}
-void static inline WriteLE16(unsigned char* ptr, uint16_t x)
+template <ByteType B>
+inline void WriteLE16(B* ptr, uint16_t x)
{
uint16_t v = htole16_internal(x);
memcpy(ptr, &v, 2);
}
-void static inline WriteLE32(unsigned char* ptr, uint32_t x)
+template <ByteType B>
+inline void WriteLE32(B* ptr, uint32_t x)
{
uint32_t v = htole32_internal(x);
memcpy(ptr, &v, 4);
}
-void static inline WriteLE64(unsigned char* ptr, uint64_t x)
+template <ByteType B>
+inline void WriteLE64(B* ptr, uint64_t x)
{
uint64_t v = htole64_internal(x);
memcpy(ptr, &v, 8);
}
-uint16_t static inline ReadBE16(const unsigned char* ptr)
+template <ByteType B>
+inline uint16_t ReadBE16(const B* ptr)
{
uint16_t x;
memcpy(&x, ptr, 2);
return be16toh_internal(x);
}
-uint32_t static inline ReadBE32(const unsigned char* ptr)
+template <ByteType B>
+inline uint32_t ReadBE32(const B* ptr)
{
uint32_t x;
memcpy(&x, ptr, 4);
return be32toh_internal(x);
}
-uint64_t static inline ReadBE64(const unsigned char* ptr)
+template <ByteType B>
+inline uint64_t ReadBE64(const B* ptr)
{
uint64_t x;
memcpy(&x, ptr, 8);
return be64toh_internal(x);
}
-void static inline WriteBE16(unsigned char* ptr, uint16_t x)
+template <ByteType B>
+inline void WriteBE16(B* ptr, uint16_t x)
{
uint16_t v = htobe16_internal(x);
memcpy(ptr, &v, 2);
}
-void static inline WriteBE32(unsigned char* ptr, uint32_t x)
+template <ByteType B>
+inline void WriteBE32(B* ptr, uint32_t x)
{
uint32_t v = htobe32_internal(x);
memcpy(ptr, &v, 4);
}
-void static inline WriteBE64(unsigned char* ptr, uint64_t x)
+template <ByteType B>
+inline void WriteBE64(B* ptr, uint64_t x)
{
uint64_t v = htobe64_internal(x);
memcpy(ptr, &v, 8);
diff --git a/src/httpserver.h b/src/httpserver.h
index 33216a0119..6535dc6086 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -14,8 +14,17 @@ namespace util {
class SignalInterrupt;
} // namespace util
-static const int DEFAULT_HTTP_THREADS=4;
-static const int DEFAULT_HTTP_WORKQUEUE=16;
+/**
+ * The default value for `-rpcthreads`. This number of threads will be created at startup.
+ */
+static const int DEFAULT_HTTP_THREADS=16;
+
+/**
+ * The default value for `-rpcworkqueue`. This is the maximum depth of the work queue,
+ * we don't allocate this number of work queue items upfront.
+ */
+static const int DEFAULT_HTTP_WORKQUEUE=64;
+
static const int DEFAULT_HTTP_SERVER_TIMEOUT=30;
struct evhttp_request;
diff --git a/src/init.cpp b/src/init.cpp
index 4e61e030f7..b5adcf6476 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -523,7 +523,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
argsman.AddArg("-addnode=<ip>", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
- argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet3: 127.0.0.1:%u=onion, testnet4: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), testnet4BaseParams->OnionServiceTargetPort(), signetBaseParams->OnionServiceTargetPort(), regtestBaseParams->OnionServiceTargetPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet3: 127.0.0.1:%u=onion, testnet4: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultChainParams->GetDefaultPort() + 1, testnetChainParams->GetDefaultPort() + 1, testnet4ChainParams->GetDefaultPort() + 1, signetChainParams->GetDefaultPort() + 1, regtestChainParams->GetDefaultPort() + 1), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
argsman.AddArg("-cjdnsreachable", "If set, then this host is configured for CJDNS (connecting to fc00::/8 addresses would lead us to the CJDNS network, see doc/cjdns.md) (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -550,7 +550,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
- argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), testnet4ChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md). If set to a value x, the default onion listening port will be set to x+1.", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), testnet4ChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
#ifdef HAVE_SOCKADDR_UN
argsman.AddArg("-proxy=<ip:port|path>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled). May be a local file path prefixed with 'unix:' if the proxy supports it.", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION);
#else
@@ -665,7 +665,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
argsman.AddArg("-rpcwhitelist=<whitelist>", "Set a whitelist to filter incoming RPC calls for a specific user. The field <whitelist> comes in the format: <USERNAME>:<rpc 1>,<rpc 2>,...,<rpc n>. If multiple whitelists are set for a given user, they are set-intersected. See -rpcwhitelistdefault documentation for information on default whitelist behavior.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
- argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
+ argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the maximum depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
if (can_listen_ipc) {
argsman.AddArg("-ipcbind=<address>", "Bind to Unix socket address and listen for incoming connections. Valid address values are \"unix\" to listen on the default path, <datadir>/node.sock, or \"unix:/custom/path\" to specify a custom path. Can be specified multiple times to listen on multiple paths. Default behavior is not to listen on any path. If relative paths are specified, they are interpreted relative to the network data directory. If paths include any parent directory components and the parent directories do not exist, they will be created.", ArgsManager::ALLOW_ANY, OptionsCategory::IPC);
@@ -1807,7 +1807,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
{
WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);
kernel_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
- return !kernel_notifications.m_tip_block.IsNull() || ShutdownRequested(node);
+ return kernel_notifications.TipBlock() || ShutdownRequested(node);
});
}
@@ -1827,7 +1827,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (tip_info) {
tip_info->block_height = chain_active_height;
tip_info->block_time = best_block_time;
- tip_info->verification_progress = GuessVerificationProgress(chainman.GetParams().TxData(), &tip);
+ tip_info->verification_progress = chainman.GuessVerificationProgress(&tip);
}
if (tip_info && chainman.m_best_header) {
tip_info->header_height = chainman.m_best_header->nHeight;
@@ -1858,6 +1858,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const uint16_t default_bind_port =
static_cast<uint16_t>(args.GetIntArg("-port", Params().GetDefaultPort()));
+ const uint16_t default_bind_port_onion = default_bind_port + 1;
+
const auto BadPortWarning = [](const char* prefix, uint16_t port) {
return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and "
"thus it is unlikely that any peer will connect to it. See "
@@ -1882,7 +1884,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const std::string network_type = bind_arg.substr(index + 1);
if (network_type == "onion") {
const std::string truncated_bind_arg = bind_arg.substr(0, index);
- bind_addr = Lookup(truncated_bind_arg, BaseParams().OnionServiceTargetPort(), false);
+ bind_addr = Lookup(truncated_bind_arg, default_bind_port_onion, false);
if (bind_addr.has_value()) {
connOptions.onion_binds.push_back(bind_addr.value());
continue;
@@ -1918,7 +1920,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
} else if (!connOptions.vBinds.empty()) {
onion_service_target = connOptions.vBinds.front();
} else {
- onion_service_target = DefaultOnionServiceTarget();
+ onion_service_target = DefaultOnionServiceTarget(default_bind_port_onion);
connOptions.onion_binds.push_back(onion_service_target);
}
diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h
index 6f23bf3bb5..bc5955ded6 100644
--- a/src/interfaces/mining.h
+++ b/src/interfaces/mining.h
@@ -55,7 +55,7 @@ public:
*
* @returns if the block was processed, independent of block validity
*/
- virtual bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CMutableTransaction coinbase) = 0;
+ virtual bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CTransactionRef coinbase) = 0;
};
//! Interface giving clients (RPC, Stratum v2 Template Provider in the future)
@@ -88,36 +88,10 @@ public:
/**
* Construct a new block template
*
- * @param[in] script_pub_key the coinbase output
* @param[in] options options for creating the block
* @returns a block template
*/
- virtual std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options = {}) = 0;
-
- /**
- * Processes new block. A valid new block is automatically relayed to peers.
- *
- * @param[in] block The block we want to process.
- * @param[out] new_block A boolean which is set to indicate if the block was first received via this call
- * @returns If the block was processed, independently of block validity
- */
- virtual bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) = 0;
-
- //! Return the number of transaction updates in the mempool,
- //! used to decide whether to make a new block template.
- virtual unsigned int getTransactionsUpdated() = 0;
-
- /**
- * Check a block is completely valid from start to finish.
- * Only works on top of our current best block.
- * Does not check proof-of-work.
- *
- * @param[in] block the block to validate
- * @param[in] check_merkle_root call CheckMerkleRoot()
- * @param[out] state details of why a block failed to validate
- * @returns false if it does not build on the current tip, or any of the checks fail
- */
- virtual bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) = 0;
+ virtual std::unique_ptr<BlockTemplate> createNewBlock(const node::BlockCreateOptions& options = {}) = 0;
//! Get internal node context. Useful for RPC and testing,
//! but not accessible across processes.
diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp
index f8faaa0c42..50b07bda70 100644
--- a/src/ipc/capnp/mining.capnp
+++ b/src/ipc/capnp/mining.capnp
@@ -17,10 +17,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") {
isInitialBlockDownload @1 (context :Proxy.Context) -> (result: Bool);
getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool);
waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef);
- createNewBlock @4 (scriptPubKey: Data, options: BlockCreateOptions) -> (result: BlockTemplate);
- processNewBlock @5 (context :Proxy.Context, block: Data) -> (newBlock: Bool, result: Bool);
- getTransactionsUpdated @6 (context :Proxy.Context) -> (result: UInt32);
- testBlockValidity @7 (context :Proxy.Context, block: Data, checkMerkleRoot: Bool) -> (state: BlockValidationState, result: Bool);
+ createNewBlock @4 (options: BlockCreateOptions) -> (result: BlockTemplate);
}
interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
diff --git a/src/net.cpp b/src/net.cpp
index 802dc947be..8ea7f6ce44 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -558,7 +558,6 @@ void CNode::CloseSocketDisconnect()
fDisconnect = true;
LOCK(m_sock_mutex);
if (m_sock) {
- LogDebug(BCLog::NET, "disconnecting peer=%d\n", id);
m_sock.reset();
}
m_i2p_sam_session.reset();
@@ -696,6 +695,18 @@ bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete)
return true;
}
+std::string CNode::LogIP(bool log_ip) const
+{
+ return log_ip ? strprintf(" peeraddr=%s", addr.ToStringAddrPort()) : "";
+}
+
+std::string CNode::DisconnectMsg(bool log_ip) const
+{
+ return strprintf("disconnecting peer=%d%s",
+ GetId(),
+ LogIP(log_ip));
+}
+
V1Transport::V1Transport(const NodeId node_id) noexcept
: m_magic_bytes{Params().MessageStart()}, m_node_id{node_id}
{
@@ -1635,7 +1646,7 @@ std::pair<size_t, bool> CConnman::SocketSendData(CNode& node) const
// error
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) {
- LogDebug(BCLog::NET, "socket send error for peer=%d: %s\n", node.GetId(), NetworkErrorString(nErr));
+ LogDebug(BCLog::NET, "socket send error, %s: %s\n", node.DisconnectMsg(fLogIPs), NetworkErrorString(nErr));
node.CloseSocketDisconnect();
}
}
@@ -1879,7 +1890,7 @@ void CConnman::DisconnectNodes()
// Disconnect any connected nodes
for (CNode* pnode : m_nodes) {
if (!pnode->fDisconnect) {
- LogDebug(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId());
+ LogDebug(BCLog::NET, "Network not active, %s\n", pnode->DisconnectMsg(fLogIPs));
pnode->fDisconnect = true;
}
}
@@ -1971,26 +1982,43 @@ bool CConnman::InactivityCheck(const CNode& node) const
if (!ShouldRunInactivityChecks(node, now)) return false;
- if (last_recv.count() == 0 || last_send.count() == 0) {
- LogDebug(BCLog::NET, "socket no message in first %i seconds, %d %d peer=%d\n", count_seconds(m_peer_connect_timeout), last_recv.count() != 0, last_send.count() != 0, node.GetId());
+ bool has_received{last_recv.count() != 0};
+ bool has_sent{last_send.count() != 0};
+
+ if (!has_received || !has_sent) {
+ std::string has_never;
+ if (!has_received) has_never += ", never received from peer";
+ if (!has_sent) has_never += ", never sent to peer";
+ LogDebug(BCLog::NET,
+ "socket no message in first %i seconds%s, %s\n",
+ count_seconds(m_peer_connect_timeout),
+ has_never,
+ node.DisconnectMsg(fLogIPs)
+ );
return true;
}
if (now > last_send + TIMEOUT_INTERVAL) {
- LogDebug(BCLog::NET, "socket sending timeout: %is peer=%d\n", count_seconds(now - last_send), node.GetId());
+ LogDebug(BCLog::NET,
+ "socket sending timeout: %is, %s\n", count_seconds(now - last_send),
+ node.DisconnectMsg(fLogIPs)
+ );
return true;
}
if (now > last_recv + TIMEOUT_INTERVAL) {
- LogDebug(BCLog::NET, "socket receive timeout: %is peer=%d\n", count_seconds(now - last_recv), node.GetId());
+ LogDebug(BCLog::NET,
+ "socket receive timeout: %is, %s\n", count_seconds(now - last_recv),
+ node.DisconnectMsg(fLogIPs)
+ );
return true;
}
if (!node.fSuccessfullyConnected) {
if (node.m_transport->GetInfo().transport_type == TransportProtocolType::DETECTING) {
- LogDebug(BCLog::NET, "V2 handshake timeout peer=%d\n", node.GetId());
+ LogDebug(BCLog::NET, "V2 handshake timeout, %s\n", node.DisconnectMsg(fLogIPs));
} else {
- LogDebug(BCLog::NET, "version handshake timeout peer=%d\n", node.GetId());
+ LogDebug(BCLog::NET, "version handshake timeout, %s\n", node.DisconnectMsg(fLogIPs));
}
return true;
}
@@ -2118,6 +2146,10 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
{
bool notify = false;
if (!pnode->ReceiveMsgBytes({pchBuf, (size_t)nBytes}, notify)) {
+ LogDebug(BCLog::NET,
+ "receiving message bytes failed, %s\n",
+ pnode->DisconnectMsg(fLogIPs)
+ );
pnode->CloseSocketDisconnect();
}
RecordBytesRecv(nBytes);
@@ -2130,7 +2162,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
{
// socket closed gracefully
if (!pnode->fDisconnect) {
- LogDebug(BCLog::NET, "socket closed for peer=%d\n", pnode->GetId());
+ LogDebug(BCLog::NET, "socket closed, %s\n", pnode->DisconnectMsg(fLogIPs));
}
pnode->CloseSocketDisconnect();
}
@@ -2141,7 +2173,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
if (!pnode->fDisconnect) {
- LogDebug(BCLog::NET, "socket recv error for peer=%d: %s\n", pnode->GetId(), NetworkErrorString(nErr));
+ LogDebug(BCLog::NET, "socket recv error, %s: %s\n", pnode->DisconnectMsg(fLogIPs), NetworkErrorString(nErr));
}
pnode->CloseSocketDisconnect();
}
@@ -3411,6 +3443,7 @@ void CConnman::StopNodes()
std::vector<CNode*> nodes;
WITH_LOCK(m_nodes_mutex, nodes.swap(m_nodes));
for (CNode* pnode : nodes) {
+ LogDebug(BCLog::NET, "%s\n", pnode->DisconnectMsg(fLogIPs));
pnode->CloseSocketDisconnect();
DeleteNode(pnode);
}
diff --git a/src/net.h b/src/net.h
index fc096ff7b8..99a9d0da4b 100644
--- a/src/net.h
+++ b/src/net.h
@@ -947,6 +947,22 @@ public:
std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); }
+ /**
+ * Helper function to optionally log the IP address.
+ *
+ * @param[in] log_ip whether to include the IP address
+ * @return " peeraddr=..." or ""
+ */
+ std::string LogIP(bool log_ip) const;
+
+ /**
+ * Helper function to log disconnects.
+ *
+ * @param[in] log_ip whether to include the IP address
+ * @return "disconnecting peer=..." and optionally "peeraddr=..."
+ */
+ std::string DisconnectMsg(bool log_ip) const;
+
/** A ping-pong round trip has completed successfully. Update latest and minimum ping times. */
void PongReceived(std::chrono::microseconds ping_time) {
m_last_ping_time = ping_time;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index e503a68382..a19443c0f5 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2238,7 +2238,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
(((m_chainman.m_best_header != nullptr) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
!pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target
) {
- LogDebug(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "historical block serving limit reached, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -2247,7 +2247,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
if (!pfrom.HasPermission(NetPermissionFlags::NoBan) && (
(((peer.m_our_services & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((peer.m_our_services & NODE_NETWORK) != NODE_NETWORK) && (tip->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) {
- LogDebug(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold, %s\n", pfrom.DisconnectMsg(fLogIPs));
//disconnect node and prevent it from stalling (would otherwise wait for the missing block)
pfrom.fDisconnect = true;
return;
@@ -2270,9 +2270,9 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
std::vector<uint8_t> block_data;
if (!m_chainman.m_blockman.ReadRawBlockFromDisk(block_data, block_pos)) {
if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) {
- LogDebug(BCLog::NET, "Block was pruned before it could be read, disconnect peer=%s\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "Block was pruned before it could be read, %s\n", pfrom.DisconnectMsg(fLogIPs));
} else {
- LogError("Cannot load block from disk, disconnect peer=%d\n", pfrom.GetId());
+ LogError("Cannot load block from disk, %s\n", pfrom.DisconnectMsg(fLogIPs));
}
pfrom.fDisconnect = true;
return;
@@ -2284,9 +2284,9 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
if (!m_chainman.m_blockman.ReadBlockFromDisk(*pblockRead, block_pos)) {
if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) {
- LogDebug(BCLog::NET, "Block was pruned before it could be read, disconnect peer=%s\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "Block was pruned before it could be read, %s\n", pfrom.DisconnectMsg(fLogIPs));
} else {
- LogError("Cannot load block from disk, disconnect peer=%d\n", pfrom.GetId());
+ LogError("Cannot load block from disk, %s\n", pfrom.DisconnectMsg(fLogIPs));
}
pfrom.fDisconnect = true;
return;
@@ -2788,7 +2788,7 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, Peer& peer
// the minimum chain work, even if a peer has a chain past our tip,
// as an anti-DoS measure.
if (pfrom.IsOutboundOrBlockRelayConn()) {
- LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom.GetId());
+ LogInfo("outbound peer headers chain has insufficient work, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
}
}
@@ -3111,8 +3111,8 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer,
(filter_type == BlockFilterType::BASIC &&
(peer.m_our_services & NODE_COMPACT_FILTERS));
if (!supported_filter_type) {
- LogDebug(BCLog::NET, "peer %d requested unsupported block filter type: %d\n",
- node.GetId(), static_cast<uint8_t>(filter_type));
+ LogDebug(BCLog::NET, "peer requested unsupported block filter type: %d, %s\n",
+ static_cast<uint8_t>(filter_type), node.DisconnectMsg(fLogIPs));
node.fDisconnect = true;
return false;
}
@@ -3123,8 +3123,8 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer,
// Check that the stop block exists and the peer would be allowed to fetch it.
if (!stop_index || !BlockRequestAllowed(stop_index)) {
- LogDebug(BCLog::NET, "peer %d requested invalid block hash: %s\n",
- node.GetId(), stop_hash.ToString());
+ LogDebug(BCLog::NET, "peer requested invalid block hash: %s, %s\n",
+ stop_hash.ToString(), node.DisconnectMsg(fLogIPs));
node.fDisconnect = true;
return false;
}
@@ -3132,15 +3132,15 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer,
uint32_t stop_height = stop_index->nHeight;
if (start_height > stop_height) {
- LogDebug(BCLog::NET, "peer %d sent invalid getcfilters/getcfheaders with "
- "start height %d and stop height %d\n",
- node.GetId(), start_height, stop_height);
+ LogDebug(BCLog::NET, "peer sent invalid getcfilters/getcfheaders with "
+ "start height %d and stop height %d, %s\n",
+ start_height, stop_height, node.DisconnectMsg(fLogIPs));
node.fDisconnect = true;
return false;
}
if (stop_height - start_height >= max_height_diff) {
- LogDebug(BCLog::NET, "peer %d requested too many cfilters/cfheaders: %d / %d\n",
- node.GetId(), stop_height - start_height + 1, max_height_diff);
+ LogDebug(BCLog::NET, "peer requested too many cfilters/cfheaders: %d / %d, %s\n",
+ stop_height - start_height + 1, max_height_diff, node.DisconnectMsg(fLogIPs));
node.fDisconnect = true;
return false;
}
@@ -3407,14 +3407,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (pfrom.ExpectServicesFromConn() && !HasAllDesirableServiceFlags(nServices))
{
- LogDebug(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom.GetId(), nServices, GetDesirableServiceFlags(nServices));
+ LogDebug(BCLog::NET, "peer does not offer the expected services (%08x offered, %08x expected), %s\n",
+ nServices,
+ GetDesirableServiceFlags(nServices),
+ pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
if (nVersion < MIN_PEER_PROTO_VERSION) {
// disconnect from peers older than this proto version
- LogDebug(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom.GetId(), nVersion);
+ LogDebug(BCLog::NET, "peer using obsolete version %i, %s\n", nVersion, pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -3565,15 +3568,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
m_addrman.Good(pfrom.addr);
}
- std::string remoteAddr;
- if (fLogIPs)
- remoteAddr = ", peeraddr=" + pfrom.addr.ToStringAddrPort();
-
const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};
LogDebug(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s%s\n",
cleanSubVer, pfrom.nVersion,
peer->m_starting_height, addrMe.ToStringAddrPort(), fRelay, pfrom.GetId(),
- remoteAddr, (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
+ pfrom.LogIP(fLogIPs), (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
peer->m_time_offset = NodeSeconds{std::chrono::seconds{nTime}} - Now<NodeSeconds>();
if (!pfrom.IsInboundConn()) {
@@ -3591,7 +3590,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Feeler connections exist only to verify if address is online.
if (pfrom.IsFeelerConn()) {
- LogDebug(BCLog::NET, "feeler connection completed peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "feeler connection completed, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
}
return;
@@ -3617,7 +3616,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
pfrom.ConnectionTypeAsString(),
TransportTypeAsString(pfrom.m_transport->GetInfo().transport_type),
pfrom.nVersion.load(), peer->m_starting_height,
- pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToStringAddrPort()) : ""),
+ pfrom.GetId(), pfrom.LogIP(fLogIPs),
(mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
}
@@ -3695,7 +3694,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::WTXIDRELAY) {
if (pfrom.fSuccessfullyConnected) {
// Disconnect peers that send a wtxidrelay message after VERACK.
- LogDebug(BCLog::NET, "wtxidrelay received after verack from peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "wtxidrelay received after verack, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -3717,7 +3716,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::SENDADDRV2) {
if (pfrom.fSuccessfullyConnected) {
// Disconnect peers that send a SENDADDRV2 message after VERACK.
- LogDebug(BCLog::NET, "sendaddrv2 received after verack from peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "sendaddrv2 received after verack, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -3730,19 +3729,19 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// from switching announcement protocols after the connection is up.
if (msg_type == NetMsgType::SENDTXRCNCL) {
if (!m_txreconciliation) {
- LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl from peer=%d ignored, as our node does not have txreconciliation enabled\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "sendtxrcncl from peer=%d ignored, as our node does not have txreconciliation enabled\n", pfrom.GetId());
return;
}
if (pfrom.fSuccessfullyConnected) {
- LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received after verack from peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "sendtxrcncl received after verack, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
// Peer must not offer us reconciliations if we specified no tx relay support in VERSION.
if (RejectIncomingTxs(pfrom)) {
- LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received from peer=%d to which we indicated no tx relay; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "sendtxrcncl received to which we indicated no tx relay, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -3752,7 +3751,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// eliminates them, so that this flag fully represents what we are looking for.
const auto* tx_relay = peer->GetTxRelay();
if (!tx_relay || !WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs)) {
- LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received from peer=%d which indicated no tx relay to us; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "sendtxrcncl received which indicated no tx relay to us, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -3765,16 +3764,16 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
peer_txreconcl_version, remote_salt);
switch (result) {
case ReconciliationRegisterResult::NOT_FOUND:
- LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "Ignore unexpected txreconciliation signal from peer=%d\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "Ignore unexpected txreconciliation signal from peer=%d\n", pfrom.GetId());
break;
case ReconciliationRegisterResult::SUCCESS:
break;
case ReconciliationRegisterResult::ALREADY_REGISTERED:
- LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "txreconciliation protocol violation from peer=%d (sendtxrcncl received from already registered peer); disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "txreconciliation protocol violation (sendtxrcncl received from already registered peer), %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
case ReconciliationRegisterResult::PROTOCOL_VIOLATION:
- LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "txreconciliation protocol violation from peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "txreconciliation protocol violation, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -3877,7 +3876,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements
if (pfrom.IsAddrFetchConn() && vAddr.size() > 1) {
- LogDebug(BCLog::NET, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "addrfetch connection completed, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
}
return;
@@ -3927,7 +3926,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
} else if (inv.IsGenTxMsg()) {
if (reject_tx_invs) {
- LogDebug(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
+ LogDebug(BCLog::NET, "transaction (%s) inv sent in violation of protocol, %s\n", inv.hash.ToString(), pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -4004,7 +4003,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
vRecv >> locator >> hashStop;
if (locator.vHave.size() > MAX_LOCATOR_SZ) {
- LogDebug(BCLog::NET, "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId());
+ LogDebug(BCLog::NET, "getblocks locator size %lld > %d, %s\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -4126,7 +4125,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
vRecv >> locator >> hashStop;
if (locator.vHave.size() > MAX_LOCATOR_SZ) {
- LogDebug(BCLog::NET, "getheaders locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId());
+ LogDebug(BCLog::NET, "getheaders locator size %lld > %d, %s\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -4667,7 +4666,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
{
if (!pfrom.HasPermission(NetPermissionFlags::NoBan))
{
- LogDebug(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "mempool request with bloom filters disabled, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
}
return;
@@ -4677,7 +4676,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
{
if (!pfrom.HasPermission(NetPermissionFlags::NoBan))
{
- LogDebug(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "mempool request with bandwidth limit reached, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
}
return;
@@ -4767,7 +4766,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::FILTERLOAD) {
if (!(peer->m_our_services & NODE_BLOOM)) {
- LogDebug(BCLog::NET, "filterload received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "filterload received despite not offering bloom services, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -4792,7 +4791,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::FILTERADD) {
if (!(peer->m_our_services & NODE_BLOOM)) {
- LogDebug(BCLog::NET, "filteradd received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "filteradd received despite not offering bloom services, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -4820,7 +4819,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::FILTERCLEAR) {
if (!(peer->m_our_services & NODE_BLOOM)) {
- LogDebug(BCLog::NET, "filterclear received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
+ LogDebug(BCLog::NET, "filterclear received despite not offering bloom services, %s\n", pfrom.DisconnectMsg(fLogIPs));
pfrom.fDisconnect = true;
return;
}
@@ -5041,7 +5040,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, Peer& peer, std::chrono::seco
// message to give the peer a chance to update us.
if (state.m_chain_sync.m_sent_getheaders) {
// They've run out of time to catch up!
- LogPrintf("Disconnecting outbound peer %d for old chain, best known block = %s\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>");
+ LogInfo("Outbound peer has old chain, best known block = %s, %s\n", state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", pto.DisconnectMsg(fLogIPs));
pto.fDisconnect = true;
} else {
assert(state.m_chain_sync.m_work_header);
@@ -5442,7 +5441,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
const auto current_time{GetTime<std::chrono::microseconds>()};
if (pto->IsAddrFetchConn() && current_time - pto->m_connected > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) {
- LogDebug(BCLog::NET, "addrfetch connection timeout; disconnecting peer=%d\n", pto->GetId());
+ LogDebug(BCLog::NET, "addrfetch connection timeout, %s\n", pto->DisconnectMsg(fLogIPs));
pto->fDisconnect = true;
return true;
}
@@ -5786,7 +5785,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
// should only happen during initial block download.
- LogPrintf("Peer=%d%s is stalling block download, disconnecting\n", pto->GetId(), fLogIPs ? strprintf(" peeraddr=%s", pto->addr.ToStringAddrPort()) : "");
+ LogInfo("Peer is stalling block download, %s\n", pto->DisconnectMsg(fLogIPs));
pto->fDisconnect = true;
// Increase timeout for the next peer so that we don't disconnect multiple peers if our own
// bandwidth is insufficient.
@@ -5805,7 +5804,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
int nOtherPeersWithValidatedDownloads = m_peers_downloading_from - 1;
if (current_time > state.m_downloading_since + std::chrono::seconds{consensusParams.nPowTargetSpacing} * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) {
- LogPrintf("Timeout downloading block %s from peer=%d%s, disconnecting\n", queuedBlock.pindex->GetBlockHash().ToString(), pto->GetId(), fLogIPs ? strprintf(" peeraddr=%s", pto->addr.ToStringAddrPort()) : "");
+ LogInfo("Timeout downloading block %s, %s\n", queuedBlock.pindex->GetBlockHash().ToString(), pto->DisconnectMsg(fLogIPs));
pto->fDisconnect = true;
return true;
}
@@ -5821,11 +5820,11 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// disconnect our sync peer for stalling; we have bigger
// problems if we can't get any outbound peers.
if (!pto->HasPermission(NetPermissionFlags::NoBan)) {
- LogPrintf("Timeout downloading headers from peer=%d%s, disconnecting\n", pto->GetId(), fLogIPs ? strprintf(" peeraddr=%s", pto->addr.ToStringAddrPort()) : "");
+ LogInfo("Timeout downloading headers, %s\n", pto->DisconnectMsg(fLogIPs));
pto->fDisconnect = true;
return true;
} else {
- LogPrintf("Timeout downloading headers from noban peer=%d%s, not disconnecting\n", pto->GetId(), fLogIPs ? strprintf(" peeraddr=%s", pto->addr.ToStringAddrPort()) : "");
+ LogInfo("Timeout downloading headers from noban peer, not %s\n", pto->DisconnectMsg(fLogIPs));
// Reset the headers sync state so that we have a
// chance to try downloading from a different peer.
// Note: this will also result in at least one more
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index e4ae9400e3..f3b8c6a072 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -324,7 +324,7 @@ public:
}
double getVerificationProgress() override
{
- return GuessVerificationProgress(chainman().GetParams().TxData(), WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()));
+ return chainman().GuessVerificationProgress(WITH_LOCK(chainman().GetMutex(), return chainman().ActiveChain().Tip()));
}
bool isInitialBlockDownload() override
{
@@ -406,9 +406,9 @@ public:
}
std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
{
- return MakeSignalHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
+ return MakeSignalHandler(::uiInterface.NotifyBlockTip_connect([fn, this](SynchronizationState sync_state, const CBlockIndex* block) {
fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
- GuessVerificationProgress(Params().TxData(), block));
+ chainman().GuessVerificationProgress(block));
}));
}
std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
@@ -639,8 +639,8 @@ public:
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
double guessVerificationProgress(const uint256& block_hash) override
{
- LOCK(::cs_main);
- return GuessVerificationProgress(chainman().GetParams().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash));
+ LOCK(chainman().GetMutex());
+ return chainman().GuessVerificationProgress(chainman().m_blockman.LookupBlockIndex(block_hash));
}
bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
{
@@ -913,19 +913,17 @@ public:
std::vector<uint256> getCoinbaseMerklePath() override
{
- return BlockMerkleBranch(m_block_template->block);
+ return TransactionMerklePath(m_block_template->block, 0);
}
- bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CMutableTransaction coinbase) override
+ bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CTransactionRef coinbase) override
{
CBlock block{m_block_template->block};
- auto cb = MakeTransactionRef(std::move(coinbase));
-
if (block.vtx.size() == 0) {
- block.vtx.push_back(cb);
+ block.vtx.push_back(coinbase);
} else {
- block.vtx[0] = cb;
+ block.vtx[0] = coinbase;
}
block.nVersion = version;
@@ -973,7 +971,9 @@ public:
{
WAIT_LOCK(notifications().m_tip_block_mutex, lock);
notifications().m_tip_block_cv.wait_for(lock, timeout, [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) {
- return (notifications().m_tip_block != current_tip && notifications().m_tip_block != uint256::ZERO) || chainman().m_interrupt;
+ // We need to wait for m_tip_block to be set AND for the value
+ // to differ from the current_tip value.
+ return (notifications().TipBlock() && notifications().TipBlock() != current_tip) || chainman().m_interrupt;
});
}
// Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
@@ -981,34 +981,11 @@ public:
return BlockRef{chainman().ActiveChain().Tip()->GetBlockHash(), chainman().ActiveChain().Tip()->nHeight};
}
- bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override
- {
- return chainman().ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/new_block);
- }
-
- unsigned int getTransactionsUpdated() override
- {
- return context()->mempool->GetTransactionsUpdated();
- }
-
- bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override
- {
- LOCK(cs_main);
- CBlockIndex* tip{chainman().ActiveChain().Tip()};
- // Fail if the tip updated before the lock was taken
- if (block.hashPrevBlock != tip->GetBlockHash()) {
- state.Error("Block does not connect to current chain tip.");
- return false;
- }
-
- return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root);
- }
-
- std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override
+ std::unique_ptr<BlockTemplate> createNewBlock(const BlockCreateOptions& options) override
{
BlockAssembler::Options assemble_options{options};
ApplyArgsManOptions(*Assert(m_node.args), assemble_options);
- return std::make_unique<BlockTemplateImpl>(BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key), m_node);
+ return std::make_unique<BlockTemplateImpl>(BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(), m_node);
}
NodeContext* context() override { return &m_node; }
diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp
index a09803165c..550ffe74c4 100644
--- a/src/node/kernel_notifications.cpp
+++ b/src/node/kernel_notifications.cpp
@@ -52,6 +52,7 @@ kernel::InterruptResult KernelNotifications::blockTip(SynchronizationState state
{
{
LOCK(m_tip_block_mutex);
+ Assume(index.GetBlockHash() != uint256::ZERO);
m_tip_block = index.GetBlockHash();
m_tip_block_cv.notify_all();
}
@@ -99,6 +100,13 @@ void KernelNotifications::fatalError(const bilingual_str& message)
m_exit_status, message, &m_warnings);
}
+std::optional<uint256> KernelNotifications::TipBlock()
+{
+ AssertLockHeld(m_tip_block_mutex);
+ return m_tip_block;
+};
+
+
void ReadNotificationArgs(const ArgsManager& args, KernelNotifications& notifications)
{
if (auto value{args.GetIntArg("-stopatheight")}) notifications.m_stop_at_height = *value;
diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h
index 35070b5285..f4174381da 100644
--- a/src/node/kernel_notifications.h
+++ b/src/node/kernel_notifications.h
@@ -59,12 +59,14 @@ public:
//! The block for which the last blockTip notification was received.
//! It's first set when the tip is connected during node initialization.
//! Might be unset during an early shutdown.
- uint256 m_tip_block GUARDED_BY(m_tip_block_mutex){uint256::ZERO};
+ std::optional<uint256> TipBlock() EXCLUSIVE_LOCKS_REQUIRED(m_tip_block_mutex);
private:
const std::function<bool()>& m_shutdown_request;
std::atomic<int>& m_exit_status;
node::Warnings& m_warnings;
+
+ std::optional<uint256> m_tip_block GUARDED_BY(m_tip_block_mutex);
};
void ReadNotificationArgs(const ArgsManager& args, KernelNotifications& notifications);
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index 790ee1c146..5d7304b597 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -106,7 +106,7 @@ void BlockAssembler::resetBlock()
nFees = 0;
}
-std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
+std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock()
{
const auto time_start{SteadyClock::now()};
@@ -151,7 +151,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
coinbaseTx.vin.resize(1);
coinbaseTx.vin[0].prevout.SetNull();
coinbaseTx.vout.resize(1);
- coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
+ coinbaseTx.vout[0].scriptPubKey = m_options.coinbase_output_script;
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
diff --git a/src/node/miner.h b/src/node/miner.h
index 25ce110b34..f6461a8d55 100644
--- a/src/node/miner.h
+++ b/src/node/miner.h
@@ -169,8 +169,8 @@ public:
explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options);
- /** Construct a new block template with coinbase to scriptPubKeyIn */
- std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
+ /** Construct a new block template */
+ std::unique_ptr<CBlockTemplate> CreateNewBlock();
inline static std::optional<int64_t> m_last_block_num_txs{};
inline static std::optional<int64_t> m_last_block_weight{};
diff --git a/src/node/types.h b/src/node/types.h
index 1302f1b127..4b0de084ab 100644
--- a/src/node/types.h
+++ b/src/node/types.h
@@ -3,8 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//! @file node/types.h is a home for public enum and struct type definitions
-//! that are used by internally by node code, but also used externally by wallet
-//! or GUI code.
+//! that are used internally by node code, but also used externally by wallet,
+//! mining or GUI code.
//!
//! This file is intended to define only simple types that do not have external
//! dependencies. More complicated types should be defined in dedicated header
@@ -14,6 +14,7 @@
#define BITCOIN_NODE_TYPES_H
#include <cstddef>
+#include <script/script.h>
namespace node {
enum class TransactionError {
@@ -43,6 +44,22 @@ struct BlockCreateOptions {
* transaction outputs.
*/
size_t coinbase_output_max_additional_sigops{400};
+ /**
+ * Script to put in the coinbase transaction. The default is an
+ * anyone-can-spend dummy.
+ *
+ * Should only be used for tests, when the default doesn't suffice.
+ *
+ * Note that higher level code like the getblocktemplate RPC may omit the
+ * coinbase transaction entirely. It's instead constructed by pool software
+ * using fields like coinbasevalue, coinbaseaux and default_witness_commitment.
+ * This software typically also controls the payout outputs, even for solo
+ * mining.
+ *
+ * The size and sigops are not checked against
+ * coinbase_max_additional_weight and coinbase_output_max_additional_sigops.
+ */
+ CScript coinbase_output_script{CScript() << OP_TRUE};
};
} // namespace node
diff --git a/src/policy/packages.h b/src/policy/packages.h
index 3050320122..4b2350edac 100644
--- a/src/policy/packages.h
+++ b/src/policy/packages.h
@@ -89,8 +89,9 @@ bool IsChildWithParents(const Package& package);
*/
bool IsChildWithParentsTree(const Package& package);
-/** Get the hash of these transactions' wtxids, concatenated in lexicographical order (treating the
- * wtxids as little endian encoded uint256, smallest to largest). */
+/** Get the hash of the concatenated wtxids of transactions, with wtxids
+ * treated as a little-endian numbers and sorted in ascending numeric order.
+ */
uint256 GetPackageHash(const std::vector<CTransactionRef>& transactions);
#endif // BITCOIN_POLICY_PACKAGES_H
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index b634dea561..bc76361fba 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -71,7 +71,7 @@ std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx,
// descendants (i.e. if multiple conflicts share a descendant, it will be counted multiple
// times), but we just want to be conservative to avoid doing too much work.
if (nConflictingCount > MAX_REPLACEMENT_CANDIDATES) {
- return strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n",
+ return strprintf("rejecting replacement %s; too many potential replacements (%d > %d)",
txid.ToString(),
nConflictingCount,
MAX_REPLACEMENT_CANDIDATES);
diff --git a/src/random.cpp b/src/random.cpp
index 9b5131023f..4265c48022 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -671,9 +671,11 @@ void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept
{
GetRNGState().MakeDeterministic(seed);
}
+std::atomic<bool> g_used_g_prng{false}; // Only accessed from tests
void GetRandBytes(Span<unsigned char> bytes) noexcept
{
+ g_used_g_prng = true;
ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST, /*always_use_real_rng=*/false);
}
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 41673ee21d..823d2303c8 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1307,6 +1307,7 @@ RPCHelpMan getblockchaininfo()
{RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "height of the last block pruned, plus one (only present if pruning is enabled)"},
{RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"},
{RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"},
+ {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "the block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"},
(IsDeprecatedRPCEnabled("warnings") ?
RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
@@ -1336,7 +1337,7 @@ RPCHelpMan getblockchaininfo()
obj.pushKV("difficulty", GetDifficulty(tip));
obj.pushKV("time", tip.GetBlockTime());
obj.pushKV("mediantime", tip.GetMedianTimePast());
- obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
+ obj.pushKV("verificationprogress", chainman.GuessVerificationProgress(&tip));
obj.pushKV("initialblockdownload", chainman.IsInitialBlockDownload());
obj.pushKV("chainwork", tip.nChainWork.GetHex());
obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
@@ -1351,6 +1352,11 @@ RPCHelpMan getblockchaininfo()
obj.pushKV("prune_target_size", chainman.m_blockman.GetPruneTarget());
}
}
+ if (chainman.GetParams().GetChainType() == ChainType::SIGNET) {
+ const std::vector<uint8_t>& signet_challenge =
+ chainman.GetParams().GetConsensus().signet_challenge;
+ obj.pushKV("signet_challenge", HexStr(signet_challenge));
+ }
NodeContext& node = EnsureAnyNodeContext(request.context);
obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));
@@ -3338,7 +3344,7 @@ return RPCHelpMan{
data.pushKV("blocks", (int)chain.Height());
data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
data.pushKV("difficulty", GetDifficulty(*tip));
- data.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
+ data.pushKV("verificationprogress", chainman.GuessVerificationProgress(tip));
data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
if (cs.m_from_snapshot_blockhash) {
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index 6d462a7e85..52260d5794 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -146,7 +146,8 @@ static RPCHelpMan testmempoolaccept()
{RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
}},
}},
- {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"},
+ {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection reason (only present when 'allowed' is false)"},
+ {RPCResult::Type::STR, "reject-details", /*optional=*/true, "Rejection details (only present when 'allowed' is false and rejection details exist)"},
}},
}
},
@@ -245,6 +246,7 @@ static RPCHelpMan testmempoolaccept()
result_inner.pushKV("reject-reason", "missing-inputs");
} else {
result_inner.pushKV("reject-reason", state.GetRejectReason());
+ result_inner.pushKV("reject-details", state.ToString());
}
}
rpc_result.push_back(std::move(result_inner));
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 60828c1711..7e5936fddf 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2022 The Bitcoin Core developers
+// Copyright (c) 2009-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -131,7 +131,7 @@ static RPCHelpMan getnetworkhashps()
};
}
-static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock&& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
+static bool GenerateBlock(ChainstateManager& chainman, CBlock&& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
{
block_out.reset();
block.hashMerkleRoot = BlockMerkleRoot(block);
@@ -151,22 +151,22 @@ static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock&& b
if (!process_new_block) return true;
- if (!miner.processNewBlock(block_out, nullptr)) {
+ if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
}
return true;
}
-static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
+static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const CScript& coinbase_output_script, int nGenerate, uint64_t nMaxTries)
{
UniValue blockHashes(UniValue::VARR);
while (nGenerate > 0 && !chainman.m_interrupt) {
- std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock(coinbase_script));
+ std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock({ .coinbase_output_script = coinbase_output_script }));
CHECK_NONFATAL(block_template);
std::shared_ptr<const CBlock> block_out;
- if (!GenerateBlock(chainman, miner, block_template->getBlock(), nMaxTries, block_out, /*process_new_block=*/true)) {
+ if (!GenerateBlock(chainman, block_template->getBlock(), nMaxTries, block_out, /*process_new_block=*/true)) {
break;
}
@@ -236,9 +236,9 @@ static RPCHelpMan generatetodescriptor()
const auto num_blocks{self.Arg<int>("num_blocks")};
const auto max_tries{self.Arg<uint64_t>("maxtries")};
- CScript coinbase_script;
+ CScript coinbase_output_script;
std::string error;
- if (!getScriptFromDescriptor(self.Arg<std::string>("descriptor"), coinbase_script, error)) {
+ if (!getScriptFromDescriptor(self.Arg<std::string>("descriptor"), coinbase_output_script, error)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
}
@@ -246,7 +246,7 @@ static RPCHelpMan generatetodescriptor()
Mining& miner = EnsureMining(node);
ChainstateManager& chainman = EnsureChainman(node);
- return generateBlocks(chainman, miner, coinbase_script, num_blocks, max_tries);
+ return generateBlocks(chainman, miner, coinbase_output_script, num_blocks, max_tries);
},
};
}
@@ -292,9 +292,9 @@ static RPCHelpMan generatetoaddress()
Mining& miner = EnsureMining(node);
ChainstateManager& chainman = EnsureChainman(node);
- CScript coinbase_script = GetScriptForDestination(destination);
+ CScript coinbase_output_script = GetScriptForDestination(destination);
- return generateBlocks(chainman, miner, coinbase_script, num_blocks, max_tries);
+ return generateBlocks(chainman, miner, coinbase_output_script, num_blocks, max_tries);
},
};
}
@@ -328,16 +328,16 @@ static RPCHelpMan generateblock()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const auto address_or_descriptor = request.params[0].get_str();
- CScript coinbase_script;
+ CScript coinbase_output_script;
std::string error;
- if (!getScriptFromDescriptor(address_or_descriptor, coinbase_script, error)) {
+ if (!getScriptFromDescriptor(address_or_descriptor, coinbase_output_script, error)) {
const auto destination = DecodeDestination(address_or_descriptor);
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address or descriptor");
}
- coinbase_script = GetScriptForDestination(destination);
+ coinbase_output_script = GetScriptForDestination(destination);
}
NodeContext& node = EnsureAnyNodeContext(request.context);
@@ -371,29 +371,30 @@ static RPCHelpMan generateblock()
ChainstateManager& chainman = EnsureChainman(node);
{
- std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock(coinbase_script, {.use_mempool = false})};
- CHECK_NONFATAL(block_template);
+ LOCK(chainman.GetMutex());
+ {
+ std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock({.use_mempool = false, .coinbase_output_script = coinbase_output_script})};
+ CHECK_NONFATAL(block_template);
- block = block_template->getBlock();
- }
+ block = block_template->getBlock();
+ }
- CHECK_NONFATAL(block.vtx.size() == 1);
+ CHECK_NONFATAL(block.vtx.size() == 1);
- // Add transactions
- block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
- RegenerateCommitments(block, chainman);
+ // Add transactions
+ block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
+ RegenerateCommitments(block, chainman);
- {
BlockValidationState state;
- if (!miner.testBlockValidity(block, /*check_merkle_root=*/false, state)) {
- throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("testBlockValidity failed: %s", state.ToString()));
+ if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) {
+ throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
}
}
std::shared_ptr<const CBlock> block_out;
uint64_t max_tries{DEFAULT_MAX_TRIES};
- if (!GenerateBlock(chainman, miner, std::move(block), max_tries, block_out, process_new_block) || !block_out) {
+ if (!GenerateBlock(chainman, std::move(block), max_tries, block_out, process_new_block) || !block_out) {
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
}
@@ -424,6 +425,7 @@ static RPCHelpMan getmininginfo()
{RPCResult::Type::NUM, "networkhashps", "The network hashes per second"},
{RPCResult::Type::NUM, "pooledtx", "The size of the mempool"},
{RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"},
+ {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "The block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"},
(IsDeprecatedRPCEnabled("warnings") ?
RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
@@ -453,6 +455,11 @@ static RPCHelpMan getmininginfo()
obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));
obj.pushKV("pooledtx", (uint64_t)mempool.size());
obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
+ if (chainman.GetParams().GetChainType() == ChainType::SIGNET) {
+ const std::vector<uint8_t>& signet_challenge =
+ chainman.GetParams().GetConsensus().signet_challenge;
+ obj.pushKV("signet_challenge", HexStr(signet_challenge));
+ }
obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));
return obj;
},
@@ -626,8 +633,8 @@ static RPCHelpMan getblocktemplate()
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "data", "transaction data encoded in hexadecimal (byte-for-byte)"},
- {RPCResult::Type::STR_HEX, "txid", "transaction id encoded in little-endian hexadecimal"},
- {RPCResult::Type::STR_HEX, "hash", "hash encoded in little-endian hexadecimal (including witness data)"},
+ {RPCResult::Type::STR_HEX, "txid", "transaction hash excluding witness data, shown in byte-reversed hex"},
+ {RPCResult::Type::STR_HEX, "hash", "transaction hash including witness data, shown in byte-reversed hex"},
{RPCResult::Type::ARR, "depends", "array of numbers",
{
{RPCResult::Type::NUM, "", "transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is"},
@@ -709,12 +716,12 @@ static RPCHelpMan getblocktemplate()
return "duplicate-inconclusive";
}
- // testBlockValidity only supports blocks built on the current Tip
+ // TestBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != tip) {
return "inconclusive-not-best-prevblk";
}
BlockValidationState state;
- miner.testBlockValidity(block, /*check_merkle_root=*/true, state);
+ TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/true);
return BIP22ValidationResult(state);
}
@@ -742,6 +749,7 @@ static RPCHelpMan getblocktemplate()
}
static unsigned int nTransactionsUpdatedLast;
+ const CTxMemPool& mempool = EnsureMemPool(node);
if (!lpval.isNull())
{
@@ -772,7 +780,7 @@ static RPCHelpMan getblocktemplate()
tip = miner.waitTipChanged(hashWatchedChain, checktxtime).hash;
// Timeout: Check transactions for update
// without holding the mempool lock to avoid deadlocks
- if (miner.getTransactionsUpdated() != nTransactionsUpdatedLastLP)
+ if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
break;
checktxtime = std::chrono::seconds(10);
}
@@ -803,19 +811,18 @@ static RPCHelpMan getblocktemplate()
static int64_t time_start;
static std::unique_ptr<BlockTemplate> block_template;
if (!pindexPrev || pindexPrev->GetBlockHash() != tip ||
- (miner.getTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
+ (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
pindexPrev = nullptr;
// Store the pindexBest used before createNewBlock, to avoid races
- nTransactionsUpdatedLast = miner.getTransactionsUpdated();
+ nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrevNew = chainman.m_blockman.LookupBlockIndex(tip);
time_start = GetTime();
// Create new block
- CScript scriptDummy = CScript() << OP_TRUE;
- block_template = miner.createNewBlock(scriptDummy);
+ block_template = miner.createNewBlock();
CHECK_NONFATAL(block_template);
@@ -1033,13 +1040,10 @@ static RPCHelpMan submitblock()
}
}
- NodeContext& node = EnsureAnyNodeContext(request.context);
- Mining& miner = EnsureMining(node);
-
bool new_block;
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
CHECK_NONFATAL(chainman.m_options.signals)->RegisterSharedValidationInterface(sc);
- bool accepted = miner.processNewBlock(blockptr, /*new_block=*/&new_block);
+ bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
CHECK_NONFATAL(chainman.m_options.signals)->UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
return "duplicate";
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 5026470edc..2e1a30744e 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -1761,7 +1761,7 @@ struct KeyParser {
std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
{
using namespace script;
-
+ Assume(ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH || ctx == ParseScriptContext::P2TR);
std::vector<std::unique_ptr<DescriptorImpl>> ret;
auto expr = Expr(sp);
if (Func("pk", expr)) {
@@ -1787,10 +1787,6 @@ std::vector<std::unique_ptr<DescriptorImpl>> ParseScript(uint32_t& key_exp_index
ret.emplace_back(std::make_unique<PKHDescriptor>(std::move(pubkey)));
}
return ret;
- } else if (ctx != ParseScriptContext::P2TR && Func("pkh", expr)) {
- // Under Taproot, always the Miniscript parser deal with it.
- error = "Can only have pkh at top level, in sh(), wsh(), or in tr()";
- return {};
}
if (ctx == ParseScriptContext::TOP && Func("combo", expr)) {
auto pubkeys = ParsePubkey(key_exp_index, expr, ctx, out, error);
diff --git a/src/script/miniscript.h b/src/script/miniscript.h
index e739d8031f..75f978457c 100644
--- a/src/script/miniscript.h
+++ b/src/script/miniscript.h
@@ -1798,7 +1798,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx)
// Get threshold
int next_comma = FindNextChar(in, ',');
if (next_comma < 1) return false;
- const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.begin(), next_comma))};
+ const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
if (!k_to_integral.has_value()) return false;
const int64_t k{k_to_integral.value()};
in = in.subspan(next_comma + 1);
@@ -1954,7 +1954,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx)
} else if (Const("after(", in)) {
int arg_size = FindNextChar(in, ')');
if (arg_size < 1) return {};
- const auto num{ToIntegral<int64_t>(std::string_view(in.begin(), arg_size))};
+ const auto num{ToIntegral<int64_t>(std::string_view(in.data(), arg_size))};
if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num));
in = in.subspan(arg_size + 1);
@@ -1962,7 +1962,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx)
} else if (Const("older(", in)) {
int arg_size = FindNextChar(in, ')');
if (arg_size < 1) return {};
- const auto num{ToIntegral<int64_t>(std::string_view(in.begin(), arg_size))};
+ const auto num{ToIntegral<int64_t>(std::string_view(in.data(), arg_size))};
if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {};
constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num));
in = in.subspan(arg_size + 1);
@@ -1974,7 +1974,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx)
} else if (Const("thresh(", in)) {
int next_comma = FindNextChar(in, ',');
if (next_comma < 1) return {};
- const auto k{ToIntegral<int64_t>(std::string_view(in.begin(), next_comma))};
+ const auto k{ToIntegral<int64_t>(std::string_view(in.data(), next_comma))};
if (!k.has_value() || *k < 1) return {};
in = in.subspan(next_comma + 1);
// n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH
diff --git a/src/script/solver.h b/src/script/solver.h
index 5a7b685a6f..5b945477c9 100644
--- a/src/script/solver.h
+++ b/src/script/solver.h
@@ -10,6 +10,7 @@
#include <attributes.h>
#include <script/script.h>
+#include <span.h>
#include <string>
#include <optional>
@@ -17,7 +18,6 @@
#include <vector>
class CPubKey;
-template <typename C> class Span;
enum class TxoutType {
NONSTANDARD,
diff --git a/src/serialize.h b/src/serialize.h
index 2af998f3c5..6384c95dba 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -264,6 +264,7 @@ template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_wri
template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); }
template <typename Stream, BasicByte B, int N> void Serialize(Stream& s, const B (&a)[N]) { s.write(MakeByteSpan(a)); }
template <typename Stream, BasicByte B, std::size_t N> void Serialize(Stream& s, const std::array<B, N>& a) { s.write(MakeByteSpan(a)); }
+template <typename Stream, BasicByte B, std::size_t N> void Serialize(Stream& s, std::span<B, N> span) { s.write(std::as_bytes(span)); }
template <typename Stream, BasicByte B> void Serialize(Stream& s, Span<B> span) { s.write(AsBytes(span)); }
template <typename Stream, CharNotInt8 V> void Unserialize(Stream&, V) = delete; // char serialization forbidden. Use uint8_t or int8_t
@@ -278,6 +279,7 @@ template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a =
template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); }
template <typename Stream, BasicByte B, int N> void Unserialize(Stream& s, B (&a)[N]) { s.read(MakeWritableByteSpan(a)); }
template <typename Stream, BasicByte B, std::size_t N> void Unserialize(Stream& s, std::array<B, N>& a) { s.read(MakeWritableByteSpan(a)); }
+template <typename Stream, BasicByte B, std::size_t N> void Unserialize(Stream& s, std::span<B, N> span) { s.read(std::as_writable_bytes(span)); }
template <typename Stream, BasicByte B> void Unserialize(Stream& s, Span<B> span) { s.read(AsWritableBytes(span)); }
template <typename Stream> inline void Serialize(Stream& s, bool a) { uint8_t f = a; ser_writedata8(s, f); }
diff --git a/src/span.h b/src/span.h
index 3c5028f0b7..93718f6189 100644
--- a/src/span.h
+++ b/src/span.h
@@ -248,9 +248,8 @@ template <typename T>
T& SpanPopBack(Span<T>& span)
{
size_t size = span.size();
- ASSERT_IF_DEBUG(size > 0);
- T& back = span[size - 1];
- span = Span<T>(span.data(), size - 1);
+ T& back = span.back();
+ span = span.first(size - 1);
return back;
}
diff --git a/src/streams.h b/src/streams.h
index 64dbfbff14..e5316da7e7 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -79,7 +79,7 @@ public:
memcpy(vchData.data() + nPos, src.data(), nOverwrite);
}
if (nOverwrite < src.size()) {
- vchData.insert(vchData.end(), UCharCast(src.data()) + nOverwrite, UCharCast(src.end()));
+ vchData.insert(vchData.end(), UCharCast(src.data()) + nOverwrite, UCharCast(src.data() + src.size()));
}
nPos += src.size();
}
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index 4395567722..e7ffc9e201 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
+// Copyright (c) 2009-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -74,7 +74,7 @@ secure_unique_ptr<T> make_secure_unique(Args&&... as)
// initialize in place, and return as secure_unique_ptr
try {
- return secure_unique_ptr<T>(new (p) T(std::forward(as)...));
+ return secure_unique_ptr<T>(new (p) T(std::forward<Args>(as)...));
} catch (...) {
secure_allocator<T>().deallocate(p, 1);
throw;
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index ed73e44901..859b913206 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -18,7 +18,6 @@ generate_header_from_raw(data/asmap.raw test::data)
# SOURCES property is processed to gather test suite macros.
add_executable(test_bitcoin
main.cpp
- $<TARGET_OBJECTS:bitcoin_consensus>
${CMAKE_CURRENT_BINARY_DIR}/data/asmap.raw.h
${CMAKE_CURRENT_BINARY_DIR}/data/base58_encode_decode.json.h
${CMAKE_CURRENT_BINARY_DIR}/data/bip341_wallet_vectors.json.h
@@ -151,6 +150,7 @@ target_link_libraries(test_bitcoin
test_util
bitcoin_cli
bitcoin_node
+ bitcoin_consensus
minisketch
secp256k1
Boost::headers
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index 48ae874fcd..4b576bb084 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -67,8 +67,9 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev,
const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey)
{
- BlockAssembler::Options options;
- std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(scriptPubKey);
+ BlockAssembler::Options options;
+ options.coinbase_output_script = scriptPubKey;
+ std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock();
CBlock& block = pblocktemplate->block;
block.hashPrevBlock = prev->GetBlockHash();
block.nTime = prev->nTime + 1;
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index 24b8f2f793..288ffc66eb 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -161,7 +161,8 @@ void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int
// We must be able to estimate the max satisfaction size for any solvable descriptor top descriptor (but combo).
const bool is_nontop_or_nonsolvable{!parse_priv->IsSolvable() || !parse_priv->GetOutputType()};
const auto max_sat_maxsig{parse_priv->MaxSatisfactionWeight(true)};
- const auto max_sat_nonmaxsig{parse_priv->MaxSatisfactionWeight(true)};
+ const auto max_sat_nonmaxsig{parse_priv->MaxSatisfactionWeight(false)};
+ BOOST_CHECK(max_sat_nonmaxsig <= max_sat_maxsig);
const auto max_elems{parse_priv->MaxSatisfactionElems()};
const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
BOOST_CHECK_MESSAGE(is_input_size_info_set || is_nontop_or_nonsolvable, prv);
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index 53dd7215d2..dedea85080 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -41,6 +41,7 @@ void initialize_addrman()
FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
DataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
@@ -113,6 +114,7 @@ void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
FUZZ_TARGET(addrman, .init = initialize_addrman)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
@@ -197,6 +199,7 @@ FUZZ_TARGET(addrman, .init = initialize_addrman)
// Check that serialize followed by unserialize produces the same addrman.
FUZZ_TARGET(addrman_serdeser, .init = initialize_addrman)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index 4165cc6b2c..bbe8e12b2f 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -42,6 +42,7 @@ static bool operator==(const CBanEntry& lhs, const CBanEntry& rhs)
FUZZ_TARGET(banman, .init = initialize_banman)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
fs::path banlist_file = gArgs.GetDataDirNet() / "fuzzed_banlist";
diff --git a/src/test/fuzz/blockfilter.cpp b/src/test/fuzz/blockfilter.cpp
index 3adc114515..17e99ac94d 100644
--- a/src/test/fuzz/blockfilter.cpp
+++ b/src/test/fuzz/blockfilter.cpp
@@ -6,6 +6,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/random.h>
#include <cstdint>
#include <optional>
@@ -14,6 +15,7 @@
FUZZ_TARGET(blockfilter)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const std::optional<BlockFilter> block_filter = ConsumeDeserializable<BlockFilter>(fuzzed_data_provider);
if (!block_filter) {
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 20a60b098f..a62d227da8 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -36,6 +36,7 @@ void initialize_connman()
FUZZ_TARGET(connman, .init = initialize_connman)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
auto netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
index 3c81e0f3fe..e4e4723c74 100644
--- a/src/test/fuzz/fuzz.cpp
+++ b/src/test/fuzz/fuzz.cpp
@@ -6,6 +6,7 @@
#include <netaddress.h>
#include <netbase.h>
+#include <test/fuzz/util/check_globals.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <util/check.h>
@@ -78,6 +79,12 @@ void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target,
static std::string_view g_fuzz_target;
static const TypeTestOneInput* g_test_one_input{nullptr};
+inline void test_one_input(FuzzBufferType buffer)
+{
+ CheckGlobals check{};
+ (*Assert(g_test_one_input))(buffer);
+}
+
const std::function<std::string()> G_TEST_GET_FULL_NAME{[]{
return std::string{g_fuzz_target};
}};
@@ -210,7 +217,6 @@ void signal_handler(int signal)
// This function is used by libFuzzer
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
- static const auto& test_one_input = *Assert(g_test_one_input);
test_one_input({data, size});
return 0;
}
@@ -227,7 +233,6 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
int main(int argc, char** argv)
{
initialize();
- static const auto& test_one_input = *Assert(g_test_one_input);
#ifdef __AFL_LOOP
// Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
// See fuzzing.md for details.
diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp
index 92e49445ba..066c168652 100644
--- a/src/test/fuzz/golomb_rice.cpp
+++ b/src/test/fuzz/golomb_rice.cpp
@@ -8,6 +8,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/random.h>
#include <util/bytevectorhash.h>
#include <util/golombrice.h>
@@ -42,6 +43,7 @@ std::vector<uint64_t> BuildHashedSet(const std::unordered_set<std::vector<uint8_
FUZZ_TARGET(golomb_rice)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
std::vector<uint8_t> golomb_rice_data;
std::vector<uint64_t> encoded_deltas;
diff --git a/src/test/fuzz/headerssync.cpp b/src/test/fuzz/headerssync.cpp
index 1aa878bd6d..8135b0d4ea 100644
--- a/src/test/fuzz/headerssync.cpp
+++ b/src/test/fuzz/headerssync.cpp
@@ -48,6 +48,7 @@ public:
FUZZ_TARGET(headers_sync_state, .init = initialize_headers_sync_state_fuzz)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
auto mock_time{ConsumeTime(fuzzed_data_provider)};
diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp
index 51517187a0..b8024f7b1c 100644
--- a/src/test/fuzz/i2p.cpp
+++ b/src/test/fuzz/i2p.cpp
@@ -21,6 +21,7 @@ void initialize_i2p()
FUZZ_TARGET(i2p, .init = initialize_i2p)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index 82973803f8..c7ff2f3a28 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -18,6 +18,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/random.h>
#include <util/chaintype.h>
#include <util/strencodings.h>
@@ -38,6 +39,7 @@ void initialize_key()
FUZZ_TARGET(key, .init = initialize_key)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
const CKey key = [&] {
CKey k;
k.Set(buffer.begin(), buffer.end(), true);
diff --git a/src/test/fuzz/mini_miner.cpp b/src/test/fuzz/mini_miner.cpp
index d06594d5f8..a5bccd103d 100644
--- a/src/test/fuzz/mini_miner.cpp
+++ b/src/test/fuzz/mini_miner.cpp
@@ -34,6 +34,7 @@ void initialize_miner()
// Test that the MiniMiner can run with various outpoints and feerates.
FUZZ_TARGET(mini_miner, .init = initialize_miner)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
bilingual_str error;
CTxMemPool pool{CTxMemPool::Options{}, error};
@@ -112,6 +113,7 @@ FUZZ_TARGET(mini_miner, .init = initialize_miner)
// Test that MiniMiner and BlockAssembler build the same block given the same transactions and constraints.
FUZZ_TARGET(mini_miner_selection, .init = initialize_miner)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
bilingual_str error;
CTxMemPool pool{CTxMemPool::Options{}, error};
@@ -174,15 +176,15 @@ FUZZ_TARGET(mini_miner_selection, .init = initialize_miner)
miner_options.blockMinFeeRate = target_feerate;
miner_options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
miner_options.test_block_validity = false;
+ miner_options.coinbase_output_script = CScript() << OP_0;
node::BlockAssembler miner{g_setup->m_node.chainman->ActiveChainstate(), &pool, miner_options};
node::MiniMiner mini_miner{pool, outpoints};
assert(mini_miner.IsReadyToCalculate());
- CScript spk_placeholder = CScript() << OP_0;
// Use BlockAssembler as oracle. BlockAssembler and MiniMiner should select the same
// transactions, stopping once packages do not meet target_feerate.
- const auto blocktemplate{miner.CreateNewBlock(spk_placeholder)};
+ const auto blocktemplate{miner.CreateNewBlock()};
mini_miner.BuildMockTemplate(target_feerate);
assert(!mini_miner.IsReadyToCalculate());
auto mock_template_txids = mini_miner.GetMockTemplateTxids();
diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp
index 4803cdccad..28a2026a35 100644
--- a/src/test/fuzz/netaddress.cpp
+++ b/src/test/fuzz/netaddress.cpp
@@ -6,6 +6,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util/net.h>
+#include <test/util/random.h>
#include <cassert>
#include <cstdint>
@@ -13,6 +14,7 @@
FUZZ_TARGET(netaddress)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const CNetAddr net_addr = ConsumeNetAddr(fuzzed_data_provider);
diff --git a/src/test/fuzz/p2p_handshake.cpp b/src/test/fuzz/p2p_handshake.cpp
index 6c1ed11d45..d608efd87a 100644
--- a/src/test/fuzz/p2p_handshake.cpp
+++ b/src/test/fuzz/p2p_handshake.cpp
@@ -39,6 +39,7 @@ void initialize()
FUZZ_TARGET(p2p_handshake, .init = ::initialize)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*g_setup->m_node.connman);
diff --git a/src/test/fuzz/p2p_headers_presync.cpp b/src/test/fuzz/p2p_headers_presync.cpp
index 935794057d..873eb2b1cc 100644
--- a/src/test/fuzz/p2p_headers_presync.cpp
+++ b/src/test/fuzz/p2p_headers_presync.cpp
@@ -153,6 +153,7 @@ void initialize()
FUZZ_TARGET(p2p_headers_presync, .init = initialize)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
ChainstateManager& chainman = *g_testing_setup->m_node.chainman;
LOCK(NetEventsInterface::g_msgproc_mutex);
diff --git a/src/test/fuzz/package_eval.cpp b/src/test/fuzz/package_eval.cpp
index 0373d2493f..8e3d84a9e6 100644
--- a/src/test/fuzz/package_eval.cpp
+++ b/src/test/fuzz/package_eval.cpp
@@ -21,6 +21,7 @@
#include <validation.h>
#include <validationinterface.h>
+using node::BlockAssembler;
using node::NodeContext;
namespace {
@@ -42,8 +43,11 @@ void initialize_tx_pool()
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
+ BlockAssembler::Options options;
+ options.coinbase_output_script = P2WSH_EMPTY;
+
for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) {
- COutPoint prevout{MineBlock(g_setup->m_node, P2WSH_EMPTY)};
+ COutPoint prevout{MineBlock(g_setup->m_node, options)};
if (i < COINBASE_MATURITY) {
// Remember the txids to avoid expensive disk access later on
g_outpoints_coinbase_init_mature.push_back(prevout);
@@ -188,6 +192,7 @@ std::optional<COutPoint> GetChildEvictingPrevout(const CTxMemPool& tx_pool)
FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const auto& node = g_setup->m_node;
auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
@@ -342,6 +347,7 @@ FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool)
FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const auto& node = g_setup->m_node;
auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
diff --git a/src/test/fuzz/partially_downloaded_block.cpp b/src/test/fuzz/partially_downloaded_block.cpp
index c41005eb73..8a42807be8 100644
--- a/src/test/fuzz/partially_downloaded_block.cpp
+++ b/src/test/fuzz/partially_downloaded_block.cpp
@@ -44,6 +44,7 @@ PartiallyDownloadedBlock::CheckBlockFn FuzzedCheckBlock(std::optional<BlockValid
FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
auto block{ConsumeDeserializable<CBlock>(fuzzed_data_provider, TX_WITH_WITNESS)};
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 6172388208..4bd38a1ac6 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -45,13 +45,14 @@ void initialize_process_message()
{.extra_args = {"-txreconciliation"}});
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
- MineBlock(g_setup->m_node, CScript() << OP_TRUE);
+ MineBlock(g_setup->m_node, {});
}
g_setup->m_node.validation_signals->SyncWithValidationInterfaceQueue();
}
FUZZ_TARGET(process_message, .init = initialize_process_message)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
ConnmanTestMsg& connman = *static_cast<ConnmanTestMsg*>(g_setup->m_node.connman.get());
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index 25bda09378..0688868c02 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -35,13 +35,14 @@ void initialize_process_messages()
{.extra_args = {"-txreconciliation"}});
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
- MineBlock(g_setup->m_node, CScript() << OP_TRUE);
+ MineBlock(g_setup->m_node, {});
}
g_setup->m_node.validation_signals->SyncWithValidationInterfaceQueue();
}
FUZZ_TARGET(process_messages, .init = initialize_process_messages)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
ConnmanTestMsg& connman = *static_cast<ConnmanTestMsg*>(g_setup->m_node.connman.get());
diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp
index e0692600bb..37fa159c33 100644
--- a/src/test/fuzz/psbt.cpp
+++ b/src/test/fuzz/psbt.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <test/fuzz/FuzzedDataProvider.h>
-#include <test/fuzz/fuzz.h>
-
#include <node/psbt.h>
#include <psbt.h>
#include <pubkey.h>
#include <script/script.h>
#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/util/random.h>
#include <util/check.h>
#include <cstdint>
@@ -23,6 +23,7 @@ using node::PSBTInputAnalysis;
FUZZ_TARGET(psbt)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
PartiallySignedTransaction psbt_mut;
std::string error;
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index c5db9f4ae0..3e5b361186 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -51,6 +51,7 @@ void initialize_package_rbf()
FUZZ_TARGET(rbf, .init = initialize_rbf)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
@@ -92,6 +93,7 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)
FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp
index 9c18ad49cb..1bea0ba9da 100644
--- a/src/test/fuzz/rolling_bloom_filter.cpp
+++ b/src/test/fuzz/rolling_bloom_filter.cpp
@@ -6,6 +6,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/random.h>
#include <uint256.h>
#include <cassert>
@@ -16,6 +17,7 @@
FUZZ_TARGET(rolling_bloom_filter)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CRollingBloomFilter rolling_bloom_filter{
diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp
index 9be2167793..7bf90b9b77 100644
--- a/src/test/fuzz/rpc.cpp
+++ b/src/test/fuzz/rpc.cpp
@@ -365,6 +365,7 @@ void initialize_rpc()
FUZZ_TARGET(rpc, .init = initialize_rpc)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
bool good_data{true};
SetMockTime(ConsumeTime(fuzzed_data_provider));
diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp
index 7f73c3706c..702a056d07 100644
--- a/src/test/fuzz/script_sigcache.cpp
+++ b/src/test/fuzz/script_sigcache.cpp
@@ -25,6 +25,7 @@ void initialize_script_sigcache()
FUZZ_TARGET(script_sigcache, .init = initialize_script_sigcache)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const auto max_sigcache_bytes{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, DEFAULT_SIGNATURE_CACHE_BYTES)};
diff --git a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp
index ae0c8479cb..c6e31e4dc7 100644
--- a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp
+++ b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp
@@ -7,6 +7,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/random.h>
#include <cstdint>
#include <vector>
@@ -16,6 +17,7 @@ int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned
FUZZ_TARGET(secp256k1_ecdsa_signature_parse_der_lax)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
const std::vector<uint8_t> signature_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
if (signature_bytes.data() == nullptr) {
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 2a043f7458..c9eb11222f 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -14,6 +14,7 @@
#include <primitives/transaction.h>
#include <streams.h>
#include <test/fuzz/fuzz.h>
+#include <test/util/random.h>
#include <univalue.h>
#include <util/chaintype.h>
#include <util/rbf.h>
@@ -28,6 +29,7 @@ void initialize_transaction()
FUZZ_TARGET(transaction, .init = initialize_transaction)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
DataStream ds{buffer};
bool valid_tx = true;
const CTransaction tx = [&] {
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 39aa404484..a697ee9d83 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -45,8 +45,11 @@ void initialize_tx_pool()
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
+ BlockAssembler::Options options;
+ options.coinbase_output_script = P2WSH_OP_TRUE;
+
for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) {
- COutPoint prevout{MineBlock(g_setup->m_node, P2WSH_OP_TRUE)};
+ COutPoint prevout{MineBlock(g_setup->m_node, options)};
// Remember the txids to avoid expensive disk access later on
auto& outpoints = i < COINBASE_MATURITY ?
g_outpoints_coinbase_init_mature :
@@ -98,7 +101,7 @@ void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, Cha
options.nBlockMaxWeight = fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BLOCK_WEIGHT);
options.blockMinFeeRate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
auto assembler = BlockAssembler{chainstate, &tx_pool, options};
- auto block_template = assembler.CreateNewBlock(CScript{} << OP_TRUE);
+ auto block_template = assembler.CreateNewBlock();
Assert(block_template->block.vtx.size() >= 1);
}
const auto info_all = tx_pool.infoAll();
@@ -187,6 +190,7 @@ void CheckATMPInvariants(const MempoolAcceptResult& res, bool txid_in_mempool, b
FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const auto& node = g_setup->m_node;
auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
@@ -365,6 +369,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const auto& node = g_setup->m_node;
auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
diff --git a/src/test/fuzz/txdownloadman.cpp b/src/test/fuzz/txdownloadman.cpp
index 8a4d7d55c2..4917e8b405 100644
--- a/src/test/fuzz/txdownloadman.cpp
+++ b/src/test/fuzz/txdownloadman.cpp
@@ -165,6 +165,7 @@ void CheckPackageToValidate(const node::PackageToValidate& package_to_validate,
FUZZ_TARGET(txdownloadman, .init = initialize)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
// Initialize txdownloadman
@@ -294,6 +295,7 @@ static void CheckInvariants(const node::TxDownloadManagerImpl& txdownload_impl,
FUZZ_TARGET(txdownloadman_impl, .init = initialize)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
// Initialize a TxDownloadManagerImpl
diff --git a/src/test/fuzz/util/CMakeLists.txt b/src/test/fuzz/util/CMakeLists.txt
index f73a1a83c2..878286b0f4 100644
--- a/src/test/fuzz/util/CMakeLists.txt
+++ b/src/test/fuzz/util/CMakeLists.txt
@@ -3,6 +3,7 @@
# file COPYING or https://opensource.org/license/mit/.
add_library(test_fuzz STATIC EXCLUDE_FROM_ALL
+ check_globals.cpp
descriptor.cpp
mempool.cpp
net.cpp
diff --git a/src/test/fuzz/util/check_globals.cpp b/src/test/fuzz/util/check_globals.cpp
new file mode 100644
index 0000000000..fbc5a55598
--- /dev/null
+++ b/src/test/fuzz/util/check_globals.cpp
@@ -0,0 +1,41 @@
+// Copyright (c) 2024-present The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <test/fuzz/util/check_globals.h>
+
+#include <test/util/random.h>
+
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <string>
+
+struct CheckGlobalsImpl {
+ CheckGlobalsImpl()
+ {
+ g_used_g_prng = false;
+ g_seeded_g_prng_zero = false;
+ }
+ ~CheckGlobalsImpl()
+ {
+ if (g_used_g_prng && !g_seeded_g_prng_zero) {
+ std::cerr << "\n\n"
+ "The current fuzz target used the global random state.\n\n"
+
+ "This is acceptable, but requires the fuzz target to call \n"
+ "SeedRandomStateForTest(SeedRand::ZEROS) in the first line \n"
+ "of the FUZZ_TARGET function.\n\n"
+
+ "An alternative solution would be to avoid any use of globals.\n\n"
+
+ "Without a solution, fuzz instability and non-determinism can lead \n"
+ "to non-reproducible bugs or inefficient fuzzing.\n\n"
+ << std::endl;
+ std::abort(); // Abort, because AFL may try to recover from a std::exit
+ }
+ }
+};
+
+CheckGlobals::CheckGlobals() : m_impl(std::make_unique<CheckGlobalsImpl>()) {}
+CheckGlobals::~CheckGlobals() = default;
diff --git a/src/test/fuzz/util/check_globals.h b/src/test/fuzz/util/check_globals.h
new file mode 100644
index 0000000000..79f247535a
--- /dev/null
+++ b/src/test/fuzz/util/check_globals.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2024-present 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_TEST_FUZZ_UTIL_CHECK_GLOBALS_H
+#define BITCOIN_TEST_FUZZ_UTIL_CHECK_GLOBALS_H
+
+#include <memory>
+#include <optional>
+#include <string>
+
+struct CheckGlobalsImpl;
+struct CheckGlobals {
+ CheckGlobals();
+ ~CheckGlobals();
+ std::unique_ptr<CheckGlobalsImpl> m_impl;
+};
+
+#endif // BITCOIN_TEST_FUZZ_UTIL_CHECK_GLOBALS_H
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 1241bba8be..9fe922cfaf 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -70,6 +70,7 @@ void initialize_chain()
template <bool INVALID>
void utxo_snapshot_fuzz(FuzzBufferType buffer)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
auto& setup{*g_setup};
bool dirty_chainman{false}; // Re-use the global chainman, but reset it when it is dirty
diff --git a/src/test/fuzz/utxo_total_supply.cpp b/src/test/fuzz/utxo_total_supply.cpp
index b0f1a1251a..84d82f71e2 100644
--- a/src/test/fuzz/utxo_total_supply.cpp
+++ b/src/test/fuzz/utxo_total_supply.cpp
@@ -17,8 +17,11 @@
#include <util/chaintype.h>
#include <validation.h>
+using node::BlockAssembler;
+
FUZZ_TARGET(utxo_total_supply)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
/** The testing setup that creates a chainman only (no chainstate) */
ChainTestingSetup test_setup{
ChainType::REGTEST,
@@ -36,9 +39,11 @@ FUZZ_TARGET(utxo_total_supply)
LOCK(chainman.GetMutex());
return chainman.ActiveHeight();
};
+ BlockAssembler::Options options;
+ options.coinbase_output_script = CScript() << OP_FALSE;
const auto PrepareNextBlock = [&]() {
// Use OP_FALSE to avoid BIP30 check from hitting early
- auto block = PrepareBlock(node, CScript{} << OP_FALSE);
+ auto block = PrepareBlock(node, options);
// Replace OP_FALSE with OP_TRUE
{
CMutableTransaction tx{*block->vtx.back()};
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
index c70d9ddf1e..4f90138892 100644
--- a/src/test/fuzz/validation_load_mempool.cpp
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -38,6 +38,7 @@ void initialize_validation_load_mempool()
FUZZ_TARGET(validation_load_mempool, .init = initialize_validation_load_mempool)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
FuzzedFileProvider fuzzed_file_provider{fuzzed_data_provider};
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index 2b1cf8595d..f8cb0094fc 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(merkle_test)
if (ntx > 16) {
mtx = m_rng.randrange(ntx);
}
- std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx);
+ std::vector<uint256> newBranch = TransactionMerklePath(block, mtx);
std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);
BOOST_CHECK(oldBranch == newBranch);
BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot);
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index c5ecf7022e..d48f9cca3f 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -8,6 +8,7 @@
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
+#include <interfaces/mining.h>
#include <node/miner.h>
#include <policy/policy.h>
#include <test/util/random.h>
@@ -28,8 +29,9 @@
#include <boost/test/unit_test.hpp>
using namespace util::hex_literals;
+using interfaces::BlockTemplate;
+using interfaces::Mining;
using node::BlockAssembler;
-using node::CBlockTemplate;
namespace miner_tests {
struct MinerTestingSetup : public TestingSetup {
@@ -54,7 +56,10 @@ struct MinerTestingSetup : public TestingSetup {
Assert(error.empty());
return *m_node.mempool;
}
- BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool);
+ std::unique_ptr<Mining> MakeMining()
+ {
+ return interfaces::MakeMining(m_node);
+ }
};
} // namespace miner_tests
@@ -62,15 +67,6 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup)
static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
-BlockAssembler MinerTestingSetup::AssemblerForTest(CTxMemPool& tx_mempool)
-{
- BlockAssembler::Options options;
-
- options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
- options.blockMinFeeRate = blockMinFeeRate;
- return BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options};
-}
-
constexpr static struct {
unsigned char extranonce;
unsigned int nonce;
@@ -108,6 +104,10 @@ static std::unique_ptr<CBlockIndex> CreateBlockIndex(int nHeight, CBlockIndex* a
void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
{
CTxMemPool& tx_mempool{MakeMempool()};
+ auto mining{MakeMining()};
+ BlockAssembler::Options options;
+ options.coinbase_output_script = scriptPubKey;
+
LOCK(tx_mempool.cs);
// Test the ancestor feerate transaction selection.
TestMemPoolEntryHelper entry;
@@ -137,11 +137,13 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
Txid hashHighFeeTx = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
- std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
- BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U);
- BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx);
- BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx);
- BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashMediumFeeTx);
+ std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
+ CBlock block{block_template->getBlock()};
+ BOOST_REQUIRE_EQUAL(block.vtx.size(), 4U);
+ BOOST_CHECK(block.vtx[1]->GetHash() == hashParentTx);
+ BOOST_CHECK(block.vtx[2]->GetHash() == hashHighFeeTx);
+ BOOST_CHECK(block.vtx[3]->GetHash() == hashMediumFeeTx);
// Test that a package below the block min tx fee doesn't get included
tx.vin[0].prevout.hash = hashHighFeeTx;
@@ -158,11 +160,13 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
Txid hashLowFeeTx = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(feeToUse).FromTx(tx));
- pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
+ block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
+ block = block_template->getBlock();
// Verify that the free tx and the low fee tx didn't get selected
- for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
- BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx);
- BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx);
+ for (size_t i=0; i<block.vtx.size(); ++i) {
+ BOOST_CHECK(block.vtx[i]->GetHash() != hashFreeTx);
+ BOOST_CHECK(block.vtx[i]->GetHash() != hashLowFeeTx);
}
// Test that packages above the min relay fee do get included, even if one
@@ -172,10 +176,12 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
hashLowFeeTx = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(feeToUse + 2).FromTx(tx));
- pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
- BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
- BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
- BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);
+ block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
+ block = block_template->getBlock();
+ BOOST_REQUIRE_EQUAL(block.vtx.size(), 6U);
+ BOOST_CHECK(block.vtx[4]->GetHash() == hashFreeTx);
+ BOOST_CHECK(block.vtx[5]->GetHash() == hashLowFeeTx);
// Test that transaction selection properly updates ancestor fee
// calculations as ancestor transactions get included in a block.
@@ -194,12 +200,14 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
Txid hashLowFeeTx2 = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
- pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
+ block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
+ block = block_template->getBlock();
// Verify that this tx isn't selected.
- for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
- BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx2);
- BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx2);
+ for (size_t i=0; i<block.vtx.size(); ++i) {
+ BOOST_CHECK(block.vtx[i]->GetHash() != hashFreeTx2);
+ BOOST_CHECK(block.vtx[i]->GetHash() != hashLowFeeTx2);
}
// This tx will be mineable, and should cause hashLowFeeTx2 to be selected
@@ -207,9 +215,11 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vin[0].prevout.n = 1;
tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee
AddToMempool(tx_mempool, entry.Fee(10000).FromTx(tx));
- pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
- BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U);
- BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
+ block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
+ block = block_template->getBlock();
+ BOOST_REQUIRE_EQUAL(block.vtx.size(), 9U);
+ BOOST_CHECK(block.vtx[8]->GetHash() == hashLowFeeTx2);
}
void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight)
@@ -225,13 +235,20 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
const CAmount HIGHFEE = COIN;
const CAmount HIGHERFEE = 4 * COIN;
+ auto mining{MakeMining()};
+ BOOST_REQUIRE(mining);
+
+ BlockAssembler::Options options;
+ options.coinbase_output_script = scriptPubKey;
+
{
CTxMemPool& tx_mempool{MakeMempool()};
LOCK(tx_mempool.cs);
// Just to make sure we can still make simple blocks
- auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
- BOOST_CHECK(pblocktemplate);
+ auto block_template{mining->createNewBlock(options)};
+ BOOST_REQUIRE(block_template);
+ CBlock block{block_template->getBlock()};
// block sigops > limit: 1000 CHECKMULTISIG + 1
tx.vin.resize(1);
@@ -250,7 +267,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
+ BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("bad-blk-sigops"));
}
{
@@ -267,7 +284,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ BOOST_REQUIRE(mining->createNewBlock(options));
}
{
@@ -291,7 +308,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ BOOST_REQUIRE(mining->createNewBlock(options));
}
{
@@ -301,7 +318,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
// orphan in tx_mempool, template creation fails
hash = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
+ BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
}
{
@@ -322,7 +339,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; // First txn output + fresh coinbase - new txn fee
hash = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(HIGHERFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ BOOST_REQUIRE(mining->createNewBlock(options));
}
{
@@ -338,7 +355,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
// give it a fee so it'll get mined
AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
// Should throw bad-cb-multiple
- BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
+ BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("bad-cb-multiple"));
}
{
@@ -355,7 +372,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
+ BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
}
{
@@ -375,7 +392,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
next->BuildSkip();
m_node.chainman->ActiveChain().SetTip(*next);
}
- BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ BOOST_REQUIRE(mining->createNewBlock(options));
// Extend to a 210000-long block chain.
while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) {
CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
@@ -387,7 +404,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
next->BuildSkip();
m_node.chainman->ActiveChain().SetTip(*next);
}
- BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ BOOST_REQUIRE(mining->createNewBlock(options));
// invalid p2sh txn in tx_mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
@@ -403,7 +420,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("mandatory-script-verify-flag-failed"));
+ BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("mandatory-script-verify-flag-failed"));
// Delete the dummy blocks again.
while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) {
@@ -505,14 +522,15 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
- auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
- BOOST_CHECK(pblocktemplate);
+ auto block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
// None of the of the absolute height/time locked tx should have made
// it into the template because we still check IsFinalTx in CreateNewBlock,
// but relative locked txs will if inconsistently added to mempool.
// For now these will still generate a valid template until BIP68 soft fork
- BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3U);
+ CBlock block{block_template->getBlock()};
+ BOOST_CHECK_EQUAL(block.vtx.size(), 3U);
// However if we advance height by 1 and time by SEQUENCE_LOCK_TIME, all of them should be mined
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) {
CBlockIndex* ancestor{Assert(m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i))};
@@ -521,12 +539,20 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
m_node.chainman->ActiveChain().Tip()->nHeight++;
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1);
- BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
- BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
+ block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
+ block = block_template->getBlock();
+ BOOST_CHECK_EQUAL(block.vtx.size(), 5U);
}
void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
{
+ auto mining{MakeMining()};
+ BOOST_REQUIRE(mining);
+
+ BlockAssembler::Options options;
+ options.coinbase_output_script = scriptPubKey;
+
CTxMemPool& tx_mempool{MakeMempool()};
LOCK(tx_mempool.cs);
@@ -588,31 +614,34 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
Txid hashFreeGrandchild = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
- auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
- BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
- BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashFreeParent);
- BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashFreePrioritisedTx);
- BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashParentTx);
- BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashPrioritsedChild);
- BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashFreeChild);
- for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
+ auto block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
+ CBlock block{block_template->getBlock()};
+ BOOST_REQUIRE_EQUAL(block.vtx.size(), 6U);
+ BOOST_CHECK(block.vtx[1]->GetHash() == hashFreeParent);
+ BOOST_CHECK(block.vtx[2]->GetHash() == hashFreePrioritisedTx);
+ BOOST_CHECK(block.vtx[3]->GetHash() == hashParentTx);
+ BOOST_CHECK(block.vtx[4]->GetHash() == hashPrioritsedChild);
+ BOOST_CHECK(block.vtx[5]->GetHash() == hashFreeChild);
+ for (size_t i=0; i<block.vtx.size(); ++i) {
// The FreeParent and FreeChild's prioritisations should not impact the child.
- BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeGrandchild);
+ BOOST_CHECK(block.vtx[i]->GetHash() != hashFreeGrandchild);
// De-prioritised transaction should not be included.
- BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashMediumFeeTx);
+ BOOST_CHECK(block.vtx[i]->GetHash() != hashMediumFeeTx);
}
}
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
+ auto mining{MakeMining()};
+ BOOST_REQUIRE(mining);
+
// Note that by default, these tests run with size accounting enabled.
CScript scriptPubKey = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG;
- std::unique_ptr<CBlockTemplate> pblocktemplate;
-
- CTxMemPool& tx_mempool{*m_node.mempool};
- // Simple block creation, nothing special yet:
- BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ BlockAssembler::Options options;
+ options.coinbase_output_script = scriptPubKey;
+ std::unique_ptr<BlockTemplate> block_template;
// We can't make transactions until we have inputs
// Therefore, load 110 blocks :)
@@ -620,27 +649,48 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
int baseheight = 0;
std::vector<CTransactionRef> txFirst;
for (const auto& bi : BLOCKINFO) {
- CBlock *pblock = &pblocktemplate->block; // pointer for convenience
+ const int current_height{mining->getTip()->height};
+
+ // Simple block creation, nothing special yet:
+ block_template = mining->createNewBlock(options);
+ BOOST_REQUIRE(block_template);
+
+ CBlock block{block_template->getBlock()};
+ CMutableTransaction txCoinbase(*block.vtx[0]);
{
LOCK(cs_main);
- pblock->nVersion = VERSIONBITS_TOP_BITS;
- pblock->nTime = m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1;
- CMutableTransaction txCoinbase(*pblock->vtx[0]);
+ block.nVersion = VERSIONBITS_TOP_BITS;
+ block.nTime = Assert(m_node.chainman)->ActiveChain().Tip()->GetMedianTimePast()+1;
txCoinbase.version = 1;
- txCoinbase.vin[0].scriptSig = CScript{} << (m_node.chainman->ActiveChain().Height() + 1) << bi.extranonce;
+ txCoinbase.vin[0].scriptSig = CScript{} << (current_height + 1) << bi.extranonce;
txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
txCoinbase.vout[0].scriptPubKey = CScript();
- pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
+ block.vtx[0] = MakeTransactionRef(txCoinbase);
if (txFirst.size() == 0)
- baseheight = m_node.chainman->ActiveChain().Height();
+ baseheight = current_height;
if (txFirst.size() < 4)
- txFirst.push_back(pblock->vtx[0]);
- pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
- pblock->nNonce = bi.nonce;
+ txFirst.push_back(block.vtx[0]);
+ block.hashMerkleRoot = BlockMerkleRoot(block);
+ block.nNonce = bi.nonce;
+ }
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
+ // Alternate calls between Chainman's ProcessNewBlock and submitSolution
+ // via the Mining interface. The former is used by net_processing as well
+ // as the submitblock RPC.
+ if (current_height % 2 == 0) {
+ BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr));
+ } else {
+ BOOST_REQUIRE(block_template->submitSolution(block.nVersion, block.nTime, block.nNonce, MakeTransactionRef(txCoinbase)));
+ }
+ {
+ LOCK(cs_main);
+ // The above calls don't guarantee the tip is actually updated, so
+ // we explictly check this.
+ auto maybe_new_tip{Assert(m_node.chainman)->ActiveChain().Tip()};
+ BOOST_REQUIRE_EQUAL(maybe_new_tip->GetBlockHash(), block.GetHash());
}
- std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
- BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, true, nullptr));
- pblock->hashPrevBlock = pblock->GetHash();
+ // This just adds coverage
+ mining->waitTipChanged(block.hashPrevBlock);
}
LOCK(cs_main);
diff --git a/src/test/peerman_tests.cpp b/src/test/peerman_tests.cpp
index 6de373eef2..64b13fa3cc 100644
--- a/src/test/peerman_tests.cpp
+++ b/src/test/peerman_tests.cpp
@@ -20,8 +20,7 @@ static void mineBlock(const node::NodeContext& node, std::chrono::seconds block_
{
auto curr_time = GetTime<std::chrono::seconds>();
SetMockTime(block_time); // update time so the block is created with it
- node::BlockAssembler::Options options;
- CBlock block = node::BlockAssembler{node.chainman->ActiveChainstate(), nullptr, options}.CreateNewBlock(CScript() << OP_TRUE)->block;
+ CBlock block = node::BlockAssembler{node.chainman->ActiveChainstate(), nullptr, {}}.CreateNewBlock()->block;
while (!CheckProofOfWork(block.GetHash(), block.nBits, node.chainman->GetConsensus())) ++block.nNonce;
block.fChecked = true; // little speedup
SetMockTime(curr_time); // process block at current time
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 59eb90bd27..8753ddee37 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1700,9 +1700,8 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
BOOST_CHECK_EQUAL(HexStr(sighash), input["intermediary"]["sigHash"].get_str());
// To verify the sigmsg, hash the expected sigmsg, and compare it with the (expected) sighash.
- BOOST_CHECK_EQUAL(HexStr((HashWriter{HASHER_TAPSIGHASH} << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
+ BOOST_CHECK_EQUAL(HexStr((HashWriter{HASHER_TAPSIGHASH} << std::span<const uint8_t>{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
}
-
}
}
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index b28e1b4196..7e403694e2 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -304,7 +304,7 @@ public:
if (s.template GetParams<BaseFormat>().m_base_format == BaseFormat::RAW) {
s << m_base_data;
} else {
- s << Span{HexStr(Span{&m_base_data, 1})};
+ s << std::span<const char>{HexStr(Span{&m_base_data, 1})};
}
}
diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp
index ad7a38d3fe..04925792dc 100644
--- a/src/test/util/mining.cpp
+++ b/src/test/util/mining.cpp
@@ -24,9 +24,10 @@ COutPoint generatetoaddress(const NodeContext& node, const std::string& address)
{
const auto dest = DecodeDestination(address);
assert(IsValidDestination(dest));
- const auto coinbase_script = GetScriptForDestination(dest);
+ BlockAssembler::Options assembler_options;
+ assembler_options.coinbase_output_script = GetScriptForDestination(dest);
- return MineBlock(node, coinbase_script);
+ return MineBlock(node, assembler_options);
}
std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params)
@@ -60,9 +61,9 @@ std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const
return ret;
}
-COutPoint MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
+COutPoint MineBlock(const NodeContext& node, const node::BlockAssembler::Options& assembler_options)
{
- auto block = PrepareBlock(node, coinbase_scriptPubKey);
+ auto block = PrepareBlock(node, assembler_options);
auto valid = MineBlock(node, block);
assert(!valid.IsNull());
return valid;
@@ -108,12 +109,12 @@ COutPoint MineBlock(const NodeContext& node, std::shared_ptr<CBlock>& block)
return {};
}
-std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey,
+std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node,
const BlockAssembler::Options& assembler_options)
{
auto block = std::make_shared<CBlock>(
BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get()), assembler_options}
- .CreateNewBlock(coinbase_scriptPubKey)
+ .CreateNewBlock()
->block);
LOCK(cs_main);
@@ -125,6 +126,7 @@ std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coi
std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
{
BlockAssembler::Options assembler_options;
+ assembler_options.coinbase_output_script = coinbase_scriptPubKey;
ApplyArgsManOptions(*node.args, assembler_options);
- return PrepareBlock(node, coinbase_scriptPubKey, assembler_options);
+ return PrepareBlock(node, assembler_options);
}
diff --git a/src/test/util/mining.h b/src/test/util/mining.h
index 3f071257f1..9c6e29b4d3 100644
--- a/src/test/util/mining.h
+++ b/src/test/util/mining.h
@@ -23,7 +23,8 @@ struct NodeContext;
std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params);
/** Returns the generated coin */
-COutPoint MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
+COutPoint MineBlock(const node::NodeContext&,
+ const node::BlockAssembler::Options& assembler_options);
/**
* Returns the generated coin (or Null if the block was invalid).
@@ -32,8 +33,8 @@ COutPoint MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubK
COutPoint MineBlock(const node::NodeContext&, std::shared_ptr<CBlock>& block);
/** Prepare a block to be mined */
-std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
-std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext& node, const CScript& coinbase_scriptPubKey,
+std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&);
+std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext& node,
const node::BlockAssembler::Options& assembler_options);
/** RPC-like helper function, returns the generated coin */
diff --git a/src/test/util/net.h b/src/test/util/net.h
index 043e317bf0..d3aefda4f0 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -12,6 +12,7 @@
#include <netaddress.h>
#include <node/connection_types.h>
#include <node/eviction.h>
+#include <span.h>
#include <sync.h>
#include <util/sock.h>
@@ -28,9 +29,6 @@
class FastRandomContext;
-template <typename C>
-class Span;
-
struct ConnmanTestMsg : public CConnman {
using CConnman::CConnman;
diff --git a/src/test/util/random.cpp b/src/test/util/random.cpp
index 32d785e45d..770848f708 100644
--- a/src/test/util/random.cpp
+++ b/src/test/util/random.cpp
@@ -12,6 +12,8 @@
#include <cstdlib>
#include <iostream>
+std::atomic<bool> g_seeded_g_prng_zero{false};
+
extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept;
void SeedRandomStateForTest(SeedRand seedtype)
@@ -36,6 +38,10 @@ void SeedRandomStateForTest(SeedRand seedtype)
return GetRandHash();
}();
+ g_seeded_g_prng_zero = seedtype == SeedRand::ZEROS;
+ if constexpr (G_FUZZING) {
+ Assert(g_seeded_g_prng_zero); // Only SeedRandomStateForTest(SeedRand::ZEROS) is allowed in fuzz tests
+ }
const uint256& seed{seedtype == SeedRand::FIXED_SEED ? ctx_seed : uint256::ZERO};
LogInfo("Setting random seed for current tests to %s=%s\n", RANDOM_CTX_SEED, seed.GetHex());
MakeRandDeterministicDANGEROUS(seed);
diff --git a/src/test/util/random.h b/src/test/util/random.h
index 441150e666..47bc7a18f9 100644
--- a/src/test/util/random.h
+++ b/src/test/util/random.h
@@ -9,6 +9,7 @@
#include <random.h>
#include <uint256.h>
+#include <atomic>
#include <cstdint>
enum class SeedRand {
@@ -27,6 +28,9 @@ enum class SeedRand {
/** Seed the global RNG state for testing and log the seed value. This affects all randomness, except GetStrongRandBytes(). */
void SeedRandomStateForTest(SeedRand seed);
+extern std::atomic<bool> g_seeded_g_prng_zero;
+extern std::atomic<bool> g_used_g_prng;
+
template <RandomNumberGenerator Rng>
inline CAmount RandMoney(Rng&& rng)
{
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 12feba09a5..3f8c6f41ba 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -108,6 +108,9 @@ static void ExitFailure(std::string_view str_err)
BasicTestingSetup::BasicTestingSetup(const ChainType chainType, TestOpts opts)
: m_args{}
{
+ if constexpr (!G_FUZZING) {
+ SeedRandomForTest(SeedRand::FIXED_SEED);
+ }
m_node.shutdown_signal = &m_interrupt;
m_node.shutdown_request = [this]{ return m_interrupt(); };
m_node.args = &gArgs;
@@ -139,8 +142,6 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, TestOpts opts)
}
}
- SeedRandomForTest(SeedRand::FIXED_SEED);
-
const std::string test_name{G_TEST_GET_FULL_NAME ? G_TEST_GET_FULL_NAME() : ""};
if (!m_node.args->IsArgSet("-testdatadir")) {
// To avoid colliding with a leftover prior datadir, and to allow
@@ -377,7 +378,8 @@ CBlock TestChain100Setup::CreateBlock(
Chainstate& chainstate)
{
BlockAssembler::Options options;
- CBlock block = BlockAssembler{chainstate, nullptr, options}.CreateNewBlock(scriptPubKey)->block;
+ options.coinbase_output_script = scriptPubKey;
+ CBlock block = BlockAssembler{chainstate, nullptr, options}.CreateNewBlock()->block;
Assert(block.vtx.size() == 1);
for (const CMutableTransaction& tx : txns) {
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index f3bc8e7139..5c1f195868 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -66,7 +66,8 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash)
static uint64_t time = Params().GenesisBlock().nTime;
BlockAssembler::Options options;
- auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(CScript{} << i++ << OP_TRUE);
+ options.coinbase_output_script = CScript{} << i++ << OP_TRUE;
+ auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock();
auto pblock = std::make_shared<CBlock>(ptemplate->block);
pblock->hashPrevBlock = prev_hash;
pblock->nTime = ++time;
@@ -331,7 +332,8 @@ BOOST_AUTO_TEST_CASE(witness_commitment_index)
CScript pubKey;
pubKey << 1 << OP_TRUE;
BlockAssembler::Options options;
- auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(pubKey);
+ options.coinbase_output_script = pubKey;
+ auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock();
CBlock pblock = ptemplate->block;
CTxOut witness;
diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp
index c9cca8af04..bf8cd819f2 100644
--- a/src/test/validation_chainstate_tests.cpp
+++ b/src/test/validation_chainstate_tests.cpp
@@ -72,7 +72,8 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
ChainstateManager& chainman = *Assert(m_node.chainman);
const auto get_notify_tip{[&]() {
LOCK(m_node.notifications->m_tip_block_mutex);
- return m_node.notifications->m_tip_block;
+ BOOST_REQUIRE(m_node.notifications->TipBlock());
+ return *m_node.notifications->TipBlock();
}};
uint256 curr_tip = get_notify_tip();
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 8d14b6ce2e..407d6085aa 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -711,9 +711,9 @@ void StopTorControl()
}
}
-CService DefaultOnionServiceTarget()
+CService DefaultOnionServiceTarget(uint16_t port)
{
struct in_addr onion_service_target;
onion_service_target.s_addr = htonl(INADDR_LOOPBACK);
- return {onion_service_target, BaseParams().OnionServiceTargetPort()};
+ return {onion_service_target, port};
}
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 4a0eef223e..0b66201cf1 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -27,7 +27,7 @@ void StartTorControl(CService onion_service_target);
void InterruptTorControl();
void StopTorControl();
-CService DefaultOnionServiceTarget();
+CService DefaultOnionServiceTarget(uint16_t port);
/** Reply from Tor, can be single or multi-line */
class TorControlReply
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 950004044e..3a5a3fb306 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -442,7 +442,7 @@ void CTxMemPool::Apply(ChangeSet* changeset)
std::optional<CTxMemPool::setEntries> ancestors;
if (i == 0) {
// Note: ChangeSet::CalculateMemPoolAncestors() will return a
- // cached value if mempool ancestors for this tranaction were
+ // cached value if mempool ancestors for this transaction were
// previously calculated.
// We can only use a cached ancestor calculation for the first
// transaction in a package, because in-package parents won't be
diff --git a/src/txmempool.h b/src/txmempool.h
index e505c87f09..10acb2aa22 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -810,7 +810,7 @@ public:
* mempool.
*
* CalculateMemPoolAncestors() calculates the in-mempool (not including
- * what is in the change set itself) ancestors of a given transacion.
+ * what is in the change set itself) ancestors of a given transaction.
*
* Apply() will apply the removals and additions that are staged into the
* mempool.
diff --git a/src/uint256.h b/src/uint256.h
index 8223787041..708f0c2ff1 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -69,16 +69,27 @@ public:
/** @name Hex representation
*
- * The reverse-byte hex representation is a convenient way to view the blob
- * as a number, because it is consistent with the way the base_uint class
- * converts blobs to numbers.
+ * The hex representation used by GetHex(), ToString(), FromHex() and
+ * SetHexDeprecated() is unusual, since it shows bytes of the base_blob in
+ * reverse order. For example, a 4-byte blob {0x12, 0x34, 0x56, 0x78} is
+ * represented as "78563412" instead of the more typical "12345678"
+ * representation that would be shown in a hex editor or used by typical
+ * byte-array / hex conversion functions like python's bytes.hex() and
+ * bytes.fromhex().
+ *
+ * The nice thing about the reverse-byte representation, even though it is
+ * unusual, is that if a blob contains an arithmetic number in little endian
+ * format (with least significant bytes first, and most significant bytes
+ * last), the GetHex() output will match the way the number would normally
+ * be written in base-16 (with most significant digits first and least
+ * significant digits last).
+ *
+ * This means, for example, that ArithToUint256(num).GetHex() can be used to
+ * display an arith_uint256 num value as a number, because
+ * ArithToUint256() converts the number to a blob in little-endian format,
+ * so the arith_uint256 class doesn't need to have its own number parsing
+ * and formatting functions.
*
- * @note base_uint treats the blob as an array of bytes with the numerically
- * least significant byte first and the most significant byte last. Because
- * numbers are typically written with the most significant digit first and
- * the least significant digit last, the reverse hex display of the blob
- * corresponds to the same numeric value that base_uint interprets from the
- * blob.
* @{*/
std::string GetHex() const;
/** Unlike FromHex this accepts any invalid input, thus it is fragile and deprecated!
diff --git a/src/univalue/CMakeLists.txt b/src/univalue/CMakeLists.txt
index 96733fe077..c31e82cadc 100644
--- a/src/univalue/CMakeLists.txt
+++ b/src/univalue/CMakeLists.txt
@@ -15,10 +15,119 @@ target_include_directories(univalue
target_link_libraries(univalue PRIVATE core_interface)
if(BUILD_TESTS)
- add_executable(unitester test/unitester.cpp)
- target_compile_definitions(unitester
- PRIVATE
- JSON_TEST_SRC=\"${CMAKE_CURRENT_SOURCE_DIR}/test\"
+ include(GenerateHeaders)
+ generate_header_from_json(test/fail1.json)
+ generate_header_from_json(test/fail10.json)
+ generate_header_from_json(test/fail11.json)
+ generate_header_from_json(test/fail12.json)
+ generate_header_from_json(test/fail13.json)
+ generate_header_from_json(test/fail14.json)
+ generate_header_from_json(test/fail15.json)
+ generate_header_from_json(test/fail16.json)
+ generate_header_from_json(test/fail17.json)
+ generate_header_from_json(test/fail18.json)
+ generate_header_from_json(test/fail19.json)
+ generate_header_from_json(test/fail2.json)
+ generate_header_from_json(test/fail20.json)
+ generate_header_from_json(test/fail21.json)
+ generate_header_from_json(test/fail22.json)
+ generate_header_from_json(test/fail23.json)
+ generate_header_from_json(test/fail24.json)
+ generate_header_from_json(test/fail25.json)
+ generate_header_from_json(test/fail26.json)
+ generate_header_from_json(test/fail27.json)
+ generate_header_from_json(test/fail28.json)
+ generate_header_from_json(test/fail29.json)
+ generate_header_from_json(test/fail3.json)
+ generate_header_from_json(test/fail30.json)
+ generate_header_from_json(test/fail31.json)
+ generate_header_from_json(test/fail32.json)
+ generate_header_from_json(test/fail33.json)
+ generate_header_from_json(test/fail34.json)
+ generate_header_from_json(test/fail35.json)
+ generate_header_from_json(test/fail36.json)
+ generate_header_from_json(test/fail37.json)
+ generate_header_from_json(test/fail38.json)
+ generate_header_from_json(test/fail39.json)
+ generate_header_from_json(test/fail4.json)
+ generate_header_from_json(test/fail40.json)
+ generate_header_from_json(test/fail41.json)
+ generate_header_from_json(test/fail42.json)
+ generate_header_from_json(test/fail44.json)
+ generate_header_from_json(test/fail45.json)
+ generate_header_from_json(test/fail5.json)
+ generate_header_from_json(test/fail6.json)
+ generate_header_from_json(test/fail7.json)
+ generate_header_from_json(test/fail8.json)
+ generate_header_from_json(test/fail9.json)
+ generate_header_from_json(test/pass1.json)
+ generate_header_from_json(test/pass2.json)
+ generate_header_from_json(test/pass3.json)
+ generate_header_from_json(test/pass4.json)
+ generate_header_from_json(test/round1.json)
+ generate_header_from_json(test/round2.json)
+ generate_header_from_json(test/round3.json)
+ generate_header_from_json(test/round4.json)
+ generate_header_from_json(test/round5.json)
+ generate_header_from_json(test/round6.json)
+ generate_header_from_json(test/round7.json)
+ add_executable(unitester
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail1.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail10.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail11.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail12.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail13.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail14.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail15.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail16.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail17.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail18.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail19.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail2.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail20.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail21.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail22.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail23.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail24.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail25.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail26.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail27.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail28.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail29.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail3.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail30.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail31.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail32.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail33.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail34.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail35.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail36.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail37.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail38.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail39.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail4.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail40.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail41.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail42.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail44.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail45.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail5.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail6.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail7.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail8.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/fail9.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/pass1.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/pass2.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/pass3.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/pass4.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/round1.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/round2.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/round3.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/round4.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/round5.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/round6.json.h
+ ${CMAKE_CURRENT_BINARY_DIR}/test/round7.json.h
+ test/unitester.cpp
)
target_link_libraries(unitester
PRIVATE
diff --git a/src/univalue/test/fail18.json b/src/univalue/test/fail18.json
index edac92716f..a72bec7e18 100644
--- a/src/univalue/test/fail18.json
+++ b/src/univalue/test/fail18.json
@@ -1 +1 @@
-[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
diff --git a/src/univalue/test/pass2.json b/src/univalue/test/pass2.json
index d3c63c7ad8..624387bf33 100644
--- a/src/univalue/test/pass2.json
+++ b/src/univalue/test/pass2.json
@@ -1 +1 @@
-[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp
index d27e647e5c..e517e64188 100644
--- a/src/univalue/test/unitester.cpp
+++ b/src/univalue/test/unitester.cpp
@@ -1,130 +1,159 @@
// Copyright 2014 BitPay Inc.
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2015-present The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <univalue.h>
+#include <univalue/test/fail1.json.h>
+#include <univalue/test/fail10.json.h>
+#include <univalue/test/fail11.json.h>
+#include <univalue/test/fail12.json.h>
+#include <univalue/test/fail13.json.h>
+#include <univalue/test/fail14.json.h>
+#include <univalue/test/fail15.json.h>
+#include <univalue/test/fail16.json.h>
+#include <univalue/test/fail17.json.h>
+#include <univalue/test/fail18.json.h>
+#include <univalue/test/fail19.json.h>
+#include <univalue/test/fail2.json.h>
+#include <univalue/test/fail20.json.h>
+#include <univalue/test/fail21.json.h>
+#include <univalue/test/fail22.json.h>
+#include <univalue/test/fail23.json.h>
+#include <univalue/test/fail24.json.h>
+#include <univalue/test/fail25.json.h>
+#include <univalue/test/fail26.json.h>
+#include <univalue/test/fail27.json.h>
+#include <univalue/test/fail28.json.h>
+#include <univalue/test/fail29.json.h>
+#include <univalue/test/fail3.json.h>
+#include <univalue/test/fail30.json.h>
+#include <univalue/test/fail31.json.h>
+#include <univalue/test/fail32.json.h>
+#include <univalue/test/fail33.json.h>
+#include <univalue/test/fail34.json.h>
+#include <univalue/test/fail35.json.h>
+#include <univalue/test/fail36.json.h>
+#include <univalue/test/fail37.json.h>
+#include <univalue/test/fail38.json.h>
+#include <univalue/test/fail39.json.h>
+#include <univalue/test/fail4.json.h>
+#include <univalue/test/fail40.json.h>
+#include <univalue/test/fail41.json.h>
+#include <univalue/test/fail42.json.h>
+#include <univalue/test/fail44.json.h>
+#include <univalue/test/fail45.json.h>
+#include <univalue/test/fail5.json.h>
+#include <univalue/test/fail6.json.h>
+#include <univalue/test/fail7.json.h>
+#include <univalue/test/fail8.json.h>
+#include <univalue/test/fail9.json.h>
+#include <univalue/test/pass1.json.h>
+#include <univalue/test/pass2.json.h>
+#include <univalue/test/pass3.json.h>
+#include <univalue/test/pass4.json.h>
+#include <univalue/test/round1.json.h>
+#include <univalue/test/round2.json.h>
+#include <univalue/test/round3.json.h>
+#include <univalue/test/round4.json.h>
+#include <univalue/test/round5.json.h>
+#include <univalue/test/round6.json.h>
+#include <univalue/test/round7.json.h>
+
+#include <array>
#include <cassert>
#include <cstdio>
#include <string>
-#ifndef JSON_TEST_SRC
-#error JSON_TEST_SRC must point to test source directory
-#endif
-
-std::string srcdir(JSON_TEST_SRC);
-
static std::string rtrim(std::string s)
{
- s.erase(s.find_last_not_of(" \n\r\t")+1);
+ s.erase(s.find_last_not_of(" \n\r\t") + 1);
return s;
}
static void runtest(std::string filename, const std::string& jdata)
{
- std::string prefix = filename.substr(0, 4);
-
- bool wantPass = (prefix == "pass") || (prefix == "roun");
- bool wantFail = (prefix == "fail");
- bool wantRoundTrip = (prefix == "roun");
- assert(wantPass || wantFail);
-
- UniValue val;
- bool testResult = val.read(jdata);
-
- if (wantPass) {
- assert(testResult == true);
- } else {
- assert(testResult == false);
- }
-
- if (wantRoundTrip) {
- std::string odata = val.write(0, 0);
- assert(odata == rtrim(jdata));
- }
-}
-
-static void runtest_file(const char *filename_)
-{
- std::string basename(filename_);
- std::string filename = srcdir + "/" + basename;
- FILE *f = fopen(filename.c_str(), "r");
- assert(f != nullptr);
+ std::string prefix = filename.substr(0, 4);
- std::string jdata;
+ bool wantPass = (prefix == "pass") || (prefix == "roun");
+ bool wantFail = (prefix == "fail");
+ bool wantRoundTrip = (prefix == "roun");
+ assert(wantPass || wantFail);
- char buf[4096];
- while (!feof(f)) {
- int bread = fread(buf, 1, sizeof(buf), f);
- assert(!ferror(f));
-
- std::string s(buf, bread);
- jdata += s;
- }
+ UniValue val;
+ bool testResult = val.read(jdata);
- assert(!ferror(f));
- fclose(f);
+ if (wantPass) {
+ assert(testResult == true);
+ } else {
+ assert(testResult == false);
+ }
- runtest(basename, jdata);
+ if (wantRoundTrip) {
+ std::string odata = val.write(0, 0);
+ assert(odata == rtrim(jdata));
+ }
}
-static const char *filenames[] = {
- "fail10.json",
- "fail11.json",
- "fail12.json",
- "fail13.json",
- "fail14.json",
- "fail15.json",
- "fail16.json",
- "fail17.json",
- //"fail18.json", // investigate
- "fail19.json",
- "fail1.json",
- "fail20.json",
- "fail21.json",
- "fail22.json",
- "fail23.json",
- "fail24.json",
- "fail25.json",
- "fail26.json",
- "fail27.json",
- "fail28.json",
- "fail29.json",
- "fail2.json",
- "fail30.json",
- "fail31.json",
- "fail32.json",
- "fail33.json",
- "fail34.json",
- "fail35.json",
- "fail36.json",
- "fail37.json",
- "fail38.json", // invalid unicode: only first half of surrogate pair
- "fail39.json", // invalid unicode: only second half of surrogate pair
- "fail40.json", // invalid unicode: broken UTF-8
- "fail41.json", // invalid unicode: unfinished UTF-8
- "fail42.json", // valid json with garbage following a nul byte
- "fail44.json", // unterminated string
- "fail45.json", // nested beyond max depth
- "fail3.json",
- "fail4.json", // extra comma
- "fail5.json",
- "fail6.json",
- "fail7.json",
- "fail8.json",
- "fail9.json", // extra comma
- "pass1.json",
- "pass2.json",
- "pass3.json",
- "pass4.json",
- "round1.json", // round-trip test
- "round2.json", // unicode
- "round3.json", // bare string
- "round4.json", // bare number
- "round5.json", // bare true
- "round6.json", // bare false
- "round7.json", // bare null
-};
+#define TEST_FILE(name) {#name, json_tests::name}
+inline constexpr std::array tests{std::to_array<std::tuple<std::string_view, std::string_view>>({
+ TEST_FILE(fail1),
+ TEST_FILE(fail10),
+ TEST_FILE(fail11),
+ TEST_FILE(fail12),
+ TEST_FILE(fail13),
+ TEST_FILE(fail14),
+ TEST_FILE(fail15),
+ TEST_FILE(fail16),
+ TEST_FILE(fail17),
+ TEST_FILE(fail18),
+ TEST_FILE(fail19),
+ TEST_FILE(fail2),
+ TEST_FILE(fail20),
+ TEST_FILE(fail21),
+ TEST_FILE(fail22),
+ TEST_FILE(fail23),
+ TEST_FILE(fail24),
+ TEST_FILE(fail25),
+ TEST_FILE(fail26),
+ TEST_FILE(fail27),
+ TEST_FILE(fail28),
+ TEST_FILE(fail29),
+ TEST_FILE(fail3),
+ TEST_FILE(fail30),
+ TEST_FILE(fail31),
+ TEST_FILE(fail32),
+ TEST_FILE(fail33),
+ TEST_FILE(fail34),
+ TEST_FILE(fail35),
+ TEST_FILE(fail36),
+ TEST_FILE(fail37),
+ TEST_FILE(fail38), // invalid unicode: only first half of surrogate pair
+ TEST_FILE(fail39), // invalid unicode: only second half of surrogate pair
+ TEST_FILE(fail4), // extra comma
+ TEST_FILE(fail40), // invalid unicode: broken UTF-8
+ TEST_FILE(fail41), // invalid unicode: unfinished UTF-8
+ TEST_FILE(fail42), // valid json with garbage following a nul byte
+ TEST_FILE(fail44), // unterminated string
+ TEST_FILE(fail45), // nested beyond max depth
+ TEST_FILE(fail5),
+ TEST_FILE(fail6),
+ TEST_FILE(fail7),
+ TEST_FILE(fail8),
+ TEST_FILE(fail9), // extra comma
+ TEST_FILE(pass1),
+ TEST_FILE(pass2),
+ TEST_FILE(pass3),
+ TEST_FILE(pass4),
+ TEST_FILE(round1), // round-trip test
+ TEST_FILE(round2), // unicode
+ TEST_FILE(round3), // bare string
+ TEST_FILE(round4), // bare number
+ TEST_FILE(round5), // bare true
+ TEST_FILE(round6), // bare false
+ TEST_FILE(round7), // bare null
+})};
// Test \u handling
void unescape_unicode_test()
@@ -156,10 +185,10 @@ void no_nul_test()
assert(val.read({buf + 3, 7}));
}
-int main (int argc, char *argv[])
+int main(int argc, char* argv[])
{
- for (const auto& f: filenames) {
- runtest_file(f);
+ for (const auto& [file, json] : tests) {
+ runtest(std::string{file}, std::string{json});
}
unescape_unicode_test();
@@ -167,4 +196,3 @@ int main (int argc, char *argv[])
return 0;
}
-
diff --git a/src/util/hasher.h b/src/util/hasher.h
index 3ad6d5bb94..e4594c7dda 100644
--- a/src/util/hasher.h
+++ b/src/util/hasher.h
@@ -8,13 +8,12 @@
#include <crypto/common.h>
#include <crypto/siphash.h>
#include <primitives/transaction.h>
+#include <span.h>
#include <uint256.h>
#include <cstdint>
#include <cstring>
-template <typename C> class Span;
-
class SaltedTxidHasher
{
private:
diff --git a/src/validation.cpp b/src/validation.cpp
index aff8fe7024..3e8a7cf520 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -88,6 +88,8 @@ using node::CBlockIndexHeightOnlyComparator;
using node::CBlockIndexWorkComparator;
using node::SnapshotMetadata;
+/** Size threshold for warning about slow UTXO set flush to disk. */
+static constexpr size_t WARN_FLUSH_COINS_SIZE = 1 << 30; // 1 GiB
/** Time to wait between writing blocks/block index to disk. */
static constexpr std::chrono::hours DATABASE_WRITE_INTERVAL{1};
/** Time to wait between flushing chainstate to disk. */
@@ -2929,8 +2931,9 @@ bool Chainstate::FlushStateToDisk(
}
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
if (fDoFullFlush && !CoinsTip().GetBestBlock().IsNull()) {
- LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("write coins cache to disk (%d coins, %.2fkB)",
- coins_count, coins_mem_usage / 1000), BCLog::BENCH);
+ if (coins_mem_usage >= WARN_FLUSH_COINS_SIZE) LogWarning("Flushing large (%d GiB) UTXO set to disk, it may take several minutes", coins_mem_usage >> 30);
+ LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("write coins cache to disk (%d coins, %.2fKiB)",
+ coins_count, coins_mem_usage >> 10), BCLog::BENCH);
// Typical Coin structures on disk are around 48 bytes in size.
// Pushing a new one to the database can cause it to be written
@@ -2983,9 +2986,9 @@ void Chainstate::PruneAndFlush()
}
static void UpdateTipLog(
+ const ChainstateManager& chainman,
const CCoinsViewCache& coins_tip,
const CBlockIndex* tip,
- const CChainParams& params,
const std::string& func_name,
const std::string& prefix,
const std::string& warning_messages) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
@@ -2997,7 +3000,7 @@ static void UpdateTipLog(
tip->GetBlockHash().ToString(), tip->nHeight, tip->nVersion,
log(tip->nChainWork.getdouble()) / log(2.0), tip->m_chain_tx_count,
FormatISO8601DateTime(tip->GetBlockTime()),
- GuessVerificationProgress(params.TxData(), tip),
+ chainman.GuessVerificationProgress(tip),
coins_tip.DynamicMemoryUsage() * (1.0 / (1 << 20)),
coins_tip.GetCacheSize(),
!warning_messages.empty() ? strprintf(" warning='%s'", warning_messages) : "");
@@ -3008,15 +3011,13 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
AssertLockHeld(::cs_main);
const auto& coins_tip = this->CoinsTip();
- const CChainParams& params{m_chainman.GetParams()};
-
// The remainder of the function isn't relevant if we are not acting on
// the active chainstate, so return if need be.
if (this != &m_chainman.ActiveChainstate()) {
// Only log every so often so that we don't bury log messages at the tip.
constexpr int BACKGROUND_LOG_INTERVAL = 2000;
if (pindexNew->nHeight % BACKGROUND_LOG_INTERVAL == 0) {
- UpdateTipLog(coins_tip, pindexNew, params, __func__, "[background validation] ", "");
+ UpdateTipLog(m_chainman, coins_tip, pindexNew, __func__, "[background validation] ", "");
}
return;
}
@@ -3031,7 +3032,7 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(m_chainman, bit);
- ThresholdState state = checker.GetStateFor(pindex, params.GetConsensus(), m_chainman.m_warningcache.at(bit));
+ ThresholdState state = checker.GetStateFor(pindex, m_chainman.GetConsensus(), m_chainman.m_warningcache.at(bit));
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
if (state == ThresholdState::ACTIVE) {
@@ -3042,7 +3043,7 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
}
}
}
- UpdateTipLog(coins_tip, pindexNew, params, __func__, "",
+ UpdateTipLog(m_chainman, coins_tip, pindexNew, __func__, "",
util::Join(warning_messages, Untranslated(", ")).original);
}
@@ -3528,6 +3529,10 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
bool fInvalidFound = false;
std::shared_ptr<const CBlock> nullBlockPtr;
+ // BlockConnected signals must be sent for the original role;
+ // in case snapshot validation is completed during ActivateBestChainStep, the
+ // result of GetRole() changes from BACKGROUND to NORMAL.
+ const ChainstateRole chainstate_role{this->GetRole()};
if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace)) {
// A system error occurred
return false;
@@ -3543,7 +3548,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
assert(trace.pblock && trace.pindex);
if (m_chainman.m_options.signals) {
- m_chainman.m_options.signals->BlockConnected(this->GetRole(), trace.pblock, trace.pindex);
+ m_chainman.m_options.signals->BlockConnected(chainstate_role, trace.pblock, trace.pindex);
}
}
@@ -4720,7 +4725,7 @@ bool Chainstate::LoadChainTip()
tip->GetBlockHash().ToString(),
m_chain.Height(),
FormatISO8601DateTime(tip->GetBlockTime()),
- GuessVerificationProgress(m_chainman.GetParams().TxData(), tip));
+ m_chainman.GuessVerificationProgress(tip));
// Ensure KernelNotifications m_tip_block is set even if no new block arrives.
if (this->GetRole() != ChainstateRole::BACKGROUND) {
@@ -5611,9 +5616,12 @@ bool Chainstate::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
//! Guess how far we are in the verification process at the given block index
//! require cs_main if pindex has not been validated yet (because m_chain_tx_count might be unset)
-double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pindex) {
- if (pindex == nullptr)
+double ChainstateManager::GuessVerificationProgress(const CBlockIndex* pindex) const
+{
+ const ChainTxData& data{GetParams().TxData()};
+ if (pindex == nullptr) {
return 0.0;
+ }
if (!Assume(pindex->m_chain_tx_count > 0)) {
LogWarning("Internal bug detected: block %d has unset m_chain_tx_count (%s %s). Please report this issue here: %s\n",
diff --git a/src/validation.h b/src/validation.h
index aea7a4621b..e2ff5925c5 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -95,9 +95,6 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
bool FatalError(kernel::Notifications& notifications, BlockValidationState& state, const bilingual_str& message);
-/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
-double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex* pindex);
-
/** Prune block files up to a given height */
void PruneBlockFilesManual(Chainstate& active_chainstate, int nManualPruneHeight);
@@ -1151,6 +1148,9 @@ public:
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload() const;
+ /** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
+ double GuessVerificationProgress(const CBlockIndex* pindex) const;
+
/**
* Import blocks from an external file
*
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index cee558088f..6e6d7e053b 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -478,7 +478,6 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c
// Neither adding to the current selection nor exploring the omission branch of the last selected UTXO can
// find any solutions. Redirect to exploring the Omission branch of the penultimate selected UTXO (i.e.
// set `next_utxo` to one after the penultimate selected, then deselect the last two selected UTXOs)
- should_cut = false;
deselect_last();
should_shift = true;
}
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index ea32199497..41951e84c8 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -34,9 +34,9 @@ inline std::ostream& operator<<(std::ostream& os, const std::pair<const Serializ
namespace wallet {
-static Span<const std::byte> StringBytes(std::string_view str)
+inline std::span<const std::byte> StringBytes(std::string_view str)
{
- return AsBytes<const char>({str.data(), str.size()});
+ return std::as_bytes(std::span{str});
}
static SerializeData StringData(std::string_view str)
diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp
index 31fa00c0a2..ed77befac2 100644
--- a/src/wallet/test/fuzz/coinselection.cpp
+++ b/src/wallet/test/fuzz/coinselection.cpp
@@ -218,6 +218,7 @@ FUZZ_TARGET(coin_grinder_is_optimal)
FUZZ_TARGET(coinselection)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
std::vector<COutput> utxo_pool;
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index 50bc7e43b3..7b85fb26fc 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -56,6 +56,7 @@ void initialize_setup()
FUZZ_TARGET(wallet_notifications, .init = initialize_setup)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
// The total amount, to be distributed to the wallets a and b in txs
// without fee. Thus, the balance of the wallets should always equal the
diff --git a/src/wallet/test/fuzz/scriptpubkeyman.cpp b/src/wallet/test/fuzz/scriptpubkeyman.cpp
index 091d42f6cf..b0d8628a91 100644
--- a/src/wallet/test/fuzz/scriptpubkeyman.cpp
+++ b/src/wallet/test/fuzz/scriptpubkeyman.cpp
@@ -85,6 +85,7 @@ static DescriptorScriptPubKeyMan* CreateDescriptor(WalletDescriptor& wallet_desc
FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm)
{
+ SeedRandomStateForTest(SeedRand::ZEROS);
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
const auto& node{g_setup->m_node};
Chainstate& chainstate{node.chainman->ActiveChainstate()};
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 557fcc7cea..60b3fb4e20 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -148,6 +148,10 @@ class BIP65Test(BitcoinTestFramework):
# create and test one invalid tx per CLTV failure reason (5 in total)
for i in range(5):
spendtx = wallet.create_self_transfer()['tx']
+ assert_equal(len(spendtx.vin), 1)
+ coin = spendtx.vin[0]
+ coin_txid = format(coin.prevout.hash, '064x')
+ coin_vout = coin.prevout.n
cltv_invalidate(spendtx, i)
expected_cltv_reject_reason = [
@@ -159,12 +163,15 @@ class BIP65Test(BitcoinTestFramework):
][i]
# First we show that this tx is valid except for CLTV by getting it
# rejected from the mempool for exactly that reason.
+ spendtx_txid = spendtx.hash
+ spendtx_wtxid = spendtx.getwtxid()
assert_equal(
[{
- 'txid': spendtx.hash,
- 'wtxid': spendtx.getwtxid(),
+ 'txid': spendtx_txid,
+ 'wtxid': spendtx_wtxid,
'allowed': False,
'reject-reason': expected_cltv_reject_reason,
+ 'reject-details': expected_cltv_reject_reason + f", input 0 of {spendtx_txid} (wtxid {spendtx_wtxid}), spending {coin_txid}:{coin_vout}"
}],
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
)
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index f6b832106b..0c3b0f1224 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -109,18 +109,23 @@ class BIP66Test(BitcoinTestFramework):
self.log.info("Test that transactions with non-DER signatures cannot appear in a block")
block.nVersion = 4
- spendtx = self.create_tx(self.coinbase_txids[1])
+ coin_txid = self.coinbase_txids[1]
+ spendtx = self.create_tx(coin_txid)
unDERify(spendtx)
spendtx.rehash()
# First we show that this tx is valid except for DERSIG by getting it
# rejected from the mempool for exactly that reason.
+ spendtx_txid = spendtx.hash
+ spendtx_wtxid = spendtx.getwtxid()
assert_equal(
[{
- 'txid': spendtx.hash,
- 'wtxid': spendtx.getwtxid(),
+ 'txid': spendtx_txid,
+ 'wtxid': spendtx_wtxid,
'allowed': False,
'reject-reason': 'mandatory-script-verify-flag-failed (Non-canonical DER signature)',
+ 'reject-details': 'mandatory-script-verify-flag-failed (Non-canonical DER signature), ' +
+ f"input 0 of {spendtx_txid} (wtxid {spendtx_wtxid}), spending {coin_txid}:0"
}],
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
)
diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py
index 030bf51ed8..191c6466df 100755
--- a/test/functional/feature_index_prune.py
+++ b/test/functional/feature_index_prune.py
@@ -1,8 +1,9 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2022 The Bitcoin Core developers
+# Copyright (c) 2020-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test indices in conjunction with prune."""
+import concurrent.futures
import os
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -19,9 +20,25 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
["-fastprune", "-prune=1", "-blockfilterindex=1"],
["-fastprune", "-prune=1", "-coinstatsindex=1"],
["-fastprune", "-prune=1", "-blockfilterindex=1", "-coinstatsindex=1"],
- []
+ [],
]
+ def setup_network(self):
+ self.setup_nodes() # No P2P connection, so that linear_sync works
+
+ def linear_sync(self, node_from, *, height_from=None):
+ # Linear sync over RPC, because P2P sync may not be linear
+ to_height = node_from.getblockcount()
+ if height_from is None:
+ height_from = min([n.getblockcount() for n in self.nodes]) + 1
+ with concurrent.futures.ThreadPoolExecutor(max_workers=self.num_nodes) as rpc_threads:
+ for i in range(height_from, to_height + 1):
+ b = node_from.getblock(blockhash=node_from.getblockhash(i), verbosity=0)
+ list(rpc_threads.map(lambda n: n.submitblock(b), self.nodes))
+
+ def generate(self, node, num_blocks, sync_fun=None):
+ return super().generate(node, num_blocks, sync_fun=sync_fun or (lambda: self.linear_sync(node)))
+
def sync_index(self, height):
expected_filter = {
'basic block filter index': {'synced': True, 'best_block_height': height},
@@ -36,22 +53,9 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
expected = {**expected_filter, **expected_stats}
self.wait_until(lambda: self.nodes[2].getindexinfo() == expected)
- def reconnect_nodes(self):
- self.connect_nodes(0,1)
- self.connect_nodes(0,2)
- self.connect_nodes(0,3)
-
- def mine_batches(self, blocks):
- n = blocks // 250
- for _ in range(n):
- self.generate(self.nodes[0], 250)
- self.generate(self.nodes[0], blocks % 250)
- self.sync_blocks()
-
def restart_without_indices(self):
for i in range(3):
self.restart_node(i, extra_args=["-fastprune", "-prune=1"])
- self.reconnect_nodes()
def run_test(self):
filter_nodes = [self.nodes[0], self.nodes[2]]
@@ -65,7 +69,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
for node in stats_nodes:
assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash']
- self.mine_batches(500)
+ self.generate(self.nodes[0], 500)
self.sync_index(height=700)
self.log.info("prune some blocks")
@@ -104,7 +108,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
msg = "Querying specific block heights requires coinstatsindex"
assert_raises_rpc_error(-8, msg, node.gettxoutsetinfo, "muhash", height_hash)
- self.mine_batches(749)
+ self.generate(self.nodes[0], 749)
self.log.info("prune exactly up to the indices best blocks while the indices are disabled")
for i in range(3):
@@ -118,7 +122,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
self.log.info("prune further than the indices best blocks while the indices are disabled")
self.restart_without_indices()
- self.mine_batches(1000)
+ self.generate(self.nodes[0], 1000)
for i in range(3):
pruneheight_3 = self.nodes[i].pruneblockchain(2000)
@@ -134,12 +138,10 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
self.log.info("make sure the nodes start again with the indices and an additional -reindex arg")
for i in range(3):
- restart_args = self.extra_args[i]+["-reindex"]
+ restart_args = self.extra_args[i] + ["-reindex"]
self.restart_node(i, extra_args=restart_args)
- # The nodes need to be reconnected to the non-pruning node upon restart, otherwise they will be stuck
- self.connect_nodes(i, 3)
- self.sync_blocks(timeout=300)
+ self.linear_sync(self.nodes[3])
self.sync_index(height=2500)
for node in self.nodes[:2]:
@@ -150,8 +152,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
self.log.info("ensure that prune locks don't prevent indices from failing in a reorg scenario")
with self.nodes[0].assert_debug_log(['basic block filter index prune lock moved back to 2480']):
self.nodes[3].invalidateblock(self.nodes[0].getblockhash(2480))
- self.generate(self.nodes[3], 30)
- self.sync_blocks()
+ self.generate(self.nodes[3], 30, sync_fun=lambda: self.linear_sync(self.nodes[3], height_from=2480))
if __name__ == '__main__':
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index 136cdd024d..ad5a7e4831 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -122,7 +122,7 @@ class MaxUploadTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].getpeerinfo()), 3)
# At most a couple more tries should succeed (depending on how long
# the test has been running so far).
- with self.nodes[0].assert_debug_log(expected_msgs=["historical block serving limit reached, disconnect peer"]):
+ with self.nodes[0].assert_debug_log(expected_msgs=["historical block serving limit reached, disconnecting peer=0"]):
for _ in range(3):
p2p_conns[0].send_message(getdata_request)
p2p_conns[0].wait_for_disconnect()
@@ -147,7 +147,7 @@ class MaxUploadTest(BitcoinTestFramework):
# But if p2p_conns[1] tries for an old block, it gets disconnected too.
getdata_request.inv = [CInv(MSG_BLOCK, big_old_block)]
- with self.nodes[0].assert_debug_log(expected_msgs=["historical block serving limit reached, disconnect peer"]):
+ with self.nodes[0].assert_debug_log(expected_msgs=["historical block serving limit reached, disconnecting peer=1"]):
p2p_conns[1].send_message(getdata_request)
p2p_conns[1].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 1)
@@ -197,7 +197,7 @@ class MaxUploadTest(BitcoinTestFramework):
assert_equal(peer_info[0]['permissions'], ['download'])
self.log.info("Peer gets disconnected for a mempool request after limit is reached")
- with self.nodes[0].assert_debug_log(expected_msgs=["mempool request with bandwidth limit reached, disconnect peer"]):
+ with self.nodes[0].assert_debug_log(expected_msgs=["mempool request with bandwidth limit reached, disconnecting peer=0"]):
peer.send_message(msg_mempool())
peer.wait_for_disconnect()
diff --git a/test/functional/feature_port.py b/test/functional/feature_port.py
new file mode 100755
index 0000000000..2746d7d79c
--- /dev/null
+++ b/test/functional/feature_port.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+# Copyright (c) 2024-present The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""
+Test the -port option and its interactions with
+-bind.
+"""
+
+from test_framework.test_framework import (
+ BitcoinTestFramework,
+)
+from test_framework.util import (
+ p2p_port,
+)
+
+
+class PortTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ # Avoid any -bind= on the command line.
+ self.bind_to_localhost_only = False
+ self.num_nodes = 1
+
+ def run_test(self):
+ node = self.nodes[0]
+ node.has_explicit_bind = True
+ port1 = p2p_port(self.num_nodes)
+ port2 = p2p_port(self.num_nodes + 5)
+
+ self.log.info("When starting with -port, bitcoind binds to it and uses port + 1 for an onion bind")
+ with node.assert_debug_log(expected_msgs=[f'Bound to 0.0.0.0:{port1}', f'Bound to 127.0.0.1:{port1 + 1}']):
+ self.restart_node(0, extra_args=["-listen", f"-port={port1}"])
+
+ self.log.info("When specifying -port multiple times, only the last one is taken")
+ with node.assert_debug_log(expected_msgs=[f'Bound to 0.0.0.0:{port2}', f'Bound to 127.0.0.1:{port2 + 1}'], unexpected_msgs=[f'Bound to 0.0.0.0:{port1}']):
+ self.restart_node(0, extra_args=["-listen", f"-port={port1}", f"-port={port2}"])
+
+ self.log.info("When specifying ports with both -port and -bind, the one from -port is ignored")
+ with node.assert_debug_log(expected_msgs=[f'Bound to 0.0.0.0:{port2}'], unexpected_msgs=[f'Bound to 0.0.0.0:{port1}']):
+ self.restart_node(0, extra_args=["-listen", f"-port={port1}", f"-bind=0.0.0.0:{port2}"])
+
+ self.log.info("When -bind specifies no port, the values from -port and -bind are combined")
+ with self.nodes[0].assert_debug_log(expected_msgs=[f'Bound to 0.0.0.0:{port1}']):
+ self.restart_node(0, extra_args=["-listen", f"-port={port1}", "-bind=0.0.0.0"])
+
+ self.log.info("When an onion bind specifies no port, the value from -port, incremented by 1, is taken")
+ with self.nodes[0].assert_debug_log(expected_msgs=[f'Bound to 127.0.0.1:{port1 + 1}']):
+ self.restart_node(0, extra_args=["-listen", f"-port={port1}", "-bind=127.0.0.1=onion"])
+
+ self.log.info("Invalid values for -port raise errors")
+ self.stop_node(0)
+ node.extra_args = ["-listen", "-port=65536"]
+ node.assert_start_raises_init_error(expected_msg="Error: Invalid port specified in -port: '65536'")
+ node.extra_args = ["-listen", "-port=0"]
+ node.assert_start_raises_init_error(expected_msg="Error: Invalid port specified in -port: '0'")
+
+
+if __name__ == '__main__':
+ PortTest(__file__).main()
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index d9700e2ee2..ef2ecfab9e 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -103,14 +103,22 @@ class ReplaceByFeeTest(BitcoinTestFramework):
"""Simple doublespend"""
# we use MiniWallet to create a transaction template with inputs correctly set,
# and modify the output (amount, scriptPubKey) according to our needs
- tx = self.wallet.create_self_transfer()["tx"]
+ tx = self.wallet.create_self_transfer(fee_rate=Decimal("0.003"))["tx"]
tx1a_txid = self.nodes[0].sendrawtransaction(tx.serialize().hex())
# Should fail because we haven't changed the fee
tx.vout[0].scriptPubKey[-1] ^= 1
+ tx.rehash()
+ tx_hex = tx.serialize().hex()
# This will raise an exception due to insufficient fee
- assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx.serialize().hex(), 0)
+ reject_reason = "insufficient fee"
+ reject_details = f"{reject_reason}, rejecting replacement {tx.hash}; new feerate 0.00300000 BTC/kvB <= old feerate 0.00300000 BTC/kvB"
+ res = self.nodes[0].testmempoolaccept(rawtxs=[tx_hex])[0]
+ assert_equal(res["reject-reason"], reject_reason)
+ assert_equal(res["reject-details"], reject_details)
+ assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, tx_hex, 0)
+
# Extra 0.1 BTC fee
tx.vout[0].nValue -= int(0.1 * COIN)
@@ -154,7 +162,14 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx_hex = dbl_tx.serialize().hex()
# This will raise an exception due to insufficient fee
- assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
+ reject_reason = "insufficient fee"
+ reject_details = f"{reject_reason}, rejecting replacement {dbl_tx.hash}, less fees than conflicting txs; 3.00 < 4.00"
+ res = self.nodes[0].testmempoolaccept(rawtxs=[dbl_tx_hex])[0]
+ assert_equal(res["reject-reason"], reject_reason)
+ assert_equal(res["reject-details"], reject_details)
+ assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
+
+
# Accepted with sufficient fee
dbl_tx.vout[0].nValue = int(0.1 * COIN)
@@ -273,22 +288,30 @@ class ReplaceByFeeTest(BitcoinTestFramework):
utxo1 = self.make_utxo(self.nodes[0], int(1.2 * COIN))
utxo2 = self.make_utxo(self.nodes[0], 3 * COIN)
- tx1a_utxo = self.wallet.send_self_transfer(
+ tx1a = self.wallet.send_self_transfer(
from_node=self.nodes[0],
utxo_to_spend=utxo1,
sequence=0,
fee=Decimal("0.1"),
- )["new_utxo"]
+ )
+ tx1a_utxo = tx1a["new_utxo"]
# Direct spend an output of the transaction we're replacing.
- tx2_hex = self.wallet.create_self_transfer_multi(
+ tx2 = self.wallet.create_self_transfer_multi(
utxos_to_spend=[utxo1, utxo2, tx1a_utxo],
sequence=0,
amount_per_output=int(COIN * tx1a_utxo["value"]),
- )["hex"]
+ )["tx"]
+ tx2_hex = tx2.serialize().hex()
# This will raise an exception
- assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, 0)
+ reject_reason = "bad-txns-spends-conflicting-tx"
+ reject_details = f"{reject_reason}, {tx2.hash} spends conflicting transaction {tx1a['tx'].hash}"
+ res = self.nodes[0].testmempoolaccept(rawtxs=[tx2_hex])[0]
+ assert_equal(res["reject-reason"], reject_reason)
+ assert_equal(res["reject-details"], reject_details)
+ assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, tx2_hex, 0)
+
# Spend tx1a's output to test the indirect case.
tx1b_utxo = self.wallet.send_self_transfer(
@@ -319,14 +342,21 @@ class ReplaceByFeeTest(BitcoinTestFramework):
fee=Decimal("0.1"),
)
- tx2_hex = self.wallet.create_self_transfer_multi(
+ tx2 = self.wallet.create_self_transfer_multi(
utxos_to_spend=[confirmed_utxo, unconfirmed_utxo],
sequence=0,
amount_per_output=1 * COIN,
- )["hex"]
+ )["tx"]
+ tx2_hex = tx2.serialize().hex()
# This will raise an exception
- assert_raises_rpc_error(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, 0)
+ reject_reason = "replacement-adds-unconfirmed"
+ reject_details = f"{reject_reason}, replacement {tx2.hash} adds unconfirmed input, idx 1"
+ res = self.nodes[0].testmempoolaccept(rawtxs=[tx2_hex])[0]
+ assert_equal(res["reject-reason"], reject_reason)
+ assert_equal(res["reject-details"], reject_details)
+ assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, tx2_hex, 0)
+
def test_too_many_replacements(self):
"""Replacements that evict too many transactions are rejected"""
@@ -368,7 +398,13 @@ class ReplaceByFeeTest(BitcoinTestFramework):
double_tx_hex = double_tx.serialize().hex()
# This will raise an exception
- assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, 0)
+ reject_reason = "too many potential replacements"
+ reject_details = f"{reject_reason}, rejecting replacement {double_tx.hash}; too many potential replacements ({MAX_REPLACEMENT_LIMIT + 1} > {MAX_REPLACEMENT_LIMIT})"
+ res = self.nodes[0].testmempoolaccept(rawtxs=[double_tx_hex])[0]
+ assert_equal(res["reject-reason"], reject_reason)
+ assert_equal(res["reject-details"], reject_details)
+ assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, double_tx_hex, 0)
+
# If we remove an input, it should pass
double_tx.vin.pop()
diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py
index b648266cae..63091b3ee8 100755
--- a/test/functional/feature_signet.py
+++ b/test/functional/feature_signet.py
@@ -9,6 +9,8 @@ from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+SIGNET_DEFAULT_CHALLENGE = '512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae'
+
signet_blocks = [
'00000020f61eee3b63a380a477a063af32b2bbc97c9ff9f01f2c4225e973988108000000f575c83235984e7dc4afc1f30944c170462e84437ab6f2d52e16878a79e4678bd1914d5fae77031eccf4070001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025151feffffff0200f2052a010000001600149243f727dd5343293eb83174324019ec16c2630f0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402205e423a8754336ca99dbe16509b877ef1bf98d008836c725005b3c787c41ebe46022047246e4467ad7cc7f1ad98662afcaf14c115e0095a227c7b05c5182591c23e7e01000120000000000000000000000000000000000000000000000000000000000000000000000000',
'00000020533b53ded9bff4adc94101d32400a144c54edc5ed492a3b26c63b2d686000000b38fef50592017cfafbcab88eb3d9cf50b2c801711cad8299495d26df5e54812e7914d5fae77031ecfdd0b0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025251feffffff0200f2052a01000000160014fd09839740f0e0b4fc6d5e2527e4022aa9b89dfa0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022031d64a1692cdad1fc0ced69838169fe19ae01be524d831b95fcf5ea4e6541c3c02204f9dea0801df8b4d0cd0857c62ab35c6c25cc47c930630dc7fe723531daa3e9b01000120000000000000000000000000000000000000000000000000000000000000000000000000',
@@ -22,21 +24,31 @@ signet_blocks = [
'00000020a868e8514be5e46dabd6a122132f423f36a43b716a40c394e2a8d063e1010000f4c6c717e99d800c699c25a2006a75a0c5c09f432a936f385e6fce139cdbd1a5e9964d5fae77031e7d026e0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025a51feffffff0200f2052a01000000160014aaa671c82b138e3b8f510cd801e5f2bd0aa305940000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022042309f4c3c7a1a2ac8c24f890f962df1c0086cec10be0868087cfc427520cb2702201dafee8911c269b7e786e242045bb57cef3f5b0f177010c6159abae42f646cc501000120000000000000000000000000000000000000000000000000000000000000000000000000',
]
+class SignetParams:
+ def __init__(self, challenge=None):
+ if challenge is None:
+ self.challenge = SIGNET_DEFAULT_CHALLENGE
+ self.shared_args = []
+ else:
+ self.challenge = challenge
+ self.shared_args = [f"-signetchallenge={challenge}"]
class SignetBasicTest(BitcoinTestFramework):
def set_test_params(self):
self.chain = "signet"
self.num_nodes = 6
self.setup_clean_chain = True
- shared_args1 = ["-signetchallenge=51"] # OP_TRUE
- shared_args2 = [] # default challenge
- # we use the exact same challenge except we do it as a 2-of-2, which means it should fail
- shared_args3 = ["-signetchallenge=522103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae"]
+ self.signets = [
+ SignetParams(challenge='51'), # OP_TRUE
+ SignetParams(), # default challenge
+ # default challenge as a 2-of-2, which means it should fail
+ SignetParams(challenge='522103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae')
+ ]
self.extra_args = [
- shared_args1, shared_args1,
- shared_args2, shared_args2,
- shared_args3, shared_args3,
+ self.signets[0].shared_args, self.signets[0].shared_args,
+ self.signets[1].shared_args, self.signets[1].shared_args,
+ self.signets[2].shared_args, self.signets[2].shared_args,
]
def setup_network(self):
@@ -50,14 +62,28 @@ class SignetBasicTest(BitcoinTestFramework):
def run_test(self):
self.log.info("basic tests using OP_TRUE challenge")
+ self.log.info('getblockchaininfo')
+ def check_getblockchaininfo(node_idx, signet_idx):
+ blockchain_info = self.nodes[node_idx].getblockchaininfo()
+ assert_equal(blockchain_info['chain'], 'signet')
+ assert_equal(blockchain_info['signet_challenge'], self.signets[signet_idx].challenge)
+ check_getblockchaininfo(node_idx=1, signet_idx=0)
+ check_getblockchaininfo(node_idx=2, signet_idx=1)
+ check_getblockchaininfo(node_idx=5, signet_idx=2)
+
self.log.info('getmininginfo')
- mining_info = self.nodes[0].getmininginfo()
- assert_equal(mining_info['blocks'], 0)
- assert_equal(mining_info['chain'], 'signet')
- assert 'currentblocktx' not in mining_info
- assert 'currentblockweight' not in mining_info
- assert_equal(mining_info['networkhashps'], Decimal('0'))
- assert_equal(mining_info['pooledtx'], 0)
+ def check_getmininginfo(node_idx, signet_idx):
+ mining_info = self.nodes[node_idx].getmininginfo()
+ assert_equal(mining_info['blocks'], 0)
+ assert_equal(mining_info['chain'], 'signet')
+ assert 'currentblocktx' not in mining_info
+ assert 'currentblockweight' not in mining_info
+ assert_equal(mining_info['networkhashps'], Decimal('0'))
+ assert_equal(mining_info['pooledtx'], 0)
+ assert_equal(mining_info['signet_challenge'], self.signets[signet_idx].challenge)
+ check_getmininginfo(node_idx=0, signet_idx=0)
+ check_getmininginfo(node_idx=3, signet_idx=1)
+ check_getmininginfo(node_idx=4, signet_idx=2)
self.generate(self.nodes[0], 1, sync_fun=self.no_op)
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index ea609bbb34..27ecc3b4a8 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -67,6 +67,8 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
if "fees" in r:
r["fees"].pop("effective-feerate")
r["fees"].pop("effective-includes")
+ if "reject-details" in r:
+ r.pop("reject-details")
assert_equal(result_expected, result_test)
assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state
diff --git a/test/functional/mempool_accept_wtxid.py b/test/functional/mempool_accept_wtxid.py
index e00e7b1ae4..f74d00e37c 100755
--- a/test/functional/mempool_accept_wtxid.py
+++ b/test/functional/mempool_accept_wtxid.py
@@ -100,13 +100,15 @@ class MempoolWtxidTest(BitcoinTestFramework):
"txid": child_one_txid,
"wtxid": child_one_wtxid,
"allowed": False,
- "reject-reason": "txn-already-in-mempool"
+ "reject-reason": "txn-already-in-mempool",
+ "reject-details": "txn-already-in-mempool"
}])
assert_equal(node.testmempoolaccept([child_two.serialize().hex()])[0], {
"txid": child_two_txid,
"wtxid": child_two_wtxid,
"allowed": False,
- "reject-reason": "txn-same-nonwitness-data-in-mempool"
+ "reject-reason": "txn-same-nonwitness-data-in-mempool",
+ "reject-details": "txn-same-nonwitness-data-in-mempool"
})
# sendrawtransaction will not throw but quits early when the exact same transaction is already in mempool
diff --git a/test/functional/mempool_ephemeral_dust.py b/test/functional/mempool_ephemeral_dust.py
index 56e4b404e4..e614a9e607 100755
--- a/test/functional/mempool_ephemeral_dust.py
+++ b/test/functional/mempool_ephemeral_dust.py
@@ -126,7 +126,7 @@ class EphemeralDustTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].getrawmempool()), 2)
assert_mempool_contents(self, self.nodes[0], expected=[dusty_tx["tx"], sweep_tx["tx"]])
- # Node restart; doesn't allow allow ephemeral transaction back in due to individual submission
+ # Node restart; doesn't allow ephemeral transaction back in due to individual submission
# resulting in 0-fee. Supporting re-submission of CPFP packages on restart is desired but not
# yet implemented.
self.restart_node(0)
@@ -325,7 +325,7 @@ class EphemeralDustTest(BitcoinTestFramework):
dusty_tx, _ = self.create_ephemeral_dust_package(tx_version=3)
assert_raises_rpc_error(-26, "min relay fee not met", self.nodes[0].sendrawtransaction, dusty_tx["hex"])
- block_res = self.nodes[0].rpc.generateblock(self.wallet.get_address(), [dusty_tx["hex"]])
+ block_res = self.generateblock(self.nodes[0], self.wallet.get_address(), [dusty_tx["hex"]], sync_fun=self.no_op)
self.nodes[0].invalidateblock(block_res["hash"])
assert_mempool_contents(self, self.nodes[0], expected=[dusty_tx["tx"]], sync=False)
@@ -335,7 +335,7 @@ class EphemeralDustTest(BitcoinTestFramework):
assert_raises_rpc_error(-26, "min relay fee not met", self.nodes[0].sendrawtransaction, sweep_tx["hex"])
# Mine the sweep then re-org, the sweep will not make it back in due to spend checks
- block_res = self.nodes[0].rpc.generateblock(self.wallet.get_address(), [dusty_tx["hex"], sweep_tx["hex"]])
+ block_res = self.generateblock(self.nodes[0], self.wallet.get_address(), [dusty_tx["hex"], sweep_tx["hex"]], sync_fun=self.no_op)
self.nodes[0].invalidateblock(block_res["hash"])
assert_mempool_contents(self, self.nodes[0], expected=[dusty_tx["tx"]], sync=False)
@@ -344,7 +344,7 @@ class EphemeralDustTest(BitcoinTestFramework):
self.add_output_to_create_multi_result(sweep_tx_2)
assert_raises_rpc_error(-26, "min relay fee not met", self.nodes[0].sendrawtransaction, sweep_tx_2["hex"])
- reconsider_block_res = self.nodes[0].rpc.generateblock(self.wallet.get_address(), [dusty_tx["hex"], sweep_tx_2["hex"]])
+ reconsider_block_res = self.generateblock(self.nodes[0], self.wallet.get_address(), [dusty_tx["hex"], sweep_tx_2["hex"]], sync_fun=self.no_op)
self.nodes[0].invalidateblock(reconsider_block_res["hash"])
assert_mempool_contents(self, self.nodes[0], expected=[dusty_tx["tx"], sweep_tx_2["tx"]], sync=False)
@@ -357,13 +357,13 @@ class EphemeralDustTest(BitcoinTestFramework):
self.log.info("Test that ephemeral dust tx with fees or multi dust don't enter mempool via reorg")
multi_dusty_tx, _ = self.create_ephemeral_dust_package(tx_version=3, num_dust_outputs=2)
- block_res = self.nodes[0].rpc.generateblock(self.wallet.get_address(), [multi_dusty_tx["hex"]])
+ block_res = self.generateblock(self.nodes[0], self.wallet.get_address(), [multi_dusty_tx["hex"]], sync_fun=self.no_op)
self.nodes[0].invalidateblock(block_res["hash"])
assert_equal(self.nodes[0].getrawmempool(), [])
# With fee and one dust
dusty_fee_tx, _ = self.create_ephemeral_dust_package(tx_version=3, dust_tx_fee=1)
- block_res = self.nodes[0].rpc.generateblock(self.wallet.get_address(), [dusty_fee_tx["hex"]])
+ block_res = self.generateblock(self.nodes[0], self.wallet.get_address(), [dusty_fee_tx["hex"]], sync_fun=self.no_op)
self.nodes[0].invalidateblock(block_res["hash"])
assert_equal(self.nodes[0].getrawmempool(), [])
diff --git a/test/functional/mempool_package_rbf.py b/test/functional/mempool_package_rbf.py
index 7c0947a33d..4dc6f8fe36 100755
--- a/test/functional/mempool_package_rbf.py
+++ b/test/functional/mempool_package_rbf.py
@@ -219,7 +219,7 @@ class PackageRBFTest(BitcoinTestFramework):
package_child = self.wallet.create_self_transfer(fee_rate=child_feerate, utxo_to_spend=package_parent["new_utxos"][0])
pkg_results = node.submitpackage([package_parent["hex"], package_child["hex"]], maxfeerate=0)
- assert_equal(f"package RBF failed: too many potential replacements, rejecting replacement {package_child['tx'].rehash()}; too many potential replacements (102 > 100)\n", pkg_results["package_msg"])
+ assert_equal(f"package RBF failed: too many potential replacements, rejecting replacement {package_child['tx'].rehash()}; too many potential replacements (102 > 100)", pkg_results["package_msg"])
self.assert_mempool_contents(expected=expected_txns)
# Make singleton tx to conflict with in next batch
@@ -234,7 +234,7 @@ class PackageRBFTest(BitcoinTestFramework):
package_parent = self.wallet.create_self_transfer_multi(utxos_to_spend=double_spending_coins, fee_per_output=parent_fee_per_conflict)
package_child = self.wallet.create_self_transfer(fee_rate=child_feerate, utxo_to_spend=package_parent["new_utxos"][0])
pkg_results = node.submitpackage([package_parent["hex"], package_child["hex"]], maxfeerate=0)
- assert_equal(f"package RBF failed: too many potential replacements, rejecting replacement {package_child['tx'].rehash()}; too many potential replacements (101 > 100)\n", pkg_results["package_msg"])
+ assert_equal(f"package RBF failed: too many potential replacements, rejecting replacement {package_child['tx'].rehash()}; too many potential replacements (101 > 100)", pkg_results["package_msg"])
self.assert_mempool_contents(expected=expected_txns)
# Finally, evict MAX_REPLACEMENT_CANDIDATES
diff --git a/test/functional/p2p_addrv2_relay.py b/test/functional/p2p_addrv2_relay.py
index d5ded926d3..8012137971 100755
--- a/test/functional/p2p_addrv2_relay.py
+++ b/test/functional/p2p_addrv2_relay.py
@@ -78,7 +78,7 @@ class AddrTest(BitcoinTestFramework):
def run_test(self):
self.log.info('Check disconnection when sending sendaddrv2 after verack')
conn = self.nodes[0].add_p2p_connection(P2PInterface())
- with self.nodes[0].assert_debug_log(['sendaddrv2 received after verack from peer=0; disconnecting']):
+ with self.nodes[0].assert_debug_log(['sendaddrv2 received after verack, disconnecting peer=0']):
conn.send_message(msg_sendaddrv2())
conn.wait_for_disconnect()
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index f800e815d8..7848cdaadb 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -172,7 +172,7 @@ class P2PLeakTest(BitcoinTestFramework):
self.log.info('Check that old peers are disconnected')
p2p_old_peer = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False)
- with self.nodes[0].assert_debug_log(["using obsolete version 31799; disconnecting"]):
+ with self.nodes[0].assert_debug_log(["using obsolete version 31799, disconnecting peer=5"]):
p2p_old_peer.send_message(self.create_old_version(31799))
p2p_old_peer.wait_for_disconnect()
diff --git a/test/functional/p2p_sendtxrcncl.py b/test/functional/p2p_sendtxrcncl.py
index 2c7216b5ca..3f1fca5c78 100755
--- a/test/functional/p2p_sendtxrcncl.py
+++ b/test/functional/p2p_sendtxrcncl.py
@@ -168,7 +168,7 @@ class SendTxRcnclTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(["received: sendtxrcncl"]):
peer.send_message(create_sendtxrcncl_msg())
self.log.info('second SENDTXRCNCL triggers a disconnect')
- with self.nodes[0].assert_debug_log(["(sendtxrcncl received from already registered peer); disconnecting"]):
+ with self.nodes[0].assert_debug_log(["(sendtxrcncl received from already registered peer), disconnecting peer=0"]):
peer.send_message(create_sendtxrcncl_msg())
peer.wait_for_disconnect()
@@ -226,7 +226,7 @@ class SendTxRcnclTest(BitcoinTestFramework):
self.log.info('SENDTXRCNCL if block-relay-only triggers a disconnect')
peer = self.nodes[0].add_outbound_p2p_connection(
PeerNoVerack(), wait_for_verack=False, p2p_idx=0, connection_type="block-relay-only")
- with self.nodes[0].assert_debug_log(["we indicated no tx relay; disconnecting"]):
+ with self.nodes[0].assert_debug_log(["we indicated no tx relay, disconnecting peer=5"]):
peer.send_message(create_sendtxrcncl_msg())
peer.wait_for_disconnect()
diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py
index 1fd78e163b..ce01547887 100755
--- a/test/functional/p2p_timeouts.py
+++ b/test/functional/p2p_timeouts.py
@@ -84,15 +84,15 @@ class TimeoutsTest(BitcoinTestFramework):
if self.options.v2transport:
expected_timeout_logs = [
- "version handshake timeout peer=0",
- "version handshake timeout peer=1",
- "version handshake timeout peer=2",
+ "version handshake timeout, disconnecting peer=0",
+ "version handshake timeout, disconnecting peer=1",
+ "version handshake timeout, disconnecting peer=2",
]
else:
expected_timeout_logs = [
- "version handshake timeout peer=0",
- "socket no message in first 3 seconds, 1 0 peer=1",
- "socket no message in first 3 seconds, 0 0 peer=2",
+ "version handshake timeout, disconnecting peer=0",
+ "socket no message in first 3 seconds, never sent to peer, disconnecting peer=1",
+ "socket no message in first 3 seconds, never received from peer, never sent to peer, disconnecting peer=2",
]
with self.nodes[0].assert_debug_log(expected_msgs=expected_timeout_logs):
diff --git a/test/functional/p2p_v2_misbehaving.py b/test/functional/p2p_v2_misbehaving.py
index 0af96a4f8c..ee589010cd 100755
--- a/test/functional/p2p_v2_misbehaving.py
+++ b/test/functional/p2p_v2_misbehaving.py
@@ -151,7 +151,7 @@ class EncryptedP2PMisbehaving(BitcoinTestFramework):
# Ensure that the bytes sent after 4 bytes network magic are actually received.
self.wait_until(lambda: node0.getpeerinfo()[-1]["bytesrecv"] > 4)
self.wait_until(lambda: node0.getpeerinfo()[-1]["bytessent"] > 0)
- with node0.assert_debug_log(['V2 handshake timeout peer=0']):
+ with node0.assert_debug_log(['V2 handshake timeout, disconnecting peer=0']):
node0.bumpmocktime(4) # `InactivityCheck()` triggers now
peer1.wait_for_disconnect(timeout=1)
self.log.info('successful disconnection since modified ellswift was sent as response')
@@ -162,7 +162,7 @@ class EncryptedP2PMisbehaving(BitcoinTestFramework):
expected_debug_message = [
[], # EARLY_KEY_RESPONSE
["V2 transport error: missing garbage terminator, peer=1"], # EXCESS_GARBAGE
- ["V2 handshake timeout peer=3"], # WRONG_GARBAGE_TERMINATOR
+ ["V2 handshake timeout, disconnecting peer=3"], # WRONG_GARBAGE_TERMINATOR
["V2 transport error: packet decryption failure"], # WRONG_GARBAGE
["V2 transport error: packet decryption failure"], # SEND_NO_AAD
[], # SEND_NON_EMPTY_VERSION_PACKET
diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py
index 68de900664..618bbb2e00 100755
--- a/test/functional/rpc_generate.py
+++ b/test/functional/rpc_generate.py
@@ -1,9 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2022 The Bitcoin Core developers
+# Copyright (c) 2020-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test generate* RPCs."""
+from concurrent.futures import ThreadPoolExecutor
+
from test_framework.test_framework import BitcoinTestFramework
from test_framework.wallet import MiniWallet
from test_framework.util import (
@@ -83,11 +85,18 @@ class RPCGenerateTest(BitcoinTestFramework):
txid = block['tx'][1]
assert_equal(node.getrawtransaction(txid=txid, verbose=False, blockhash=hash), rawtx)
+ # Ensure that generateblock can be called concurrently by many threads.
+ self.log.info('Generate blocks in parallel')
+ generate_50_blocks = lambda n: [n.generateblock(output=address, transactions=[]) for _ in range(50)]
+ rpcs = [node.cli for _ in range(6)]
+ with ThreadPoolExecutor(max_workers=len(rpcs)) as threads:
+ list(threads.map(generate_50_blocks, rpcs))
+
self.log.info('Fail to generate block with out of order txs')
txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
utxo1 = miniwallet.get_utxo(txid=txid1)
rawtx2 = miniwallet.create_self_transfer(utxo_to_spend=utxo1)['hex']
- assert_raises_rpc_error(-25, 'testBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1])
+ assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1])
self.log.info('Fail to generate block with txid not in mempool')
missing_txid = '0000000000000000000000000000000000000000000000000000000000000000'
diff --git a/test/functional/rpc_getdescriptoractivity.py b/test/functional/rpc_getdescriptoractivity.py
index 3efa1948b7..a0dc43718b 100755
--- a/test/functional/rpc_getdescriptoractivity.py
+++ b/test/functional/rpc_getdescriptoractivity.py
@@ -20,7 +20,7 @@ class GetBlocksActivityTest(BitcoinTestFramework):
node = self.nodes[0]
wallet = MiniWallet(node)
node.setmocktime(node.getblockheader(node.getbestblockhash())['time'])
- wallet.generate(200, invalid_call=False)
+ self.generate(wallet, 200)
self.test_no_activity(node)
self.test_activity_in_block(node, wallet)
@@ -195,7 +195,7 @@ class GetBlocksActivityTest(BitcoinTestFramework):
def test_no_address(self, node, wallet):
raw_wallet = MiniWallet(self.nodes[0], mode=MiniWalletMode.RAW_P2PK)
- raw_wallet.generate(100, invalid_call=False)
+ self.generate(raw_wallet, 100)
no_addr_tx = raw_wallet.send_self_transfer(from_node=node)
raw_desc = raw_wallet.get_descriptor()
diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py
index f5d42d0c34..a2f9210f94 100755
--- a/test/functional/rpc_packages.py
+++ b/test/functional/rpc_packages.py
@@ -110,17 +110,21 @@ class RPCPackagesTest(BitcoinTestFramework):
self.assert_testres_equal(package_bad, testres_bad)
self.log.info("Check testmempoolaccept tells us when some transactions completed validation successfully")
- tx_bad_sig_hex = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}],
+ tx_bad_sig_hex = node.createrawtransaction([{"txid": coin["txid"], "vout": coin["vout"]}],
{address : coin["amount"] - Decimal("0.0001")})
tx_bad_sig = tx_from_hex(tx_bad_sig_hex)
testres_bad_sig = node.testmempoolaccept(self.independent_txns_hex + [tx_bad_sig_hex])
# By the time the signature for the last transaction is checked, all the other transactions
# have been fully validated, which is why the node returns full validation results for all
# transactions here but empty results in other cases.
+ tx_bad_sig_txid = tx_bad_sig.rehash()
+ tx_bad_sig_wtxid = tx_bad_sig.getwtxid()
assert_equal(testres_bad_sig, self.independent_txns_testres + [{
- "txid": tx_bad_sig.rehash(),
- "wtxid": tx_bad_sig.getwtxid(), "allowed": False,
- "reject-reason": "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)"
+ "txid": tx_bad_sig_txid,
+ "wtxid": tx_bad_sig_wtxid, "allowed": False,
+ "reject-reason": "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)",
+ "reject-details": "mandatory-script-verify-flag-failed (Operation not valid with the current stack size), " +
+ f"input 0 of {tx_bad_sig_txid} (wtxid {tx_bad_sig_wtxid}), spending {coin['txid']}:{coin['vout']}"
}])
self.log.info("Check testmempoolaccept reports txns in packages that exceed max feerate")
@@ -304,7 +308,8 @@ class RPCPackagesTest(BitcoinTestFramework):
assert testres_rbf_single[0]["allowed"]
testres_rbf_package = self.independent_txns_testres_blank + [{
"txid": replacement_tx["txid"], "wtxid": replacement_tx["wtxid"], "allowed": False,
- "reject-reason": "bip125-replacement-disallowed"
+ "reject-reason": "bip125-replacement-disallowed",
+ "reject-details": "bip125-replacement-disallowed"
}]
self.assert_testres_equal(self.independent_txns_hex + [replacement_tx["hex"]], testres_rbf_package)
diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index a357ae4d34..37fd5ae568 100644
--- a/test/functional/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -188,7 +188,12 @@ class AuthServiceProxy():
{'code': -342, 'message': 'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)},
http_response.status)
- responsedata = http_response.read().decode('utf8')
+ data = http_response.read()
+ try:
+ responsedata = data.decode('utf8')
+ except UnicodeDecodeError as e:
+ raise JSONRPCException({
+ 'code': -342, 'message': f'Cannot decode response in utf8 format, content: {data}, exception: {e}'})
response = json.loads(responsedata, parse_float=decimal.Decimal)
elapsed = time.time() - req_start_time
if "error" in response and response["error"] is None:
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index ff94e86468..d896a421d4 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -221,10 +221,9 @@ class TestNode():
extra_args = self.extra_args
# If listening and no -bind is given, then bitcoind would bind P2P ports on
- # 0.0.0.0:P and 127.0.0.1:18445 (for incoming Tor connections), where P is
+ # 0.0.0.0:P and 127.0.0.1:P+1 (for incoming Tor connections), where P is
# a unique port chosen by the test framework and configured as port=P in
- # bitcoin.conf. To avoid collisions on 127.0.0.1:18445, change it to
- # 127.0.0.1:tor_port().
+ # bitcoin.conf. To avoid collisions, change it to 127.0.0.1:tor_port().
will_listen = all(e != "-nolisten" and e != "-listen=0" for e in extra_args)
has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in extra_args)
if will_listen and not has_explicit_bind:
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index ab2a5d38d6..14930ef671 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -453,6 +453,17 @@ def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect=
f.write("unsafesqlitesync=1\n")
if disable_autoconnect:
f.write("connect=0\n")
+ # Limit max connections to mitigate test failures on some systems caused by the warning:
+ # "Warning: Reducing -maxconnections from <...> to <...> due to system limitations".
+ # The value is calculated as follows:
+ # available_fds = 256 // Same as FD_SETSIZE on NetBSD.
+ # MIN_CORE_FDS = 151 // Number of file descriptors required for core functionality.
+ # MAX_ADDNODE_CONNECTIONS = 8 // Maximum number of -addnode outgoing nodes.
+ # nBind == 3 // Maximum number of bound interfaces used in a test.
+ #
+ # min_required_fds = MIN_CORE_FDS + MAX_ADDNODE_CONNECTIONS + nBind = 151 + 8 + 3 = 162;
+ # nMaxConnections = available_fds - min_required_fds = 256 - 161 = 94;
+ f.write("maxconnections=94\n")
f.write(extra_config)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 5a542e58a4..85170b1045 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -341,6 +341,7 @@ BASE_SCRIPTS = [
'feature_minchainwork.py',
'rpc_estimatefee.py',
'rpc_getblockstats.py',
+ 'feature_port.py',
'feature_bind_port_externalip.py',
'wallet_create_tx.py --legacy-wallet',
'wallet_send.py --legacy-wallet',
diff --git a/test/functional/wallet_assumeutxo.py b/test/functional/wallet_assumeutxo.py
index 76cd2097a3..ac904d6ce4 100755
--- a/test/functional/wallet_assumeutxo.py
+++ b/test/functional/wallet_assumeutxo.py
@@ -17,6 +17,7 @@ from test_framework.messages import COIN
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
+ ensure_for,
)
from test_framework.wallet import MiniWallet
@@ -34,17 +35,18 @@ class AssumeutxoTest(BitcoinTestFramework):
def set_test_params(self):
"""Use the pregenerated, deterministic chain up to height 199."""
- self.num_nodes = 2
+ self.num_nodes = 3
self.rpc_timeout = 120
self.extra_args = [
[],
[],
+ [],
]
def setup_network(self):
"""Start with the nodes disconnected so that one can generate a snapshot
including blocks the other hasn't yet seen."""
- self.add_nodes(2)
+ self.add_nodes(3)
self.start_nodes(extra_args=self.extra_args)
def run_test(self):
@@ -57,6 +59,7 @@ class AssumeutxoTest(BitcoinTestFramework):
"""
n0 = self.nodes[0]
n1 = self.nodes[1]
+ n2 = self.nodes[2]
self.mini_wallet = MiniWallet(n0)
@@ -88,6 +91,7 @@ class AssumeutxoTest(BitcoinTestFramework):
# make n1 aware of the new header, but don't give it the block.
n1.submitheader(newblock)
+ n2.submitheader(newblock)
# Ensure everyone is seeing the same headers.
for n in self.nodes:
@@ -125,6 +129,7 @@ class AssumeutxoTest(BitcoinTestFramework):
assert_equal(n0.getblockcount(), FINAL_HEIGHT)
assert_equal(n1.getblockcount(), START_HEIGHT)
+ assert_equal(n2.getblockcount(), START_HEIGHT)
assert_equal(n0.getblockchaininfo()["blocks"], FINAL_HEIGHT)
@@ -192,6 +197,13 @@ class AssumeutxoTest(BitcoinTestFramework):
w = n1.get_wallet_rpc("w")
assert_equal(w.getbalance(), 34)
+ self.log.info("Check balance of a wallet that is active during snapshot completion")
+ n2.restorewallet("w", "backup_w.dat")
+ loaded = n2.loadtxoutset(dump_output['path'])
+ self.connect_nodes(0, 2)
+ self.wait_until(lambda: len(n2.getchainstates()['chainstates']) == 1)
+ ensure_for(duration=1, f=lambda: (n2.getbalance() == 34))
+
if __name__ == '__main__':
AssumeutxoTest(__file__).main()
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
index 62b4756a8f..3a56050731 100755
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020-2022 The Bitcoin Core developers
+# Copyright (c) 2020-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test Migrating a wallet from legacy to descriptor."""
@@ -463,7 +463,7 @@ class WalletMigrationTest(BitcoinTestFramework):
addr_info = wallet.getaddressinfo(addr)
desc = descsum_create("pk(" + addr_info["pubkey"] + ")")
- self.master_node.generatetodescriptor(1, desc, invalid_call=False)
+ self.generatetodescriptor(self.master_node, 1, desc)
bals = wallet.getbalances()
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 9917eca75a..e87977edfc 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -371,10 +371,6 @@ def run_once(*, fuzz_pool, corpus, test_list, src_dir, fuzz_bin, using_libfuzzer
for future in as_completed(jobs):
output, result, target = future.result()
logging.debug(output)
- if using_libfuzzer:
- done_stat = [l for l in output.splitlines() if "DONE" in l]
- assert len(done_stat) == 1
- stats.append((target, done_stat[0]))
try:
result.check_returncode()
except subprocess.CalledProcessError as e:
@@ -382,8 +378,12 @@ def run_once(*, fuzz_pool, corpus, test_list, src_dir, fuzz_bin, using_libfuzzer
logging.info(e.stdout)
if e.stderr:
logging.info(e.stderr)
- logging.info(f"Target {result.args} failed with exit code {e.returncode}")
+ logging.info(f"⚠️ Failure generated from target with exit code {e.returncode}: {result.args}")
sys.exit(1)
+ if using_libfuzzer:
+ done_stat = [l for l in output.splitlines() if "DONE" in l]
+ assert len(done_stat) == 1
+ stats.append((target, done_stat[0]))
if using_libfuzzer:
print("Summary:")
diff --git a/test/lint/lint-assertions.py b/test/lint/lint-assertions.py
deleted file mode 100755
index 5d01b13fd4..0000000000
--- a/test/lint/lint-assertions.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (c) 2018-2022 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check for assertions with obvious side effects.
-
-import sys
-import subprocess
-
-
-def git_grep(params: [], error_msg: ""):
- try:
- output = subprocess.check_output(["git", "grep", *params], text=True, encoding="utf8")
- print(error_msg)
- print(output)
- return 1
- except subprocess.CalledProcessError as ex1:
- if ex1.returncode > 1:
- raise ex1
- return 0
-
-
-def main():
- # Aborting the whole process is undesirable for RPC code. So nonfatal
- # checks should be used over assert. See: src/util/check.h
- # src/rpc/server.cpp is excluded from this check since it's mostly meta-code.
- exit_code = git_grep([
- "--line-number",
- "--extended-regexp",
- r"\<(A|a)ss(ume|ert)\(",
- "--",
- "src/rpc/",
- "src/wallet/rpc*",
- ":(exclude)src/rpc/server.cpp",
- ], "CHECK_NONFATAL(condition) or NONFATAL_UNREACHABLE should be used instead of assert for RPC code.")
-
- # The `BOOST_ASSERT` macro requires to `#include boost/assert.hpp`,
- # which is an unnecessary Boost dependency.
- exit_code |= git_grep([
- "--line-number",
- "--extended-regexp",
- r"BOOST_ASSERT\(",
- "--",
- "*.cpp",
- "*.h",
- ], "BOOST_ASSERT must be replaced with Assert, BOOST_REQUIRE, or BOOST_CHECK.")
-
- sys.exit(exit_code)
-
-
-if __name__ == "__main__":
- main()
diff --git a/test/lint/test_runner/src/main.rs b/test/lint/test_runner/src/main.rs
index f4fb1c36e5..8479fd2d64 100644
--- a/test/lint/test_runner/src/main.rs
+++ b/test/lint/test_runner/src/main.rs
@@ -49,6 +49,16 @@ fn get_linter_list() -> Vec<&'static Linter> {
lint_fn: lint_std_filesystem
},
&Linter {
+ description: "Check that fatal assertions are not used in RPC code",
+ name: "rpc_assert",
+ lint_fn: lint_rpc_assert
+ },
+ &Linter {
+ description: "Check that boost assertions are not used",
+ name: "boost_assert",
+ lint_fn: lint_boost_assert
+ },
+ &Linter {
description: "Check that release note snippets are in the right folder",
name: "doc_release_note_snippets",
lint_fn: lint_doc_release_note_snippets
@@ -237,7 +247,7 @@ fn lint_py_lint() -> LintResult {
"F822", // undefined name name in __all__
"F823", // local variable name … referenced before assignment
"F841", // local variable 'foo' is assigned to but never used
- "PLE", // Pylint errors
+ "PLE", // Pylint errors
"W191", // indentation contains tabs
"W291", // trailing whitespace
"W292", // no newline at end of file
@@ -273,6 +283,7 @@ fn lint_std_filesystem() -> LintResult {
let found = git()
.args([
"grep",
+ "--line-number",
"std::filesystem",
"--",
"./src/",
@@ -283,10 +294,66 @@ fn lint_std_filesystem() -> LintResult {
.success();
if found {
Err(r#"
-^^^
Direct use of std::filesystem may be dangerous and buggy. Please include <util/fs.h> and use the
fs:: namespace, which has unsafe filesystem functions marked as deleted.
"#
+ .trim()
+ .to_string())
+ } else {
+ Ok(())
+ }
+}
+
+fn lint_rpc_assert() -> LintResult {
+ let found = git()
+ .args([
+ "grep",
+ "--line-number",
+ "--extended-regexp",
+ r"\<(A|a)ss(ume|ert)\(",
+ "--",
+ "src/rpc/",
+ "src/wallet/rpc*",
+ ":(exclude)src/rpc/server.cpp",
+ // src/rpc/server.cpp is excluded from this check since it's mostly meta-code.
+ ])
+ .status()
+ .expect("command error")
+ .success();
+ if found {
+ Err(r#"
+CHECK_NONFATAL(condition) or NONFATAL_UNREACHABLE should be used instead of assert for RPC code.
+
+Aborting the whole process is undesirable for RPC code. So nonfatal
+checks should be used over assert. See: src/util/check.h
+ "#
+ .trim()
+ .to_string())
+ } else {
+ Ok(())
+ }
+}
+
+fn lint_boost_assert() -> LintResult {
+ let found = git()
+ .args([
+ "grep",
+ "--line-number",
+ "--extended-regexp",
+ r"BOOST_ASSERT\(",
+ "--",
+ "*.cpp",
+ "*.h",
+ ])
+ .status()
+ .expect("command error")
+ .success();
+ if found {
+ Err(r#"
+BOOST_ASSERT must be replaced with Assert, BOOST_REQUIRE, or BOOST_CHECK to avoid an unnecessary
+include of the boost/assert.hpp dependency.
+ "#
+ .trim()
.to_string())
} else {
Ok(())
@@ -303,17 +370,15 @@ fn lint_doc_release_note_snippets() -> LintResult {
if non_release_notes.is_empty() {
Ok(())
} else {
- Err(format!(
- r#"
-{}
-^^^
+ println!("{non_release_notes}");
+ Err(r#"
Release note snippets and other docs must be put into the doc/ folder directly.
The doc/release-notes/ folder is for archived release notes of previous releases only. Snippets are
expected to follow the naming "/doc/release-notes-<PR number>.md".
- "#,
- non_release_notes
- ))
+ "#
+ .trim()
+ .to_string())
}
}
@@ -356,7 +421,6 @@ fn lint_trailing_whitespace() -> LintResult {
.success();
if trailing_space {
Err(r#"
-^^^
Trailing whitespace (including Windows line endings [CR LF]) is problematic, because git may warn
about it, or editors may remove it by default, forcing developers in the future to either undo the
changes manually or spend time on review.
@@ -366,6 +430,7 @@ Thus, it is best to remove the trailing space now.
Please add any false positives, such as subtrees, Windows-related files, patch files, or externally
sourced files to the exclude list.
"#
+ .trim()
.to_string())
} else {
Ok(())
@@ -382,7 +447,6 @@ fn lint_tabs_whitespace() -> LintResult {
.success();
if tabs {
Err(r#"
-^^^
Use of tabs in this codebase is problematic, because existing code uses spaces and tabs will cause
display issues and conflict with editor settings.
@@ -390,6 +454,7 @@ Please remove the tabs.
Please add any false positives, such as subtrees, or externally sourced files to the exclude list.
"#
+ .trim()
.to_string())
} else {
Ok(())
@@ -464,7 +529,6 @@ fn lint_includes_build_config() -> LintResult {
if missing {
return Err(format!(
r#"
-^^^
One or more files use a symbol declared in the bitcoin-build-config.h header. However, they are not
including the header. This is problematic, because the header may or may not be indirectly
included. If the indirect include were to be intentionally or accidentally removed, the build could
@@ -480,12 +544,13 @@ include again.
#include <bitcoin-build-config.h> // IWYU pragma: keep
"#,
defines_regex
- ));
+ )
+ .trim()
+ .to_string());
}
let redundant = print_affected_files(false);
if redundant {
return Err(r#"
-^^^
None of the files use a symbol declared in the bitcoin-build-config.h header. However, they are including
the header. Consider removing the unused include.
"#
@@ -538,7 +603,9 @@ Markdown link errors found:
{}
"#,
stderr
- ))
+ )
+ .trim()
+ .to_string())
}
Err(e) if e.kind() == ErrorKind::NotFound => {
println!("`mlc` was not found in $PATH, skipping markdown lint check.");
@@ -590,10 +657,9 @@ fn main() -> ExitCode {
env::set_current_dir(&git_root).unwrap();
if let Err(err) = (linter.lint_fn)() {
println!(
- "{err}\n^---- ⚠️ Failure generated from lint check '{}'!",
- linter.name
+ "^^^\n{err}\n^---- ⚠️ Failure generated from lint check '{}' ({})!\n\n",
+ linter.name, linter.description,
);
- println!("{}", linter.description);
test_failed = true;
}
}