diff options
74 files changed, 985 insertions, 428 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 6cecb9b59a..460906817e 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -51,10 +51,6 @@ global_task_template: &GLOBAL_TASK_TEMPLATE << : *BASE_TEMPLATE << : *MAIN_TEMPLATE -depends_sdk_cache_template: &DEPENDS_SDK_CACHE_TEMPLATE - depends_sdk_cache: - folder: "depends/sdk-sources" - compute_credits_template: &CREDITS_TEMPLATE # https://cirrus-ci.org/pricing/#compute-credits # Only use credits for pull requests to the main repo @@ -273,11 +269,15 @@ task: task: name: 'macOS 10.15 [gui, no tests] [focal]' - << : *DEPENDS_SDK_CACHE_TEMPLATE - << : *GLOBAL_TASK_TEMPLATE + << : *BASE_TEMPLATE + macos_sdk_cache: + folder: "depends/SDKs/$MACOS_SDK" + fingerprint_key: "$MACOS_SDK" + << : *MAIN_TEMPLATE container: image: ubuntu:focal env: + MACOS_SDK: "Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers" << : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV FILE_ENV: "./ci/test/00_setup_env_mac.sh" @@ -297,8 +297,10 @@ task: task: name: 'ARM64 Android APK [focal]' - << : *DEPENDS_SDK_CACHE_TEMPLATE << : *BASE_TEMPLATE + android_sdk_cache: + folder: "depends/SDKs/android" + fingerprint_key: "ANDROID_API_LEVEL=28 ANDROID_BUILD_TOOLS_VERSION=28.0.3 ANDROID_NDK_VERSION=22.1.7171670" depends_sources_cache: folder: "depends/sources" fingerprint_script: git rev-list -1 HEAD ./depends diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh index 251ac76cad..cf203b4940 100755 --- a/ci/lint/04_install.sh +++ b/ci/lint/04_install.sh @@ -17,6 +17,6 @@ ${CI_RETRY_EXE} pip3 install mypy==0.910 ${CI_RETRY_EXE} pip3 install pyzmq==22.3.0 ${CI_RETRY_EXE} pip3 install vulture==2.3 -SHELLCHECK_VERSION=v0.7.2 +SHELLCHECK_VERSION=v0.8.0 curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/ export PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}" diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh index 702b84d152..d8c23bd26b 100755 --- a/ci/test/05_before_script.sh +++ b/ci/test/05_before_script.sh @@ -15,17 +15,22 @@ fi DOCKER_EXEC mkdir -p "${DEPENDS_DIR}/SDKs" "${DEPENDS_DIR}/sdk-sources" -OSX_SDK_BASENAME="Xcode-${XCODE_VERSION}-${XCODE_BUILD_ID}-extracted-SDK-with-libcxx-headers.tar.gz" -OSX_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${OSX_SDK_BASENAME}" +OSX_SDK_BASENAME="Xcode-${XCODE_VERSION}-${XCODE_BUILD_ID}-extracted-SDK-with-libcxx-headers" -if [ -n "$XCODE_VERSION" ] && [ ! -f "$OSX_SDK_PATH" ]; then - DOCKER_EXEC curl --location --fail "${SDK_URL}/${OSX_SDK_BASENAME}" -o "$OSX_SDK_PATH" +if [ -n "$XCODE_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${OSX_SDK_BASENAME}" ]; then + OSX_SDK_FILENAME="${OSX_SDK_BASENAME}.tar.gz" + OSX_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${OSX_SDK_FILENAME}" + if [ ! -f "$OSX_SDK_PATH" ]; then + DOCKER_EXEC curl --location --fail "${SDK_URL}/${OSX_SDK_FILENAME}" -o "$OSX_SDK_PATH" + fi + DOCKER_EXEC tar -C "${DEPENDS_DIR}/SDKs" -xf "$OSX_SDK_PATH" fi -if [ -n "$ANDROID_TOOLS_URL" ]; then - ANDROID_TOOLS_PATH=$DEPENDS_DIR/sdk-sources/android-tools.zip - - DOCKER_EXEC curl --location --fail "${ANDROID_TOOLS_URL}" -o "$ANDROID_TOOLS_PATH" +if [ -n "$ANDROID_HOME" ] && [ ! -d "$ANDROID_HOME" ]; then + ANDROID_TOOLS_PATH=${DEPENDS_DIR}/sdk-sources/android-tools.zip + if [ ! -f "$ANDROID_TOOLS_PATH" ]; then + DOCKER_EXEC curl --location --fail "${ANDROID_TOOLS_URL}" -o "$ANDROID_TOOLS_PATH" + fi DOCKER_EXEC mkdir -p "${ANDROID_HOME}/cmdline-tools" DOCKER_EXEC unzip -o "$ANDROID_TOOLS_PATH" -d "${ANDROID_HOME}/cmdline-tools" DOCKER_EXEC "yes | ${ANDROID_HOME}/cmdline-tools/tools/bin/sdkmanager --install \"build-tools;${ANDROID_BUILD_TOOLS_VERSION}\" \"platform-tools\" \"platforms;android-${ANDROID_API_LEVEL}\" \"ndk;${ANDROID_NDK_VERSION}\"" @@ -38,9 +43,6 @@ if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then DOCKER_EXEC "contrib/install_db4.sh \$(pwd) --enable-umrw CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'" fi -if [ -n "$XCODE_VERSION" ] && [ -f "$OSX_SDK_PATH" ]; then - DOCKER_EXEC tar -C "${DEPENDS_DIR}/SDKs" -xf "$OSX_SDK_PATH" -fi if [[ $HOST = *-mingw32 ]]; then DOCKER_EXEC update-alternatives --set "${HOST}-g++" \$\(which "${HOST}-g++-posix"\) fi diff --git a/contrib/guix/guix-clean b/contrib/guix/guix-clean index 9fa17191e8..9af0a793cf 100755 --- a/contrib/guix/guix-clean +++ b/contrib/guix/guix-clean @@ -34,7 +34,7 @@ check_tools cat mkdir make git guix # under_dir() { local path_residue - path_residue="${2##${1}}" + path_residue="${2##"${1}"}" if [ -z "$path_residue" ] || [ "$path_residue" = "$2" ]; then return 1 else diff --git a/contrib/guix/libexec/prelude.bash b/contrib/guix/libexec/prelude.bash index 40ae4b5208..1f287e9bbb 100644 --- a/contrib/guix/libexec/prelude.bash +++ b/contrib/guix/libexec/prelude.bash @@ -2,10 +2,10 @@ export LC_ALL=C set -e -o pipefail -# shellcheck source=../../shell/realpath.bash +# shellcheck source=contrib/shell/realpath.bash source contrib/shell/realpath.bash -# shellcheck source=../../shell/git-utils.bash +# shellcheck source=contrib/shell/git-utils.bash source contrib/shell/git-utils.bash ################ diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md index 1f93474fa0..b71ce2f34b 100644 --- a/contrib/tracing/README.md +++ b/contrib/tracing/README.md @@ -234,3 +234,62 @@ Histogram of block connection times in milliseconds (ms). [16, 32) 9 | | [32, 64) 4 | | ``` + +### log_utxocache_flush.py + +A BCC Python script to log the cache and index flushes. Based on the +`utxocache:flush` tracepoint. + +```bash +$ python3 contrib/tracing/log_utxocache_flush.py ./src/bitcoind +``` + +``` +Logging utxocache flushes. Ctrl-C to end... +Duration (µs) Mode Coins Count Memory Usage Prune Full Flush +0 PERIODIC 28484 3929.87 kB False False +1 PERIODIC 28485 3930.00 kB False False +0 PERIODIC 28489 3930.51 kB False False +1 PERIODIC 28490 3930.64 kB False False +0 PERIODIC 28491 3930.77 kB False False +0 PERIODIC 28491 3930.77 kB False False +0 PERIODIC 28496 3931.41 kB False False +1 PERIODIC 28496 3931.41 kB False False +0 PERIODIC 28497 3931.54 kB False False +1 PERIODIC 28497 3931.54 kB False False +1 PERIODIC 28499 3931.79 kB False False +. +. +. +53788 ALWAYS 30076 4136.27 kB False False +7463 ALWAYS 0 245.84 kB False False +``` + +### log_utxos.bt + +A `bpftrace` script to log information about the coins that are added, spent, or +uncached from the UTXO set. Based on the `utxocache:add`, `utxocache:spend` and +`utxocache:uncache` tracepoints. + +```bash +$ bpftrace contrib/tracing/log_utxos.bt +``` + +It should produce an output similar to the following. + +```bash +Attaching 4 probes... +OP Outpoint Value Height Coinbase +Added 6ba9ad857e1ef2eb2a2c94f06813c414c7ab273e3d6bd7ad64e000315a887e7c:1 10000 2094512 No +Spent fa7dc4db56637a151f6649d8f26732956d1c5424c82aae400a83d02b2cc2c87b:0 182264897 2094512 No +Added eeb2f099b1af6a2a12e6ddd2eeb16fc5968582241d7f08ba202d28b60ac264c7:0 10000 2094512 No +Added eeb2f099b1af6a2a12e6ddd2eeb16fc5968582241d7f08ba202d28b60ac264c7:1 182254756 2094512 No +Added a0c7f4ec9cccef2d89672a624a4e6c8237a17572efdd4679eea9e9ee70d2db04:0 10072679 2094513 Yes +Spent 25e0df5cc1aeb1b78e6056bf403e5e8b7e41f138060ca0a50a50134df0549a5e:2 540 2094508 No +Spent 42f383c04e09c26a2378272ec33aa0c1bf4883ca5ab739e8b7e06be5a5787d61:1 3848399 2007724 No +Added f85e3b4b89270863a389395cc9a4123e417ab19384cef96533c6649abd6b0561:0 3788399 2094513 No +Added f85e3b4b89270863a389395cc9a4123e417ab19384cef96533c6649abd6b0561:2 540 2094513 No +Spent a05880b8c77971ed0b9f73062c7c4cdb0ff3856ab14cbf8bc481ed571cd34b83:1 5591281046 2094511 No +Added eb689865f7d957938978d6207918748f74e6aa074f47874724327089445b0960:0 5589696005 2094513 No +Added eb689865f7d957938978d6207918748f74e6aa074f47874724327089445b0960:1 1565556 2094513 No +``` diff --git a/contrib/tracing/log_utxocache_flush.py b/contrib/tracing/log_utxocache_flush.py new file mode 100755 index 0000000000..df27dc193a --- /dev/null +++ b/contrib/tracing/log_utxocache_flush.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 + +import sys +import ctypes +from bcc import BPF, USDT + +"""Example logging Bitcoin Core utxo set cache flushes utilizing + the utxocache:flush tracepoint.""" + +# USAGE: ./contrib/tracing/log_utxocache_flush.py path/to/bitcoind + +# BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into +# a sandboxed Linux kernel VM. +program = """ +# include <uapi/linux/ptrace.h> +struct data_t +{ + u64 duration; + u32 mode; + u64 coins_count; + u64 coins_mem_usage; + bool is_flush_prune; + bool is_full_flush; +}; + +// BPF perf buffer to push the data to user space. +BPF_PERF_OUTPUT(flush); + +int trace_flush(struct pt_regs *ctx) { + struct data_t data = {}; + bpf_usdt_readarg(1, ctx, &data.duration); + bpf_usdt_readarg(2, ctx, &data.mode); + bpf_usdt_readarg(3, ctx, &data.coins_count); + bpf_usdt_readarg(4, ctx, &data.coins_mem_usage); + bpf_usdt_readarg(5, ctx, &data.is_flush_prune); + bpf_usdt_readarg(5, ctx, &data.is_full_flush); + flush.perf_submit(ctx, &data, sizeof(data)); + return 0; +} +""" + +FLUSH_MODES = [ + 'NONE', + 'IF_NEEDED', + 'PERIODIC', + 'ALWAYS' +] + + +class Data(ctypes.Structure): + # define output data structure corresponding to struct data_t + _fields_ = [ + ("duration", ctypes.c_uint64), + ("mode", ctypes.c_uint32), + ("coins_count", ctypes.c_uint64), + ("coins_mem_usage", ctypes.c_uint64), + ("is_flush_prune", ctypes.c_bool), + ("is_full_flush", ctypes.c_bool) + ] + + +def print_event(event): + print("%-15d %-10s %-15d %-15s %-8s %-8s" % ( + event.duration, + FLUSH_MODES[event.mode], + event.coins_count, + "%.2f kB" % (event.coins_mem_usage/1000), + event.is_flush_prune, + event.is_full_flush + )) + + +def main(bitcoind_path): + bitcoind_with_usdts = USDT(path=str(bitcoind_path)) + + # attaching the trace functions defined in the BPF program + # to the tracepoints + bitcoind_with_usdts.enable_probe( + probe="flush", fn_name="trace_flush") + b = BPF(text=program, usdt_contexts=[bitcoind_with_usdts]) + + def handle_flush(_, data, size): + """ Coins Flush handler. + Called each time coin caches and indexes are flushed.""" + event = ctypes.cast(data, ctypes.POINTER(Data)).contents + print_event(event) + + b["flush"].open_perf_buffer(handle_flush) + print("Logging utxocache flushes. Ctrl-C to end...") + print("%-15s %-10s %-15s %-15s %-8s %-8s" % ("Duration (µs)", "Mode", + "Coins Count", "Memory Usage", + "Prune", "Full Flush")) + + while True: + try: + b.perf_buffer_poll() + except KeyboardInterrupt: + exit(0) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("USAGE: ", sys.argv[0], "path/to/bitcoind") + exit(1) + + path = sys.argv[1] + main(path) diff --git a/contrib/tracing/log_utxos.bt b/contrib/tracing/log_utxos.bt new file mode 100755 index 0000000000..0d47f3d62b --- /dev/null +++ b/contrib/tracing/log_utxos.bt @@ -0,0 +1,86 @@ +#!/usr/bin/env bpftrace + +/* + + USAGE: + + bpftrace contrib/tracing/log_utxos.bt + + This script requires a 'bitcoind' binary compiled with eBPF support and the + 'utxochache' tracepoints. By default, it's assumed that 'bitcoind' is + located in './src/bitcoind'. This can be modified in the script below. + + NOTE: requires bpftrace v0.12.0 or above. +*/ + +BEGIN +{ + printf("%-7s %-71s %16s %7s %8s\n", + "OP", "Outpoint", "Value", "Height", "Coinbase"); +} + +/* + Attaches to the 'utxocache:add' tracepoint and prints additions to the UTXO set cache. +*/ +usdt:./src/bitcoind:utxocache:add +{ + $txid = arg0; + $index = (uint32)arg1; + $height = (uint32)arg2; + $value = (int64)arg3; + $isCoinbase = arg4; + + printf("Added "); + $p = $txid + 31; + unroll(32) { + $b = *(uint8*)$p; + printf("%02x", $b); + $p-=1; + } + + printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" )); +} + +/* + Attaches to the 'utxocache:spent' tracepoint and prints spents from the UTXO set cache. +*/ +usdt:./src/bitcoind:utxocache:spent +{ + $txid = arg0; + $index = (uint32)arg1; + $height = (uint32)arg2; + $value = (int64)arg3; + $isCoinbase = arg4; + + printf("Spent "); + $p = $txid + 31; + unroll(32) { + $b = *(uint8*)$p; + printf("%02x", $b); + $p-=1; + } + + printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" )); +} + +/* + Attaches to the 'utxocache:uncache' tracepoint and uncache UTXOs from the UTXO set cache. +*/ +usdt:./src/bitcoind:utxocache:uncache +{ + $txid = arg0; + $index = (uint32)arg1; + $height = (uint32)arg2; + $value = (int64)arg3; + $isCoinbase = arg4; + + printf("Uncache "); + $p = $txid + 31; + unroll(32) { + $b = *(uint8*)$p; + printf("%02x", $b); + $p-=1; + } + + printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" )); +} diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 4ee7a64a53..ea110b1653 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -10,7 +10,7 @@ $(package)_linguist_tools = lrelease lupdate lconvert $(package)_patches = qt.pro qttools_src.pro $(package)_patches += fix_qt_pkgconfig.patch mac-qmake.conf fix_no_printer.patch no-xlib.patch $(package)_patches += support_new_android_ndks.patch fix_android_jni_static.patch dont_hardcode_pwd.patch -$(package)_patches += dont_hardcode_x86_64.patch no_sdk_version_check.patch +$(package)_patches += dont_hardcode_x86_64.patch $(package)_patches+= fix_lib_paths.patch fix_android_pch.patch $(package)_patches+= qtbase-moc-ignore-gcc-macro.patch fix_limits_header.patch $(package)_patches+= fix_montery_include.patch @@ -232,7 +232,6 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/fix_android_pch.patch && \ patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \ patch -p1 -i $($(package)_patch_dir)/dont_hardcode_x86_64.patch && \ - patch -p1 -i $($(package)_patch_dir)/no_sdk_version_check.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_lib_paths.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_limits_header.patch && \ @@ -253,6 +252,7 @@ endef define $(package)_config_cmds export PKG_CONFIG_SYSROOT_DIR=/ && \ export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ + export QT_MAC_SDK_NO_VERSION_CHECK=1 && \ cd qtbase && \ ./configure -top-level $($(package)_config_opts) endef diff --git a/depends/patches/qt/no_sdk_version_check.patch b/depends/patches/qt/no_sdk_version_check.patch deleted file mode 100644 index b16635b572..0000000000 --- a/depends/patches/qt/no_sdk_version_check.patch +++ /dev/null @@ -1,20 +0,0 @@ -commit f5eb142cd04be2bc4ca610ed3b5b7e8ce3520ee3 -Author: fanquake <fanquake@gmail.com> -Date: Tue Jan 5 16:08:49 2021 +0800 - - Don't invoke macOS SDK version checking - - This tries to use xcrun which is not available when cross-compiling. - -diff --git a/qtbase/mkspecs/features/mac/default_post.prf b/qtbase/mkspecs/features/mac/default_post.prf -index 92a9112bca6..447e186eb26 100644 ---- a/qtbase/mkspecs/features/mac/default_post.prf -+++ b/qtbase/mkspecs/features/mac/default_post.prf -@@ -8,7 +8,6 @@ contains(TEMPLATE, .*app) { - !macx-xcode:if(isEmpty(BUILDS)|build_pass) { - # Detect changes to the platform SDK - QMAKE_EXTRA_VARIABLES += QMAKE_MAC_SDK QMAKE_MAC_SDK_VERSION QMAKE_XCODE_DEVELOPER_PATH -- QMAKE_EXTRA_INCLUDES += $$shell_quote($$PWD/sdk.mk) - } - - # Detect incompatible SDK versions diff --git a/doc/tracing.md b/doc/tracing.md index 57104c43a0..5b9ba09c2f 100644 --- a/doc/tracing.md +++ b/doc/tracing.md @@ -108,6 +108,55 @@ Arguments passed: 5. SigOps in the Block (excluding coinbase SigOps) `uint64` 6. Time it took to connect the Block in microseconds (µs) as `uint64` +### Context `utxocache` + +#### Tracepoint `utxocache:flush` + +Is called *after* the caches and indexes are flushed depending on the mode +`CChainState::FlushStateToDisk` is called with. + +Arguments passed: +1. Duration in microseconds as `int64` +2. Flush state mode as `uint32`. It's an enumerator class with values `0` + (`NONE`), `1` (`IF_NEEDED`), `2` (`PERIODIC`), `3` (`ALWAYS`) +3. Number of coins flushed as `uint64` +4. Memory usage in bytes as `uint64` +5. If the flush was pruned as `bool` +6. If it was full flush as `bool` + +#### Tracepoint `utxocache:add` + +It is called when a new coin is added to the UTXO cache. + +Arguments passed: +1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian) +2. Output index as `uint32` +3. Block height the coin was added to the UTXO-set as `uint32` +4. Value of the coin as `int64` +5. If the coin is a coinbase as `bool` + +#### Tracepoint `utxocache:spent` + +It is called when a coin is spent from the UTXO cache. + +Arguments passed: +1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian) +2. Output index as `uint32` +3. Block height the coin was spent, as `uint32` +4. Value of the coin as `int64` +5. If the coin is a coinbase as `bool` + +#### Tracepoint `utxocache:uncache` + +It is called when the UTXO with the given outpoint is removed from the cache. + +Arguments passed: +1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian) +2. Output index as `uint32` +3. Block height the coin was uncached, as `uint32` +4. Value of the coin as `int64` +. If the coin is a coinbase as `bool` + ## Adding tracepoints to Bitcoin Core To add a new tracepoint, `#include <util/trace.h>` in the compilation unit where diff --git a/src/Makefile.am b/src/Makefile.am index 9d79ee0e62..6846eb9693 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -409,6 +409,7 @@ libbitcoin_wallet_a_SOURCES = \ wallet/interfaces.cpp \ wallet/load.cpp \ wallet/receive.cpp \ + wallet/rpc/signmessage.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/scriptpubkeyman.cpp \ diff --git a/src/checkqueue.h b/src/checkqueue.h index 7c20e2013c..760dfbddc1 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -167,16 +167,24 @@ public: //! Add a batch of checks to the queue void Add(std::vector<T>& vChecks) { - LOCK(m_mutex); - for (T& check : vChecks) { - queue.push_back(T()); - check.swap(queue.back()); + if (vChecks.empty()) { + return; } - nTodo += vChecks.size(); - if (vChecks.size() == 1) + + { + LOCK(m_mutex); + for (T& check : vChecks) { + queue.emplace_back(); + check.swap(queue.back()); + } + nTodo += vChecks.size(); + } + + if (vChecks.size() == 1) { m_worker_cv.notify_one(); - else if (vChecks.size() > 1) + } else { m_worker_cv.notify_all(); + } } //! Stop all of the worker threads. diff --git a/src/coins.cpp b/src/coins.cpp index ce0b131de6..daead6055e 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -7,6 +7,7 @@ #include <consensus/consensus.h> #include <logging.h> #include <random.h> +#include <util/trace.h> #include <version.h> bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; } @@ -95,6 +96,12 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi it->second.coin = std::move(coin); it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0); cachedCoinsUsage += it->second.coin.DynamicMemoryUsage(); + TRACE5(utxocache, add, + outpoint.hash.data(), + (uint32_t)outpoint.n, + (uint32_t)coin.nHeight, + (int64_t)coin.out.nValue, + (bool)coin.IsCoinBase()); } void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin) { @@ -120,6 +127,12 @@ bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) { CCoinsMap::iterator it = FetchCoin(outpoint); if (it == cacheCoins.end()) return false; cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); + TRACE5(utxocache, spent, + outpoint.hash.data(), + (uint32_t)outpoint.n, + (uint32_t)it->second.coin.nHeight, + (int64_t)it->second.coin.out.nValue, + (bool)it->second.coin.IsCoinBase()); if (moveout) { *moveout = std::move(it->second.coin); } @@ -231,6 +244,12 @@ void CCoinsViewCache::Uncache(const COutPoint& hash) CCoinsMap::iterator it = cacheCoins.find(hash); if (it != cacheCoins.end() && it->second.flags == 0) { cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); + TRACE5(utxocache, uncache, + hash.hash.data(), + (uint32_t)hash.n, + (uint32_t)it->second.coin.nHeight, + (int64_t)it->second.coin.out.nValue, + (bool)it->second.coin.IsCoinBase()); cacheCoins.erase(it); } } diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 490563426c..a56ed8802d 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -13,12 +13,13 @@ #include <util/message.h> #include <util/ui_change_type.h> +#include <cstdint> #include <functional> #include <map> #include <memory> -#include <stdint.h> #include <string> #include <tuple> +#include <type_traits> #include <utility> #include <vector> @@ -34,7 +35,7 @@ struct CRecipient; struct PartiallySignedTransaction; struct WalletContext; struct bilingual_str; -typedef uint8_t isminefilter; +using isminefilter = std::underlying_type<isminetype>::type; namespace interfaces { diff --git a/src/net.cpp b/src/net.cpp index db496c2185..e17db7e54b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1640,7 +1640,7 @@ void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set) if (interruptNet) { return; } - if (listen_socket.socket != INVALID_SOCKET && recv_set.count(listen_socket.socket) > 0) { + if (recv_set.count(listen_socket.socket) > 0) { AcceptConnection(listen_socket); } } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a896bb76ae..3f755eb178 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3206,6 +3206,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, return; } + // Stop processing the transaction early if we are still in IBD since we don't + // have enough information to validate it yet. Sending unsolicited transactions + // is not considered a protocol violation, so don't punish the peer. + if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) return; + CTransactionRef ptx; vRecv >> ptx; const CTransaction& tx = *ptx; diff --git a/src/psbt.cpp b/src/psbt.cpp index b3d8e052bc..6585766807 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -247,7 +247,7 @@ PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction& return txdata; } -bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata) +bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize) { PSBTInput& input = psbt.inputs.at(index); const CMutableTransaction& tx = *psbt.tx; @@ -295,6 +295,10 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& } // Verify that a witness signature was produced in case one was required. if (require_witness_sig && !sigdata.witness) return false; + + // If we are not finalizing, set sigdata.complete to false to not set the scriptWitness + if (!finalize && sigdata.complete) sigdata.complete = false; + input.FromSignatureData(sigdata); // If we have a witness signature, put a witness UTXO. @@ -324,7 +328,7 @@ bool FinalizePSBT(PartiallySignedTransaction& psbtx) bool complete = true; const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx); for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { - complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL); + complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true); } return complete; diff --git a/src/psbt.h b/src/psbt.h index f6b82b43de..7808a247c0 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -578,7 +578,7 @@ bool PSBTInputSigned(const PSBTInput& input); * txdata should be the output of PrecomputePSBTData (which can be shared across * multiple SignPSBTInput calls). If it is nullptr, a dummy signature will be created. **/ -bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr); +bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true); /** Counts the unsigned inputs of a PSBT. */ size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 93e49cb9a8..90fbd823a4 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -115,6 +115,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "walletcreatefundedpsbt", 4, "bip32derivs" }, { "walletprocesspsbt", 1, "sign" }, { "walletprocesspsbt", 3, "bip32derivs" }, + { "walletprocesspsbt", 4, "finalize" }, { "createpsbt", 0, "inputs" }, { "createpsbt", 1, "outputs" }, { "createpsbt", 2, "locktime" }, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 2dd121c6f6..7f3917b638 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -69,6 +69,43 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& } } +static std::vector<RPCArg> CreateTxDoc() +{ + return { + {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The inputs", + { + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + { + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"}, + }, + }, + }, + }, + {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n" + "That is, each address can only appear once and there can only be one 'data' object.\n" + "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" + " accepted as second parameter.", + { + {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "", + { + {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT}, + }, + }, + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + { + {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, + }, + }, + }, + }, + {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, + {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125-replaceable.\n" + "Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, + }; +} + static RPCHelpMan getrawtransaction() { return RPCHelpMan{ @@ -375,39 +412,7 @@ static RPCHelpMan createrawtransaction() "Returns hex-encoded raw transaction.\n" "Note that the transaction's inputs are not signed, and\n" "it is not stored in the wallet or transmitted to the network.\n", - { - {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The inputs", - { - {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", - { - {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, - {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, - {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"}, - }, - }, - }, - }, - {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n" - "That is, each address can only appear once and there can only be one 'data' object.\n" - "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" - " accepted as second parameter.", - { - {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "", - { - {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT}, - }, - }, - {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", - { - {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, - }, - }, - }, - }, - {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, - {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125-replaceable.\n" - " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, - }, + CreateTxDoc(), RPCResult{ RPCResult::Type::STR_HEX, "transaction", "hex string of the transaction" }, @@ -1435,39 +1440,7 @@ static RPCHelpMan createpsbt() return RPCHelpMan{"createpsbt", "\nCreates a transaction in the Partially Signed Transaction format.\n" "Implements the Creator role.\n", - { - {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The json objects", - { - {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", - { - {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, - {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, - {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"}, - }, - }, - }, - }, - {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n" - "That is, each address can only appear once and there can only be one 'data' object.\n" - "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" - " accepted as second parameter.", - { - {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "", - { - {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT}, - }, - }, - {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", - { - {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"}, - }, - }, - }, - }, - {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, - {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125 replaceable.\n" - " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, - }, + CreateTxDoc(), RPCResult{ RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)" }, diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index f82864b421..31f30d0379 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -26,7 +26,7 @@ class AddrManTest : public AddrMan { public: explicit AddrManTest(std::vector<bool> asmap = std::vector<bool>()) - : AddrMan(asmap, /*deterministic=*/true, /* consistency_check_ratio */ 100) + : AddrMan(asmap, /*deterministic=*/true, /*consistency_check_ratio=*/100) {} AddrInfo* Find(const CService& addr) @@ -376,7 +376,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) // Test: Sanity check, GetAddr should never return anything if addrman // is empty. BOOST_CHECK_EQUAL(addrman.size(), 0U); - std::vector<CAddress> vAddr1 = addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt); + std::vector<CAddress> vAddr1 = addrman.GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt); BOOST_CHECK_EQUAL(vAddr1.size(), 0U); CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE); @@ -396,15 +396,15 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) BOOST_CHECK(addrman.Add({addr1, addr3, addr5}, source1)); BOOST_CHECK(addrman.Add({addr2, addr4}, source2)); - BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt).size(), 5U); + BOOST_CHECK_EQUAL(addrman.GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U); // Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down. - BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt).size(), 1U); + BOOST_CHECK_EQUAL(addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U); // Test: Ensure GetAddr works with new and tried addresses. addrman.Good(CAddress(addr1, NODE_NONE)); addrman.Good(CAddress(addr2, NODE_NONE)); - BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt).size(), 5U); - BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt).size(), 1U); + BOOST_CHECK_EQUAL(addrman.GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U); + BOOST_CHECK_EQUAL(addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U); // Test: Ensure GetAddr still returns 23% when addrman has many addrs. for (unsigned int i = 1; i < (8 * 256); i++) { @@ -419,7 +419,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) if (i % 8 == 0) addrman.Good(addr); } - std::vector<CAddress> vAddr = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt); + std::vector<CAddress> vAddr = addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt); size_t percent23 = (addrman.size() * 23) / 100; BOOST_CHECK_EQUAL(vAddr.size(), percent23); @@ -973,7 +973,7 @@ BOOST_AUTO_TEST_CASE(load_addrman) // Test that the de-serialization does not throw an exception. CDataStream ssPeers1 = AddrmanToStream(addrman); bool exceptionThrown = false; - AddrMan addrman1(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100); + AddrMan addrman1(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); BOOST_CHECK(addrman1.size() == 0); try { @@ -990,7 +990,7 @@ BOOST_AUTO_TEST_CASE(load_addrman) // Test that ReadFromStream creates an addrman with the correct number of addrs. CDataStream ssPeers2 = AddrmanToStream(addrman); - AddrMan addrman2(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100); + AddrMan addrman2(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); BOOST_CHECK(addrman2.size() == 0); ReadFromStream(addrman2, ssPeers2); BOOST_CHECK(addrman2.size() == 3); @@ -1028,7 +1028,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted) // Test that the de-serialization of corrupted peers.dat throws an exception. CDataStream ssPeers1 = MakeCorruptPeersDat(); bool exceptionThrown = false; - AddrMan addrman1(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100); + AddrMan addrman1(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); BOOST_CHECK(addrman1.size() == 0); try { unsigned char pchMsgTmp[4]; @@ -1044,7 +1044,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted) // Test that ReadFromStream fails if peers.dat is corrupt CDataStream ssPeers2 = MakeCorruptPeersDat(); - AddrMan addrman2(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100); + AddrMan addrman2(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); BOOST_CHECK(addrman2.size() == 0); BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure); } diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 06db3b846e..91218511bd 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -269,7 +269,7 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) CCoinsViewTest base; SimulationTest(&base, false); - CCoinsViewDB db_base{"test", /*nCacheSize*/ 1 << 23, /*fMemory*/ true, /*fWipe*/ false}; + CCoinsViewDB db_base{"test", /*nCacheSize=*/1 << 23, /*fMemory=*/true, /*fWipe=*/false}; SimulationTest(&db_base, true); } diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 1483bd3cb3..cbdedd1b85 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -574,10 +574,10 @@ BOOST_AUTO_TEST_CASE(hkdf_hmac_sha256_l32_tests) { // Use rfc5869 test vectors but truncated to 32 bytes (our implementation only support length 32) TestHKDF_SHA256_32( - /* IKM */ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - /* salt */ "000102030405060708090a0b0c", - /* info */ "f0f1f2f3f4f5f6f7f8f9", - /* expected OKM */ "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf"); + /*ikm_hex=*/"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + /*salt_hex=*/"000102030405060708090a0b0c", + /*info_hex=*/"f0f1f2f3f4f5f6f7f8f9", + /*okm_check_hex=*/"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf"); TestHKDF_SHA256_32( "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 765663e0ef..1662529594 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -213,13 +213,13 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) banman->ClearBanned(); nodes[0] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[0], /*nKeyedNetGroupIn=*/0, - /*nLocalHostNonceIn */ 0, CAddress(), /*addrNameIn=*/"", + /*nLocalHostNonceIn=*/0, CAddress(), /*addrNameIn=*/"", ConnectionType::INBOUND, /*inbound_onion=*/false}; nodes[0]->SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(nodes[0]); nodes[0]->fSuccessfullyConnected = true; connman->AddTestNode(*nodes[0]); - peerLogic->Misbehaving(nodes[0]->GetId(), DISCOURAGEMENT_THRESHOLD, /* message */ ""); // Should be discouraged + peerLogic->Misbehaving(nodes[0]->GetId(), DISCOURAGEMENT_THRESHOLD, /*message=*/""); // Should be discouraged { LOCK(nodes[0]->cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(nodes[0])); @@ -229,13 +229,13 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged nodes[1] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[1], /*nKeyedNetGroupIn=*/1, - /*nLocalHostNonceIn */ 1, CAddress(), /*addrNameIn=*/"", + /*nLocalHostNonceIn=*/1, CAddress(), /*addrNameIn=*/"", ConnectionType::INBOUND, /*inbound_onion=*/false}; nodes[1]->SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(nodes[1]); nodes[1]->fSuccessfullyConnected = true; connman->AddTestNode(*nodes[1]); - peerLogic->Misbehaving(nodes[1]->GetId(), DISCOURAGEMENT_THRESHOLD - 1, /* message */ ""); + peerLogic->Misbehaving(nodes[1]->GetId(), DISCOURAGEMENT_THRESHOLD - 1, /*message=*/""); { LOCK(nodes[1]->cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(nodes[1])); @@ -246,7 +246,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) // [1] is not discouraged/disconnected yet. BOOST_CHECK(!banman->IsDiscouraged(addr[1])); BOOST_CHECK(!nodes[1]->fDisconnect); - peerLogic->Misbehaving(nodes[1]->GetId(), 1, /* message */ ""); // [1] reaches discouragement threshold + peerLogic->Misbehaving(nodes[1]->GetId(), 1, /*message=*/""); // [1] reaches discouragement threshold { LOCK(nodes[1]->cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(nodes[1])); @@ -260,13 +260,13 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) // Make sure non-IP peers are discouraged and disconnected properly. nodes[2] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[2], /*nKeyedNetGroupIn=*/1, - /*nLocalHostNonceIn */ 1, CAddress(), /*addrNameIn=*/"", + /*nLocalHostNonceIn=*/1, CAddress(), /*addrNameIn=*/"", ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false}; nodes[2]->SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(nodes[2]); nodes[2]->fSuccessfullyConnected = true; connman->AddTestNode(*nodes[2]); - peerLogic->Misbehaving(nodes[2]->GetId(), DISCOURAGEMENT_THRESHOLD, /* message */ ""); + peerLogic->Misbehaving(nodes[2]->GetId(), DISCOURAGEMENT_THRESHOLD, /*message=*/""); { LOCK(nodes[2]->cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(nodes[2])); @@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) peerLogic->InitializeNode(&dummyNode); dummyNode.fSuccessfullyConnected = true; - peerLogic->Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD, /* message */ ""); + peerLogic->Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD, /*message=*/""); { LOCK(dummyNode.cs_sendProcessing); BOOST_CHECK(peerLogic->SendMessages(&dummyNode)); @@ -334,7 +334,7 @@ static void MakeNewKeyWithFastRandomContext(CKey& key) { std::vector<unsigned char> keydata; keydata = g_insecure_rand_ctx.randbytes(32); - key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn*/ true); + key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn=*/true); assert(key.IsValid()); } diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index d427d12a3c..9c85c20e2b 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -29,7 +29,7 @@ FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); - AddrMan addr_man(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); + AddrMan addr_man(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); try { ReadFromStream(addr_man, data_stream); } catch (const std::exception&) { @@ -113,7 +113,7 @@ class AddrManDeterministic : public AddrMan { public: explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider) - : AddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0) + : AddrMan(std::move(asmap), /*deterministic=*/true, /*consistency_check_ratio=*/0) { WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)}); } @@ -286,9 +286,9 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman) } const AddrMan& const_addr_man{addr_man}; (void)const_addr_man.GetAddr( - /* max_addresses */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), - /* max_pct */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), - /* network */ std::nullopt); + /*max_addresses=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), + /*max_pct=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), + /*network=*/std::nullopt); (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool()); (void)const_addr_man.size(); CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index fbba25c404..b2969ecdc0 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -58,7 +58,7 @@ FUZZ_TARGET_INIT(banman, initialize_banman) } { - BanMan ban_man{banlist_file, /* client_interface */ nullptr, /* default_ban_time */ ConsumeBanTimeOffset(fuzzed_data_provider)}; + BanMan ban_man{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/ConsumeBanTimeOffset(fuzzed_data_provider)}; // The complexity is O(N^2), where N is the input size, because each call // might call DumpBanlist (or other methods that are at least linear // complexity of the input size). @@ -105,7 +105,7 @@ FUZZ_TARGET_INIT(banman, initialize_banman) SetMockTime(ConsumeTime(fuzzed_data_provider)); banmap_t banmap; ban_man.GetBanned(banmap); - BanMan ban_man_read{banlist_file, /* client_interface */ nullptr, /* default_ban_time */ 0}; + BanMan ban_man_read{banlist_file, /*client_interface=*/nullptr, /*default_ban_time=*/0}; banmap_t banmap_read; ban_man_read.GetBanned(banmap_read); assert(banmap == banmap_read); diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index 9e4718e603..b8f4ad8d94 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -25,7 +25,7 @@ FUZZ_TARGET_INIT(connman, initialize_connman) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; SetMockTime(ConsumeTime(fuzzed_data_provider)); - AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); + AddrMan addrman(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()}; CNetAddr random_netaddr; CNode random_node = ConsumeNode(fuzzed_data_provider); @@ -69,15 +69,15 @@ FUZZ_TARGET_INIT(connman, initialize_connman) }, [&] { (void)connman.GetAddresses( - /* max_addresses */ fuzzed_data_provider.ConsumeIntegral<size_t>(), - /* max_pct */ fuzzed_data_provider.ConsumeIntegral<size_t>(), - /* network */ std::nullopt); + /*max_addresses=*/fuzzed_data_provider.ConsumeIntegral<size_t>(), + /*max_pct=*/fuzzed_data_provider.ConsumeIntegral<size_t>(), + /*network=*/std::nullopt); }, [&] { (void)connman.GetAddresses( - /* requestor */ random_node, - /* max_addresses */ fuzzed_data_provider.ConsumeIntegral<size_t>(), - /* max_pct */ fuzzed_data_provider.ConsumeIntegral<size_t>()); + /*requestor=*/random_node, + /*max_addresses=*/fuzzed_data_provider.ConsumeIntegral<size_t>(), + /*max_pct=*/fuzzed_data_provider.ConsumeIntegral<size_t>()); }, [&] { (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index a9325fa738..48574d71cc 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -189,7 +189,7 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, { BlockMerkleRoot(block, &mutated); }) FUZZ_TARGET_DESERIALIZE(addrman_deserialize, { - AddrMan am(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); + AddrMan am(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); DeserializeFromFuzzingInput(buffer, am); }) FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp index 2e3b51e753..64031fde42 100644 --- a/src/test/fuzz/node_eviction.cpp +++ b/src/test/fuzz/node_eviction.cpp @@ -20,18 +20,18 @@ FUZZ_TARGET(node_eviction) std::vector<NodeEvictionCandidate> eviction_candidates; LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { eviction_candidates.push_back({ - /* id */ fuzzed_data_provider.ConsumeIntegral<NodeId>(), - /* nTimeConnected */ fuzzed_data_provider.ConsumeIntegral<int64_t>(), - /* m_min_ping_time */ std::chrono::microseconds{fuzzed_data_provider.ConsumeIntegral<int64_t>()}, - /* nLastBlockTime */ fuzzed_data_provider.ConsumeIntegral<int64_t>(), - /* nLastTXTime */ fuzzed_data_provider.ConsumeIntegral<int64_t>(), - /* fRelevantServices */ fuzzed_data_provider.ConsumeBool(), - /* fRelayTxes */ fuzzed_data_provider.ConsumeBool(), - /* fBloomFilter */ fuzzed_data_provider.ConsumeBool(), - /* nKeyedNetGroup */ fuzzed_data_provider.ConsumeIntegral<uint64_t>(), - /* prefer_evict */ fuzzed_data_provider.ConsumeBool(), - /* m_is_local */ fuzzed_data_provider.ConsumeBool(), - /* m_network */ fuzzed_data_provider.PickValueInArray(ALL_NETWORKS), + /*id=*/fuzzed_data_provider.ConsumeIntegral<NodeId>(), + /*nTimeConnected=*/fuzzed_data_provider.ConsumeIntegral<int64_t>(), + /*m_min_ping_time=*/std::chrono::microseconds{fuzzed_data_provider.ConsumeIntegral<int64_t>()}, + /*nLastBlockTime=*/fuzzed_data_provider.ConsumeIntegral<int64_t>(), + /*nLastTXTime=*/fuzzed_data_provider.ConsumeIntegral<int64_t>(), + /*fRelevantServices=*/fuzzed_data_provider.ConsumeBool(), + /*fRelayTxes=*/fuzzed_data_provider.ConsumeBool(), + /*fBloomFilter=*/fuzzed_data_provider.ConsumeBool(), + /*nKeyedNetGroup=*/fuzzed_data_provider.ConsumeIntegral<uint64_t>(), + /*prefer_evict=*/fuzzed_data_provider.ConsumeBool(), + /*m_is_local=*/fuzzed_data_provider.ConsumeBool(), + /*m_network=*/fuzzed_data_provider.PickValueInArray(ALL_NETWORKS), }); } // Make a copy since eviction_candidates may be in some valid but otherwise diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp index 63dc4ce1d9..e4d95f72a0 100644 --- a/src/test/fuzz/policy_estimator.cpp +++ b/src/test/fuzz/policy_estimator.cpp @@ -35,7 +35,7 @@ FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator) const CTransaction tx{*mtx}; block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool()); if (fuzzed_data_provider.ConsumeBool()) { - (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool()); + (void)block_policy_estimator.removeTx(tx.GetHash(), /*inBlock=*/fuzzed_data_provider.ConsumeBool()); } }, [&] { @@ -56,7 +56,7 @@ FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator) block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs); }, [&] { - (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool()); + (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /*inBlock=*/fuzzed_data_provider.ConsumeBool()); }, [&] { block_policy_estimator.FlushUnconfirmed(); diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 7b99193ad0..94a71859e9 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -83,7 +83,7 @@ void fuzz_target(FuzzBufferType buffer, const std::string& LIMIT_TO_MESSAGE_TYPE p2p_node.fSuccessfullyConnected = successfully_connected; connman.AddTestNode(p2p_node); g_setup->m_node.peerman->InitializeNode(&p2p_node); - FillNode(fuzzed_data_provider, p2p_node, /* init_version */ successfully_connected); + FillNode(fuzzed_data_provider, p2p_node, /*init_version=*/successfully_connected); const auto mock_time = ConsumeTime(fuzzed_data_provider); SetMockTime(mock_time); diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 91ec2aafde..21a959315e 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -50,7 +50,7 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages) p2p_node.fSuccessfullyConnected = successfully_connected; p2p_node.fPauseSend = false; g_setup->m_node.peerman->InitializeNode(&p2p_node); - FillNode(fuzzed_data_provider, p2p_node, /* init_version */ successfully_connected); + FillNode(fuzzed_data_provider, p2p_node, /*init_version=*/successfully_connected); connman.AddTestNode(p2p_node); } diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 0979967384..eb170aab76 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -164,7 +164,7 @@ FUZZ_TARGET_INIT(script, initialize_script) const std::string encoded_dest{EncodeDestination(tx_destination_1)}; const UniValue json_dest{DescribeAddress(tx_destination_1)}; Assert(tx_destination_1 == DecodeDestination(encoded_dest)); - (void)GetKeyForDestination(/* store */ {}, tx_destination_1); + (void)GetKeyForDestination(/*store=*/{}, tx_destination_1); const CScript dest{GetScriptForDestination(tx_destination_1)}; const bool valid{IsValidDestination(tx_destination_1)}; Assert(dest.empty() != valid); diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp index a80338b965..4669f783aa 100644 --- a/src/test/fuzz/script_assets_test_minimizer.cpp +++ b/src/test/fuzz/script_assets_test_minimizer.cpp @@ -190,7 +190,7 @@ void test_init() static ECCVerifyHandle handle; } -FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, test_init, /* hidden */ true) +FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, test_init, /*hidden=*/true) { if (buffer.size() < 2 || buffer.back() != '\n' || buffer[buffer.size() - 2] != ',') return; const std::string str((const char*)buffer.data(), buffer.size() - 2); diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index ba6c500543..389da6f5d7 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -102,6 +102,6 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction) (void)IsWitnessStandard(tx, coins_view_cache); UniValue u(UniValue::VOBJ); - TxToUniv(tx, /* hashBlock */ uint256::ZERO, u); - TxToUniv(tx, /* hashBlock */ uint256::ONE, u); + TxToUniv(tx, /*hashBlock=*/uint256::ZERO, u); + TxToUniv(tx, /*hashBlock=*/uint256::ONE, u); } diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index ac1fb657f1..c32c965ab0 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -85,8 +85,8 @@ void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CCh { BlockAssembler::Options options; options.nBlockMaxWeight = fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BLOCK_WEIGHT); - options.blockMinFeeRate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /* max */ COIN)}; - auto assembler = BlockAssembler{chainstate, *static_cast<CTxMemPool*>(&tx_pool), ::Params(), options}; + options.blockMinFeeRate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)}; + auto assembler = BlockAssembler{chainstate, *static_cast<CTxMemPool*>(&tx_pool), chainstate.m_params, options}; auto block_template = assembler.CreateNewBlock(CScript{} << OP_TRUE); Assert(block_template->block.vtx.size() >= 1); } @@ -131,7 +131,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) // The sum of the values of all spendable outpoints constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN}; - CTxMemPool tx_pool_{/* estimator */ nullptr, /* check_ratio */ 1}; + CTxMemPool tx_pool_{/*estimator=*/nullptr, /*check_ratio=*/1}; MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_); // Helper to query an amount @@ -224,13 +224,13 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) // Make sure ProcessNewPackage on one transaction works and always fully validates the transaction. // The result is not guaranteed to be the same as what is returned by ATMP. const auto result_package = WITH_LOCK(::cs_main, - return ProcessNewPackage(node.chainman->ActiveChainstate(), tx_pool, {tx}, true)); + return ProcessNewPackage(chainstate, tx_pool, {tx}, true)); auto it = result_package.m_tx_results.find(tx->GetWitnessHash()); Assert(it != result_package.m_tx_results.end()); Assert(it->second.m_result_type == MempoolAcceptResult::ResultType::VALID || it->second.m_result_type == MempoolAcceptResult::ResultType::INVALID); - const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx_pool, tx, bypass_limits)); + const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(tx_pool, chainstate, tx, GetTime(), bypass_limits, /* test_accept= */ false)); const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID; SyncWithValidationInterfaceQueue(); UnregisterSharedValidationInterface(txr); @@ -267,10 +267,10 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) // Outpoints that no longer count toward the total supply std::set<COutPoint> consumed_supply; for (const auto& removed_tx : removed) { - insert_tx(/* created_by_tx */ {consumed_erased}, /* consumed_by_tx */ {outpoints_supply}, /* tx */ *removed_tx); + insert_tx(/*created_by_tx=*/{consumed_erased}, /*consumed_by_tx=*/{outpoints_supply}, /*tx=*/*removed_tx); } for (const auto& added_tx : added) { - insert_tx(/* created_by_tx */ {outpoints_supply, outpoints_rbf}, /* consumed_by_tx */ {consumed_supply}, /* tx */ *added_tx); + insert_tx(/*created_by_tx=*/{outpoints_supply, outpoints_rbf}, /*consumed_by_tx=*/{consumed_supply}, /*tx=*/*added_tx); } for (const auto& p : consumed_erased) { Assert(outpoints_supply.erase(p) == 1); @@ -303,7 +303,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool) txids.push_back(ConsumeUInt256(fuzzed_data_provider)); } - CTxMemPool tx_pool_{/* estimator */ nullptr, /* check_ratio */ 1}; + CTxMemPool tx_pool_{/*estimator=*/nullptr, /*check_ratio=*/1}; MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_); LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300) @@ -330,7 +330,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool) const auto tx = MakeTransactionRef(mut_tx); const bool bypass_limits = fuzzed_data_provider.ConsumeBool(); ::fRequireStandard = fuzzed_data_provider.ConsumeBool(); - const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(node.chainman->ActiveChainstate(), tx_pool, tx, bypass_limits)); + const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(tx_pool, chainstate, tx, GetTime(), bypass_limits, /* test_accept= */ false)); const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID; if (accepted) { txids.push_back(tx->GetHash()); diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index 8d2a06f11a..02039cba81 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -49,7 +49,7 @@ FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain) } catch (const std::ios_base::failure&) { return false; } - return chainman.ActivateSnapshot(infile, metadata, /* in_memory */ true); + return chainman.ActivateSnapshot(infile, metadata, /*in_memory=*/true); }}; if (fuzzed_data_provider.ConsumeBool()) { diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index b3497b8ef8..005752d508 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -602,7 +602,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // // [tx1] // - CTransactionRef tx1 = make_tx(/* output_values */ {10 * COIN}); + CTransactionRef tx1 = make_tx(/*output_values=*/{10 * COIN}); pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); // Ancestors / descendants should be 1 / 1 (itself / itself) @@ -614,7 +614,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // // [tx1].0 <- [tx2] // - CTransactionRef tx2 = make_tx(/* output_values */ {495 * CENT, 5 * COIN}, /* inputs */ {tx1}); + CTransactionRef tx2 = make_tx(/*output_values=*/{495 * CENT, 5 * COIN}, /*inputs=*/{tx1}); pool.addUnchecked(entry.Fee(10000LL).FromTx(tx2)); // Ancestors / descendants should be: @@ -633,7 +633,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // // [tx1].0 <- [tx2].0 <- [tx3] // - CTransactionRef tx3 = make_tx(/* output_values */ {290 * CENT, 200 * CENT}, /* inputs */ {tx2}); + CTransactionRef tx3 = make_tx(/*output_values=*/{290 * CENT, 200 * CENT}, /*inputs=*/{tx2}); pool.addUnchecked(entry.Fee(10000LL).FromTx(tx3)); // Ancestors / descendants should be: @@ -658,7 +658,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // | // \---1 <- [tx4] // - CTransactionRef tx4 = make_tx(/* output_values */ {290 * CENT, 250 * CENT}, /* inputs */ {tx2}, /* input_indices */ {1}); + CTransactionRef tx4 = make_tx(/*output_values=*/{290 * CENT, 250 * CENT}, /*inputs=*/{tx2}, /*input_indices=*/{1}); pool.addUnchecked(entry.Fee(10000LL).FromTx(tx4)); // Ancestors / descendants should be: @@ -694,14 +694,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) CAmount v = 5 * COIN; for (uint64_t i = 0; i < 5; i++) { CTransactionRef& tyi = *ty[i]; - tyi = make_tx(/* output_values */ {v}, /* inputs */ i > 0 ? std::vector<CTransactionRef>{*ty[i - 1]} : std::vector<CTransactionRef>{}); + tyi = make_tx(/*output_values=*/{v}, /*inputs=*/i > 0 ? std::vector<CTransactionRef>{*ty[i - 1]} : std::vector<CTransactionRef>{}); v -= 50 * CENT; pool.addUnchecked(entry.Fee(10000LL).FromTx(tyi)); pool.GetTransactionAncestry(tyi->GetHash(), ancestors, descendants); BOOST_CHECK_EQUAL(ancestors, i+1); BOOST_CHECK_EQUAL(descendants, i+1); } - CTransactionRef ty6 = make_tx(/* output_values */ {5 * COIN}, /* inputs */ {tx3, ty5}); + CTransactionRef ty6 = make_tx(/*output_values=*/{5 * COIN}, /*inputs=*/{tx3, ty5}); pool.addUnchecked(entry.Fee(10000LL).FromTx(ty6)); // Ancestors / descendants should be: @@ -755,10 +755,10 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // \---1 <- [tc].0 --<--/ // CTransactionRef ta, tb, tc, td; - ta = make_tx(/* output_values */ {10 * COIN}); - tb = make_tx(/* output_values */ {5 * COIN, 3 * COIN}, /* inputs */ {ta}); - tc = make_tx(/* output_values */ {2 * COIN}, /* inputs */ {tb}, /* input_indices */ {1}); - td = make_tx(/* output_values */ {6 * COIN}, /* inputs */ {tb, tc}, /* input_indices */ {0, 0}); + ta = make_tx(/*output_values=*/{10 * COIN}); + tb = make_tx(/*output_values=*/{5 * COIN, 3 * COIN}, /*inputs=*/ {ta}); + tc = make_tx(/*output_values=*/{2 * COIN}, /*inputs=*/{tb}, /*input_indices=*/{1}); + td = make_tx(/*output_values=*/{6 * COIN}, /*inputs=*/{tb, tc}, /*input_indices=*/{0, 0}); pool.clear(); pool.addUnchecked(entry.Fee(10000LL).FromTx(ta)); pool.addUnchecked(entry.Fee(10000LL).FromTx(tb)); diff --git a/src/test/net_peer_eviction_tests.cpp b/src/test/net_peer_eviction_tests.cpp index 5eb280b498..9470ed814d 100644 --- a/src/test/net_peer_eviction_tests.cpp +++ b/src/test/net_peer_eviction_tests.cpp @@ -72,8 +72,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = false; c.m_network = NET_IPV4; }, - /* protected_peer_ids */ {0, 1, 2, 3, 4, 5}, - /* unprotected_peer_ids */ {6, 7, 8, 9, 10, 11}, + /*protected_peer_ids=*/{0, 1, 2, 3, 4, 5}, + /*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11}, random_context)); // Verify in the opposite direction. @@ -83,8 +83,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = false; c.m_network = NET_IPV6; }, - /* protected_peer_ids */ {6, 7, 8, 9, 10, 11}, - /* unprotected_peer_ids */ {0, 1, 2, 3, 4, 5}, + /*protected_peer_ids=*/{6, 7, 8, 9, 10, 11}, + /*unprotected_peer_ids=*/{0, 1, 2, 3, 4, 5}, random_context)); // Test protection of onion, localhost, and I2P peers... @@ -96,8 +96,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = false; c.m_network = (c.id == 3 || c.id == 8 || c.id == 9) ? NET_ONION : NET_IPV4; }, - /* protected_peer_ids */ {3, 8, 9}, - /* unprotected_peer_ids */ {}, + /*protected_peer_ids=*/{3, 8, 9}, + /*unprotected_peer_ids=*/{}, random_context)); // Expect 1/4 onion peers and 1/4 of the other peers to be protected, @@ -108,8 +108,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = false; c.m_network = (c.id == 3 || c.id > 7) ? NET_ONION : NET_IPV6; }, - /* protected_peer_ids */ {0, 1, 2, 3, 8, 9}, - /* unprotected_peer_ids */ {4, 5, 6, 7, 10, 11}, + /*protected_peer_ids=*/{0, 1, 2, 3, 8, 9}, + /*unprotected_peer_ids=*/{4, 5, 6, 7, 10, 11}, random_context)); // Expect 1/4 localhost peers to be protected from eviction, @@ -119,8 +119,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id == 1 || c.id == 9 || c.id == 11); c.m_network = NET_IPV4; }, - /* protected_peer_ids */ {1, 9, 11}, - /* unprotected_peer_ids */ {}, + /*protected_peer_ids=*/{1, 9, 11}, + /*unprotected_peer_ids=*/{}, random_context)); // Expect 1/4 localhost peers and 1/4 of the other peers to be protected, @@ -131,8 +131,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id > 6); c.m_network = NET_IPV6; }, - /* protected_peer_ids */ {0, 1, 2, 7, 8, 9}, - /* unprotected_peer_ids */ {3, 4, 5, 6, 10, 11}, + /*protected_peer_ids=*/{0, 1, 2, 7, 8, 9}, + /*unprotected_peer_ids=*/{3, 4, 5, 6, 10, 11}, random_context)); // Expect 1/4 I2P peers to be protected from eviction, @@ -142,8 +142,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = false; c.m_network = (c.id == 2 || c.id == 7 || c.id == 10) ? NET_I2P : NET_IPV4; }, - /* protected_peer_ids */ {2, 7, 10}, - /* unprotected_peer_ids */ {}, + /*protected_peer_ids=*/{2, 7, 10}, + /*unprotected_peer_ids=*/{}, random_context)); // Expect 1/4 I2P peers and 1/4 of the other peers to be protected, @@ -154,8 +154,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = false; c.m_network = (c.id == 4 || c.id > 8) ? NET_I2P : NET_IPV6; }, - /* protected_peer_ids */ {0, 1, 2, 4, 9, 10}, - /* unprotected_peer_ids */ {3, 5, 6, 7, 8, 11}, + /*protected_peer_ids=*/{0, 1, 2, 4, 9, 10}, + /*unprotected_peer_ids=*/{3, 5, 6, 7, 8, 11}, random_context)); // Tests with 2 networks... @@ -169,8 +169,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id == 4); c.m_network = (c.id == 3) ? NET_ONION : NET_IPV4; }, - /* protected_peer_ids */ {0, 4}, - /* unprotected_peer_ids */ {1, 2}, + /*protected_peer_ids=*/{0, 4}, + /*unprotected_peer_ids=*/{1, 2}, random_context)); // Combined test: expect having 1 localhost and 1 onion peer out of 7 to @@ -182,8 +182,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id == 6); c.m_network = (c.id == 5) ? NET_ONION : NET_IPV4; }, - /* protected_peer_ids */ {0, 1, 6}, - /* unprotected_peer_ids */ {2, 3, 4, 5}, + /*protected_peer_ids=*/{0, 1, 6}, + /*unprotected_peer_ids=*/{2, 3, 4, 5}, random_context)); // Combined test: expect having 1 localhost and 1 onion peer out of 8 to @@ -195,8 +195,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id == 6); c.m_network = (c.id == 5) ? NET_ONION : NET_IPV4; }, - /* protected_peer_ids */ {0, 1, 5, 6}, - /* unprotected_peer_ids */ {2, 3, 4, 7}, + /*protected_peer_ids=*/{0, 1, 5, 6}, + /*unprotected_peer_ids=*/{2, 3, 4, 7}, random_context)); // Combined test: expect having 3 localhost and 3 onion peers out of 12 to @@ -208,8 +208,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id == 6 || c.id == 9 || c.id == 11); c.m_network = (c.id == 7 || c.id == 8 || c.id == 10) ? NET_ONION : NET_IPV6; }, - /* protected_peer_ids */ {0, 1, 2, 6, 7, 9}, - /* unprotected_peer_ids */ {3, 4, 5, 8, 10, 11}, + /*protected_peer_ids=*/{0, 1, 2, 6, 7, 9}, + /*unprotected_peer_ids=*/{3, 4, 5, 8, 10, 11}, random_context)); // Combined test: expect having 4 localhost and 1 onion peer out of 12 to @@ -220,8 +220,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id > 4 && c.id < 9); c.m_network = (c.id == 10) ? NET_ONION : NET_IPV4; }, - /* protected_peer_ids */ {0, 1, 2, 5, 6, 10}, - /* unprotected_peer_ids */ {3, 4, 7, 8, 9, 11}, + /*protected_peer_ids=*/{0, 1, 2, 5, 6, 10}, + /*unprotected_peer_ids=*/{3, 4, 7, 8, 9, 11}, random_context)); // Combined test: expect having 4 localhost and 2 onion peers out of 16 to @@ -232,8 +232,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id == 6 || c.id == 9 || c.id == 11 || c.id == 12); c.m_network = (c.id == 8 || c.id == 10) ? NET_ONION : NET_IPV6; }, - /* protected_peer_ids */ {0, 1, 2, 3, 6, 8, 9, 10}, - /* unprotected_peer_ids */ {4, 5, 7, 11, 12, 13, 14, 15}, + /*protected_peer_ids=*/{0, 1, 2, 3, 6, 8, 9, 10}, + /*unprotected_peer_ids=*/{4, 5, 7, 11, 12, 13, 14, 15}, random_context)); // Combined test: expect having 5 localhost and 1 onion peer out of 16 to @@ -245,8 +245,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id > 10); c.m_network = (c.id == 10) ? NET_ONION : NET_IPV4; }, - /* protected_peer_ids */ {0, 1, 2, 3, 10, 11, 12, 13}, - /* unprotected_peer_ids */ {4, 5, 6, 7, 8, 9, 14, 15}, + /*protected_peer_ids=*/{0, 1, 2, 3, 10, 11, 12, 13}, + /*unprotected_peer_ids=*/{4, 5, 6, 7, 8, 9, 14, 15}, random_context)); // Combined test: expect having 1 localhost and 4 onion peers out of 16 to @@ -258,8 +258,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_is_local = (c.id == 15); c.m_network = (c.id > 6 && c.id < 11) ? NET_ONION : NET_IPV6; }, - /* protected_peer_ids */ {0, 1, 2, 3, 7, 8, 9, 15}, - /* unprotected_peer_ids */ {5, 6, 10, 11, 12, 13, 14}, + /*protected_peer_ids=*/{0, 1, 2, 3, 7, 8, 9, 15}, + /*unprotected_peer_ids=*/{5, 6, 10, 11, 12, 13, 14}, random_context)); // Combined test: expect having 2 onion and 4 I2P out of 12 peers to protect @@ -277,8 +277,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV4; } }, - /* protected_peer_ids */ {0, 1, 2, 6, 8, 10}, - /* unprotected_peer_ids */ {3, 4, 5, 7, 9, 11}, + /*protected_peer_ids=*/{0, 1, 2, 6, 8, 10}, + /*unprotected_peer_ids=*/{3, 4, 5, 7, 9, 11}, random_context)); // Tests with 3 networks... @@ -298,8 +298,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV6; } }, - /* protected_peer_ids */ {0, 4}, - /* unprotected_peer_ids */ {1, 2}, + /*protected_peer_ids=*/{0, 4}, + /*unprotected_peer_ids=*/{1, 2}, random_context)); // Combined test: expect having 1 localhost, 1 I2P and 1 onion peer out of 7 @@ -317,8 +317,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV6; } }, - /* protected_peer_ids */ {0, 1, 6}, - /* unprotected_peer_ids */ {2, 3, 4, 5}, + /*protected_peer_ids=*/{0, 1, 6}, + /*unprotected_peer_ids=*/{2, 3, 4, 5}, random_context)); // Combined test: expect having 1 localhost, 1 I2P and 1 onion peer out of 8 @@ -336,8 +336,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV6; } }, - /* protected_peer_ids */ {0, 1, 5, 6}, - /* unprotected_peer_ids */ {2, 3, 4, 7}, + /*protected_peer_ids=*/{0, 1, 5, 6}, + /*unprotected_peer_ids=*/{2, 3, 4, 7}, random_context)); // Combined test: expect having 4 localhost, 2 I2P, and 2 onion peers out of @@ -355,8 +355,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV4; } }, - /* protected_peer_ids */ {0, 1, 2, 3, 6, 7, 9, 11}, - /* unprotected_peer_ids */ {4, 5, 8, 10, 12, 13, 14, 15}, + /*protected_peer_ids=*/{0, 1, 2, 3, 6, 7, 9, 11}, + /*unprotected_peer_ids=*/{4, 5, 8, 10, 12, 13, 14, 15}, random_context)); // Combined test: expect having 1 localhost, 8 I2P and 1 onion peer out of @@ -374,8 +374,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV6; } }, - /* protected_peer_ids */ {0, 1, 2, 3, 4, 5, 12, 15, 16, 17, 18, 23}, - /* unprotected_peer_ids */ {6, 7, 8, 9, 10, 11, 13, 14, 19, 20, 21, 22}, + /*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 12, 15, 16, 17, 18, 23}, + /*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 13, 14, 19, 20, 21, 22}, random_context)); // Combined test: expect having 1 localhost, 3 I2P and 6 onion peers out of @@ -393,8 +393,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV4; } }, - /* protected_peer_ids */ {0, 1, 2, 3, 4, 5, 12, 14, 15, 17, 18, 19}, - /* unprotected_peer_ids */ {6, 7, 8, 9, 10, 11, 13, 16, 20, 21, 22, 23}, + /*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 12, 14, 15, 17, 18, 19}, + /*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 13, 16, 20, 21, 22, 23}, random_context)); // Combined test: expect having 1 localhost, 7 I2P and 4 onion peers out of @@ -412,8 +412,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV6; } }, - /* protected_peer_ids */ {0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 17, 18}, - /* unprotected_peer_ids */ {6, 7, 8, 9, 10, 11, 16, 19, 20, 21, 22, 23}, + /*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 17, 18}, + /*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 16, 19, 20, 21, 22, 23}, random_context)); // Combined test: expect having 8 localhost, 4 I2P, and 3 onion peers out of @@ -431,8 +431,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) c.m_network = NET_IPV4; } }, - /* protected_peer_ids */ {0, 1, 2, 3, 4, 5, 7, 8, 11, 12, 16, 17}, - /* unprotected_peer_ids */ {6, 9, 10, 13, 14, 15, 18, 19, 20, 21, 22, 23}, + /*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 7, 8, 11, 12, 16, 17}, + /*unprotected_peer_ids=*/{6, 9, 10, 13, 14, 15, 18, 19, 20, 21, 22, 23}, random_context)); } diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 29938d4ede..c5bd9c73fd 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -607,7 +607,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) in_addr ipv4AddrPeer; ipv4AddrPeer.s_addr = 0xa0b0c001; CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK); - std::unique_ptr<CNode> pnode = std::make_unique<CNode>(0, NODE_NETWORK, INVALID_SOCKET, addr, /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0, CAddress{}, /* pszDest */ std::string{}, ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false); + std::unique_ptr<CNode> pnode = std::make_unique<CNode>(0, NODE_NETWORK, INVALID_SOCKET, addr, /*nKeyedNetGroupIn=*/0, /*nLocalHostNonceIn=*/0, CAddress{}, /*pszDest=*/std::string{}, ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false); pnode->fSuccessfullyConnected.store(true); // the peer claims to be reaching us via IPv6 diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index d57c000b92..fed941247c 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(manythreads) std::mutex counterMutex[10]; int counter[10] = { 0 }; - FastRandomContext rng{/* fDeterministic */ true}; + FastRandomContext rng{/*fDeterministic=*/true}; auto zeroToNine = [](FastRandomContext& rc) -> int { return rc.randrange(10); }; // [0, 9] auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000] auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000] diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index e05781a6f0..6b0614ed97 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -249,26 +249,26 @@ BOOST_AUTO_TEST_CASE(tx_valid) BOOST_ERROR("Bad test flags: " << strTest); } - BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~verify_flags, txdata, strTest, /* expect_valid */ true), + BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~verify_flags, txdata, strTest, /*expect_valid=*/true), "Tx unexpectedly failed: " << strTest); // Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction for (const auto& [name, flag] : mapFlagNames) { // Removing individual flags unsigned int flags = TrimFlags(~(verify_flags | flag)); - if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ true)) { + if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) { BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest); } // Removing random combinations of flags flags = TrimFlags(~(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size()))); - if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ true)) { + if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) { BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags) << ": " << strTest); } } // Check that flags are maximal: transaction should fail if any unset flags are set. for (auto flags_excluding_one : ExcludeIndividualFlags(verify_flags)) { - if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~flags_excluding_one, txdata, strTest, /* expect_valid */ false)) { + if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, ~flags_excluding_one, txdata, strTest, /*expect_valid=*/false)) { BOOST_ERROR("Too many flags unset: " << strTest); } } @@ -340,26 +340,26 @@ BOOST_AUTO_TEST_CASE(tx_invalid) } // Not using FillFlags() in the main test, in order to detect invalid verifyFlags combination - BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, verify_flags, txdata, strTest, /* expect_valid */ false), + BOOST_CHECK_MESSAGE(CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, verify_flags, txdata, strTest, /*expect_valid=*/false), "Tx unexpectedly passed: " << strTest); // Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction for (const auto& [name, flag] : mapFlagNames) { unsigned int flags = FillFlags(verify_flags | flag); // Adding individual flags - if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ false)) { + if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) { BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest); } // Adding random combinations of flags flags = FillFlags(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size())); - if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /* expect_valid */ false)) { + if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) { BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest); } } // Check that flags are minimal: transaction should succeed if any set flags are unset. for (auto flags_excluding_one : ExcludeIndividualFlags(verify_flags)) { - if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags_excluding_one, txdata, strTest, /* expect_valid */ true)) { + if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags_excluding_one, txdata, strTest, /*expect_valid=*/true)) { BOOST_ERROR("Too many flags set: " << strTest); } } diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp index 8d92bee221..2193e21780 100644 --- a/src/test/txpackage_tests.cpp +++ b/src/test/txpackage_tests.cpp @@ -84,10 +84,10 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey())); auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/ tx_parent, /*input_vout=*/0, /*input_height=*/ 101, /*input_signing_key=*/parent_key, - /*output_destination */ child_locking_script, + /*output_destination=*/child_locking_script, /*output_amount=*/ CAmount(48 * COIN), /*submit=*/false); CTransactionRef tx_child = MakeTransactionRef(mtx_child); - const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {tx_parent, tx_child}, /* test_accept */ true); + const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {tx_parent, tx_child}, /*test_accept=*/true); BOOST_CHECK_MESSAGE(result_parent_child.m_state.IsValid(), "Package validation unexpectedly failed: " << result_parent_child.m_state.GetRejectReason()); auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash()); @@ -103,7 +103,7 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) // A single, giant transaction submitted through ProcessNewPackage fails on single tx policy. CTransactionRef giant_ptx = create_placeholder_tx(999, 999); BOOST_CHECK(GetVirtualTransactionSize(*giant_ptx) > MAX_PACKAGE_SIZE * 1000); - auto result_single_large = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {giant_ptx}, /* test_accept */ true); + auto result_single_large = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {giant_ptx}, /*test_accept=*/true); BOOST_CHECK(result_single_large.m_state.IsInvalid()); BOOST_CHECK_EQUAL(result_single_large.m_state.GetResult(), PackageValidationResult::PCKG_TX); BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(), "transaction failed"); diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h index e95573022c..555979d94e 100644 --- a/src/test/util/chainstate.h +++ b/src/test/util/chainstate.h @@ -47,7 +47,7 @@ CreateAndActivateUTXOSnapshot(NodeContext& node, const fs::path root, F malleati malleation(auto_infile, metadata); - return node.chainman->ActivateSnapshot(auto_infile, metadata, /*in_memory*/ true); + return node.chainman->ActivateSnapshot(auto_infile, metadata, /*in_memory=*/true); } diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp index 28d7967078..696fd902f8 100644 --- a/src/test/util/net.cpp +++ b/src/test/util/net.cpp @@ -46,18 +46,18 @@ std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candida std::vector<NodeEvictionCandidate> candidates; for (int id = 0; id < n_candidates; ++id) { candidates.push_back({ - /* id */ id, - /* nTimeConnected */ static_cast<int64_t>(random_context.randrange(100)), - /* m_min_ping_time */ std::chrono::microseconds{random_context.randrange(100)}, - /* nLastBlockTime */ static_cast<int64_t>(random_context.randrange(100)), - /* nLastTXTime */ static_cast<int64_t>(random_context.randrange(100)), - /* fRelevantServices */ random_context.randbool(), - /* fRelayTxes */ random_context.randbool(), - /* fBloomFilter */ random_context.randbool(), - /* nKeyedNetGroup */ random_context.randrange(100), - /* prefer_evict */ random_context.randbool(), - /* m_is_local */ random_context.randbool(), - /* m_network */ ALL_NETWORKS[random_context.randrange(ALL_NETWORKS.size())], + /*id=*/id, + /*nTimeConnected=*/static_cast<int64_t>(random_context.randrange(100)), + /*m_min_ping_time=*/std::chrono::microseconds{random_context.randrange(100)}, + /*nLastBlockTime=*/static_cast<int64_t>(random_context.randrange(100)), + /*nLastTXTime=*/static_cast<int64_t>(random_context.randrange(100)), + /*fRelevantServices=*/random_context.randbool(), + /*fRelayTxes=*/random_context.randbool(), + /*fBloomFilter=*/random_context.randbool(), + /*nKeyedNetGroup=*/random_context.randrange(100), + /*prefer_evict=*/random_context.randbool(), + /*m_is_local=*/random_context.randbool(), + /*m_network=*/ALL_NETWORKS[random_context.randrange(ALL_NETWORKS.size())], }); } return candidates; diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index cdb8238095..f5cc88f4ce 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -179,7 +179,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const m_node.chainman->InitializeChainstate(m_node.mempool.get()); m_node.chainman->ActiveChainstate().InitCoinsDB( - /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); + /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); assert(!m_node.chainman->ActiveChainstate().CanFlushToDisk()); m_node.chainman->ActiveChainstate().InitCoinsCache(1 << 23); assert(m_node.chainman->ActiveChainstate().CanFlushToDisk()); @@ -192,7 +192,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString())); } - m_node.addrman = std::make_unique<AddrMan>(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); + m_node.addrman = std::make_unique<AddrMan>(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests. m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index eb7bc071e5..4f2ccb6ebb 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -56,7 +56,7 @@ void Seed(FastRandomContext& ctx); static inline void SeedInsecureRand(SeedRand seed = SeedRand::SEED) { if (seed == SeedRand::ZEROS) { - g_insecure_rand_ctx = FastRandomContext(/* deterministic */ true); + g_insecure_rand_ctx = FastRandomContext(/*fDeterministic=*/true); } else { Seed(g_insecure_rand_ctx); } diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index 9bb08f774f..b890ae4931 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool)); c1.InitCoinsDB( - /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); + /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23)); // Add a coin to the in-memory cache, upsize once, then downsize. diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index be9e05a65e..a1f70e7e70 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) CChainState& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(&mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( - /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); + /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23)); BOOST_CHECK(!manager.IsSnapshotActive()); @@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) BOOST_CHECK_EQUAL(manager.SnapshotBlockhash().value(), snapshot_blockhash); c2.InitCoinsDB( - /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); + /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23)); // Unlike c1, which doesn't have any blocks. Gets us different tip, height. c2.LoadGenesisBlock(); @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( - /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); + /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); { LOCK(::cs_main); @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) CChainState& c2 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool, GetRandHash())); chainstates.push_back(&c2); c2.InitCoinsDB( - /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); + /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); { LOCK(::cs_main); diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp index 9136c497ea..b4daceb72c 100644 --- a/src/test/validation_flush_tests.cpp +++ b/src/test/validation_flush_tests.cpp @@ -21,7 +21,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) CTxMemPool mempool; BlockManager blockman{}; CChainState chainstate{&mempool, blockman, *Assert(m_node.chainman)}; - chainstate.InitCoinsDB(/*cache_size_bytes*/ 1 << 10, /*in_memory*/ true, /*should_wipe*/ false); + chainstate.InitCoinsDB(/*cache_size_bytes=*/1 << 10, /*in_memory=*/true, /*should_wipe=*/false); WITH_LOCK(::cs_main, chainstate.InitCoinsCache(1 << 10)); constexpr bool is_64_bit = sizeof(void*) == 8; @@ -56,7 +56,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Without any coins in the cache, we shouldn't need to flush. BOOST_CHECK_EQUAL( - chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 0), + chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::OK); // If the initial memory allocations of cacheCoins don't match these common @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) } BOOST_CHECK_EQUAL( - chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 0), + chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::CRITICAL); BOOST_TEST_MESSAGE("Exiting cache flush tests early due to unsupported arch"); @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) print_view_mem_usage(view); BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE); BOOST_CHECK_EQUAL( - chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 0), + chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::OK); } @@ -100,26 +100,26 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) for (int i{0}; i < 4; ++i) { add_coin(view); print_view_mem_usage(view); - if (chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 0) == + if (chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0) == CoinsCacheSizeState::CRITICAL) { break; } } BOOST_CHECK_EQUAL( - chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 0), + chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::CRITICAL); // Passing non-zero max mempool usage should allow us more headroom. BOOST_CHECK_EQUAL( - chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 1 << 10), + chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/1 << 10), CoinsCacheSizeState::OK); for (int i{0}; i < 3; ++i) { add_coin(view); print_view_mem_usage(view); BOOST_CHECK_EQUAL( - chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 1 << 10), + chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/1 << 10), CoinsCacheSizeState::OK); } diff --git a/src/validation.cpp b/src/validation.cpp index 714eab1f77..6ed5e7a548 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -331,8 +331,8 @@ void CChainState::MaybeUpdateMempoolForReorg( while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) { // ignore validation errors in resurrected transactions if (!fAddToMempool || (*it)->IsCoinBase() || - AcceptToMemoryPool( - *this, *m_mempool, *it, true /* bypass_limits */).m_result_type != + AcceptToMemoryPool(*m_mempool, *this, *it, GetTime(), + /* bypass_limits= */true, /* test_accept= */ false).m_result_type != MempoolAcceptResult::ResultType::VALID) { // If the transaction doesn't make it in to the mempool, remove any // transactions that depend on it (which would now be orphans). @@ -955,8 +955,8 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws) unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(m_active_chainstate.m_chain.Tip(), chainparams.GetConsensus()); if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, ws.m_precomputed_txdata, m_active_chainstate.CoinsTip())) { - return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s", - __func__, hash.ToString(), state.ToString()); + LogPrintf("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s\n", hash.ToString(), state.ToString()); + return Assume(false); } return true; @@ -1091,15 +1091,13 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std:: } // anon namespace -/** (try to) add transaction to memory pool with a specified acceptance time **/ -static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, - CChainState& active_chainstate, - const CTransactionRef &tx, int64_t nAcceptTime, - bool bypass_limits, bool test_accept) - EXCLUSIVE_LOCKS_REQUIRED(cs_main) +MempoolAcceptResult AcceptToMemoryPool(CTxMemPool& pool, CChainState& active_chainstate, const CTransactionRef& tx, + int64_t accept_time, bool bypass_limits, bool test_accept) + EXCLUSIVE_LOCKS_REQUIRED(cs_main) { + const CChainParams& chainparams{active_chainstate.m_params}; std::vector<COutPoint> coins_to_uncache; - auto args = MemPoolAccept::ATMPArgs::SingleAccept(chainparams, nAcceptTime, bypass_limits, coins_to_uncache, test_accept); + auto args = MemPoolAccept::ATMPArgs::SingleAccept(chainparams, accept_time, bypass_limits, coins_to_uncache, test_accept); const MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { // Remove coins that were not present in the coins cache before calling @@ -1116,12 +1114,6 @@ static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainp return result; } -MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, const CTransactionRef& tx, - bool bypass_limits, bool test_accept) -{ - return AcceptToMemoryPoolWithTime(Params(), pool, active_chainstate, tx, GetTime(), bypass_limits, test_accept); -} - PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool, const Package& package, bool test_accept) { @@ -1174,8 +1166,8 @@ CChainState::CChainState( ChainstateManager& chainman, std::optional<uint256> from_snapshot_blockhash) : m_mempool(mempool), - m_params(::Params()), m_blockman(blockman), + m_params(::Params()), m_chainman(chainman), m_from_snapshot_blockhash(from_snapshot_blockhash) {} @@ -2114,6 +2106,13 @@ bool CChainState::FlushStateToDisk( nLastFlush = nNow; full_flush_completed = true; } + TRACE6(utxocache, flush, + (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs) + (u_int32_t)mode, + (u_int64_t)coins_count, + (u_int64_t)coins_mem_usage, + (bool)fFlushForPrune, + (bool)fDoFullFlush); } if (full_flush_completed) { // Update best block in wallet (so we can detect restored wallets). @@ -3506,7 +3505,7 @@ MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& state.Invalid(TxValidationResult::TX_NO_MEMPOOL, "no-mempool"); return MempoolAcceptResult::Failure(state); } - auto result = AcceptToMemoryPool(active_chainstate, *active_chainstate.m_mempool, tx, /*bypass_limits=*/ false, test_accept); + auto result = AcceptToMemoryPool(*active_chainstate.m_mempool, active_chainstate, tx, GetTime(), /* bypass_limits= */ false, test_accept); active_chainstate.m_mempool->check(active_chainstate.CoinsTip(), active_chainstate.m_chain.Height() + 1); return result; } @@ -4536,7 +4535,6 @@ static const uint64_t MEMPOOL_DUMP_VERSION = 1; bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function) { - const CChainParams& chainparams = Params(); int64_t nExpiryTimeout = gArgs.GetIntArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60; FILE* filestr{mockable_fopen_function(gArgs.GetDataDirNet() / "mempool.dat", "rb")}; CAutoFile file(filestr, SER_DISK, CLIENT_VERSION); @@ -4574,8 +4572,8 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mocka } if (nTime > nNow - nExpiryTimeout) { LOCK(cs_main); - if (AcceptToMemoryPoolWithTime(chainparams, pool, active_chainstate, tx, nTime, false /* bypass_limits */, - false /* test_accept */).m_result_type == MempoolAcceptResult::ResultType::VALID) { + if (AcceptToMemoryPool(pool, active_chainstate, tx, nTime, /* bypass_limits= */ false, + /* test_accept= */ false).m_result_type == MempoolAcceptResult::ResultType::VALID) { ++count; } else { // mempool may contain the transaction already, e.g. from diff --git a/src/validation.h b/src/validation.h index a81188b5f2..881438f37a 100644 --- a/src/validation.h +++ b/src/validation.h @@ -208,19 +208,23 @@ struct PackageMempoolAcceptResult }; /** - * Try to add a transaction to the mempool. This is an internal function and is - * exposed only for testing. Client code should use ChainstateManager::ProcessTransaction() + * Try to add a transaction to the mempool. This is an internal function and is exposed only for testing. + * Client code should use ChainstateManager::ProcessTransaction() * - * @param[in] active_chainstate Reference to the active chainstate. * @param[in] pool Reference to the node's mempool. + * @param[in] active_chainstate Reference to the active chainstate. * @param[in] tx The transaction to submit for mempool acceptance. + * @param[in] accept_time The timestamp for adding the transaction to the mempool. Usually + * the current system time, but may be different. + * It is also used to determine when the entry expires. * @param[in] bypass_limits When true, don't enforce mempool fee and capacity limits. * @param[in] test_accept When true, run validation checks but don't submit to mempool. * * @returns a MempoolAcceptResult indicating whether the transaction was accepted/rejected with reason. */ -MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, const CTransactionRef& tx, - bool bypass_limits, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +MempoolAcceptResult AcceptToMemoryPool(CTxMemPool& pool, CChainState& active_chainstate, const CTransactionRef& tx, + int64_t accept_time, bool bypass_limits, bool test_accept) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** * Atomically test acceptance of a package. If the package only contains one tx, package rules still @@ -576,8 +580,6 @@ protected: //! Only the active chainstate has a mempool. CTxMemPool* m_mempool; - const CChainParams& m_params; - //! Manages the UTXO set, which is a reflection of the contents of `m_chain`. std::unique_ptr<CoinsViews> m_coins_views; @@ -586,6 +588,9 @@ public: //! CChainState instances. BlockManager& m_blockman; + /** Chain parameters for this chainstate */ + const CChainParams& m_params; + //! The chainstate manager that owns this chainstate. The reference is //! necessary so that this instance can check whether it is the active //! chainstate within deeply nested method calls. diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp index efef1ec754..6a73efb472 100644 --- a/src/wallet/external_signer_scriptpubkeyman.cpp +++ b/src/wallet/external_signer_scriptpubkeyman.cpp @@ -60,10 +60,10 @@ bool ExternalSignerScriptPubKeyMan::DisplayAddress(const CScript scriptPubKey, c } // If sign is true, transaction must previously have been filled -TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const +TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const { if (!sign) { - return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed); + return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed, finalize); } // Already complete if every input is now signed @@ -79,6 +79,6 @@ TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransact tfm::format(std::cerr, "Failed to sign: %s\n", strFailReason); return TransactionError::EXTERNAL_SIGNER_FAILED; } - FinalizePSBT(psbt); // This won't work in a multisig setup + if (finalize) FinalizePSBT(psbt); // This won't work in a multisig setup return TransactionError::OK; } diff --git a/src/wallet/external_signer_scriptpubkeyman.h b/src/wallet/external_signer_scriptpubkeyman.h index 61df3d0015..53d65d9e46 100644 --- a/src/wallet/external_signer_scriptpubkeyman.h +++ b/src/wallet/external_signer_scriptpubkeyman.h @@ -28,6 +28,6 @@ class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan bool DisplayAddress(const CScript scriptPubKey, const ExternalSigner &signer) const; - TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override; + TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; }; #endif // BITCOIN_WALLET_EXTERNAL_SIGNER_SCRIPTPUBKEYMAN_H diff --git a/src/wallet/ismine.h b/src/wallet/ismine.h index 38ed7e7770..8605547cf2 100644 --- a/src/wallet/ismine.h +++ b/src/wallet/ismine.h @@ -8,8 +8,9 @@ #include <script/standard.h> -#include <stdint.h> #include <bitset> +#include <cstdint> +#include <type_traits> class CWallet; class CScript; @@ -35,8 +36,7 @@ class CScript; * ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user. * */ -enum isminetype : unsigned int -{ +enum isminetype : unsigned int { ISMINE_NO = 0, ISMINE_WATCH_ONLY = 1 << 0, ISMINE_SPENDABLE = 1 << 1, @@ -46,7 +46,7 @@ enum isminetype : unsigned int ISMINE_ENUM_ELEMENTS, }; /** used for bitflags of isminetype */ -typedef uint8_t isminefilter; +using isminefilter = std::underlying_type<isminetype>::type; /** * Cachable amount subdivided into watchonly and spendable parts. diff --git a/src/wallet/rpc/signmessage.cpp b/src/wallet/rpc/signmessage.cpp new file mode 100644 index 0000000000..275eb2f1f7 --- /dev/null +++ b/src/wallet/rpc/signmessage.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2011-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <key_io.h> +#include <rpc/util.h> +#include <util/message.h> +#include <wallet/rpcwallet.h> +#include <wallet/wallet.h> + +#include <univalue.h> + +RPCHelpMan signmessage() +{ + return RPCHelpMan{"signmessage", + "\nSign a message with the private key of an address" + + HELP_REQUIRING_PASSPHRASE, + { + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the private key."}, + {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."}, + }, + RPCResult{ + RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64" + }, + RPCExamples{ + "\nUnlock the wallet for 30 seconds\n" + + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + + "\nCreate the signature\n" + + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + + "\nVerify the signature\n" + + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { + const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); + if (!pwallet) return NullUniValue; + + LOCK(pwallet->cs_wallet); + + EnsureWalletIsUnlocked(*pwallet); + + std::string strAddress = request.params[0].get_str(); + std::string strMessage = request.params[1].get_str(); + + CTxDestination dest = DecodeDestination(strAddress); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + const PKHash* pkhash = std::get_if<PKHash>(&dest); + if (!pkhash) { + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + } + + std::string signature; + SigningResult err = pwallet->SignMessage(strMessage, *pkhash, signature); + if (err == SigningResult::SIGNING_FAILED) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, SigningResultString(err)); + } else if (err != SigningResult::OK) { + throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err)); + } + + return signature; + }, + }; +} diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c895d5af8c..22ce271816 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -20,7 +20,6 @@ #include <script/sign.h> #include <util/bip32.h> #include <util/fees.h> -#include <util/message.h> // For MessageSign() #include <util/moneystr.h> #include <util/string.h> #include <util/system.h> @@ -48,7 +47,7 @@ using interfaces::FoundBlock; static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; -static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"}; +const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"}; static inline bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) { bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); @@ -612,63 +611,6 @@ static RPCHelpMan listaddressgroupings() }; } -static RPCHelpMan signmessage() -{ - return RPCHelpMan{"signmessage", - "\nSign a message with the private key of an address" + - HELP_REQUIRING_PASSPHRASE, - { - {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the private key."}, - {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."}, - }, - RPCResult{ - RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64" - }, - RPCExamples{ - "\nUnlock the wallet for 30 seconds\n" - + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + - "\nCreate the signature\n" - + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + - "\nVerify the signature\n" - + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") + - "\nAs a JSON-RPC call\n" - + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"") - }, - [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue -{ - const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); - if (!pwallet) return NullUniValue; - - LOCK(pwallet->cs_wallet); - - EnsureWalletIsUnlocked(*pwallet); - - std::string strAddress = request.params[0].get_str(); - std::string strMessage = request.params[1].get_str(); - - CTxDestination dest = DecodeDestination(strAddress); - if (!IsValidDestination(dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); - } - - const PKHash* pkhash = std::get_if<PKHash>(&dest); - if (!pkhash) { - throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); - } - - std::string signature; - SigningResult err = pwallet->SignMessage(strMessage, *pkhash, signature); - if (err == SigningResult::SIGNING_FAILED) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, SigningResultString(err)); - } else if (err != SigningResult::OK){ - throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err)); - } - - return signature; -}, - }; -} - static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { std::set<CTxDestination> address_set; @@ -3220,7 +3162,7 @@ static std::vector<RPCArg> FundTxDoc() {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, - {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n" + {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125-replaceable.\n" "Allows this transaction to be replaced by a transaction with higher fees"}, {"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n" "Used for fee estimation during coin selection.", @@ -4551,6 +4493,7 @@ static RPCHelpMan walletprocesspsbt() " \"NONE|ANYONECANPAY\"\n" " \"SINGLE|ANYONECANPAY\""}, {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"}, + {"finalize", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also finalize inputs if possible"}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -4572,7 +4515,7 @@ static RPCHelpMan walletprocesspsbt() // the user could have gotten from another RPC command prior to now wallet.BlockUntilSyncedToCurrentChain(); - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR}); + RPCTypeCheck(request.params, {UniValue::VSTR}); // Unserialize the transaction PartiallySignedTransaction psbtx; @@ -4587,11 +4530,12 @@ static RPCHelpMan walletprocesspsbt() // Fill transaction with our data and also sign bool sign = request.params[1].isNull() ? true : request.params[1].get_bool(); bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool(); + bool finalize = request.params[4].isNull() ? true : request.params[4].get_bool(); bool complete = true; if (sign) EnsureWalletIsUnlocked(*pwallet); - const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs)}; + const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs, nullptr, finalize)}; if (err != TransactionError::OK) { throw JSONRPCTransactionError(err); } @@ -4860,6 +4804,7 @@ RPCHelpMan removeprunedfunds(); RPCHelpMan importmulti(); RPCHelpMan importdescriptors(); RPCHelpMan listdescriptors(); +RPCHelpMan signmessage(); Span<const CRPCCommand> GetWalletRPCCommands() { diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index 40eb49cf87..fda685e9ee 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -21,6 +21,8 @@ class CTransaction; struct PartiallySignedTransaction; struct WalletContext; +extern const std::string HELP_REQUIRING_PASSPHRASE; + Span<const CRPCCommand> GetWalletRPCCommands(); /** diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 0b4632bd99..a82eaa4879 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -610,7 +610,7 @@ SigningResult LegacyScriptPubKeyMan::SignMessage(const std::string& message, con return SigningResult::SIGNING_FAILED; } -TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const +TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const { if (n_signed) { *n_signed = 0; @@ -639,7 +639,7 @@ TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psb } SignatureData sigdata; input.FillSignatureData(sigdata); - SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type); + SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize); bool signed_one = PSBTInputSigned(input); if (n_signed && (signed_one || !sign)) { @@ -2074,7 +2074,7 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, return SigningResult::OK; } -TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const +TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const { if (n_signed) { *n_signed = 0; @@ -2124,7 +2124,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& } } - SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, &txdata, sighash_type); + SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize); bool signed_one = PSBTInputSigned(input); if (n_signed && (signed_one || !sign)) { diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 2d447f1d67..9d2304a542 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -224,7 +224,7 @@ public: /** Sign a message with the given script */ virtual SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { return SigningResult::SIGNING_FAILED; }; /** Adds script and derivation path information to a PSBT, and optionally signs it. */ - virtual TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const { return TransactionError::INVALID_PSBT; } + virtual TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const { return TransactionError::INVALID_PSBT; } virtual uint256 GetID() const { return uint256(); } @@ -388,7 +388,7 @@ public: bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override; SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override; - TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override; + TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; uint256 GetID() const override; @@ -593,7 +593,7 @@ public: bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override; SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override; - TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override; + TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; uint256 GetID() const override; diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 8f985f31ee..0acd8a811f 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -133,7 +133,7 @@ inline std::vector<OutputGroup>& KnapsackGroupOutputs(const std::vector<COutput> /* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0), /* tx_noinputs_size= */ 0, /* avoid_partial= */ false); static std::vector<OutputGroup> static_groups; - static_groups = GroupOutputs(wallet, coins, coin_selection_params, filter, /* positive_only */false); + static_groups = GroupOutputs(wallet, coins, coin_selection_params, filter, /*positive_only=*/false); return static_groups; } @@ -733,7 +733,7 @@ BOOST_AUTO_TEST_CASE(waste_test) add_coin(1 * COIN, 1, selection, fee, fee); add_coin(2 * COIN, 2, selection, fee, fee); const CAmount exact_target{in_amt - fee * 2}; - BOOST_CHECK_EQUAL(0, GetSelectionWaste(selection, /* change_cost */ 0, exact_target)); + BOOST_CHECK_EQUAL(0, GetSelectionWaste(selection, /*change_cost=*/0, exact_target)); selection.clear(); // No Waste when (fee - long_term_fee) == (-cost_of_change), and no excess diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2382ac268d..e4c3822305 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1849,7 +1849,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, return false; } -TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed) const +TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed, bool finalize) const { if (n_signed) { *n_signed = 0; @@ -1881,7 +1881,7 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp // Fill in information from ScriptPubKeyMans for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) { int n_signed_this_spkm = 0; - TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm); + TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize); if (res != TransactionError::OK) { return res; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 3390d632e7..e294358609 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -555,6 +555,8 @@ public: * @param[in] sighash_type the sighash type to use when signing (if PSBT does not specify) * @param[in] sign whether to sign or not * @param[in] bip32derivs whether to fill in bip32 derivation information if available + * @param[out] n_signed the number of inputs signed by this wallet + * @param[in] finalize whether to create the final scriptSig or scriptWitness if possible * return error */ TransactionError FillPSBT(PartiallySignedTransaction& psbtx, @@ -562,7 +564,8 @@ public: int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = true, - size_t* n_signed = nullptr) const; + size_t* n_signed = nullptr, + bool finalize = true) const; /** * Submit the transaction to the node's mempool and then relay to peers. diff --git a/test/functional/feature_anchors.py b/test/functional/feature_anchors.py index 01b6c5f9eb..713c0826d3 100755 --- a/test/functional/feature_anchors.py +++ b/test/functional/feature_anchors.py @@ -8,18 +8,12 @@ import os from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import check_node_connections INBOUND_CONNECTIONS = 5 BLOCK_RELAY_CONNECTIONS = 2 -def check_node_connections(*, node, num_in, num_out): - info = node.getnetworkinfo() - assert_equal(info["connections_in"], num_in) - assert_equal(info["connections_out"], num_out) - - class AnchorsTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py new file mode 100755 index 0000000000..cffbd40271 --- /dev/null +++ b/test/functional/feature_init.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +# Copyright (c) 2021 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Stress tests related to node initialization.""" +import random +import time +import os +from pathlib import Path + +from test_framework.test_framework import BitcoinTestFramework, SkipTest +from test_framework.test_node import ErrorMatch +from test_framework.util import assert_equal + + +class InitStressTest(BitcoinTestFramework): + """ + Ensure that initialization can be interrupted at a number of points and not impair + subsequent starts. + """ + + def set_test_params(self): + self.setup_clean_chain = False + self.num_nodes = 1 + + def run_test(self): + """ + - test terminating initialization after seeing a certain log line. + - test terminating init after seeing a random number of log lines. + - test removing certain essential files to test startup error paths. + """ + # TODO: skip Windows for now since it isn't clear how to SIGTERM. + # + # Windows doesn't support `process.terminate()`. + # and other approaches (like below) don't work: + # + # os.kill(node.process.pid, signal.CTRL_C_EVENT) + if os.name == 'nt': + raise SkipTest("can't SIGTERM on Windows") + + self.stop_node(0) + node = self.nodes[0] + + def sigterm_node(): + node.process.terminate() + node.process.wait() + node.debug_log_path.unlink() + node.debug_log_path.touch() + + def check_clean_start(): + """Ensure that node restarts successfully after various interrupts.""" + # TODO: add -txindex=1 to fully test index initiatlization. + # See https://github.com/bitcoin/bitcoin/pull/23289#discussion_r735159180 for + # a discussion of the related bug. + node.start() + node.wait_for_rpc_connection() + assert_equal(200, node.getblockcount()) + + lines_to_terminate_after = [ + 'scheduler thread start', + 'Loading P2P addresses', + 'Loading banlist', + 'Loading block index', + 'Switching active chainstate', + 'Loaded best chain:', + 'init message: Verifying blocks', + 'loadblk thread start', + # TODO: reenable - see above TODO + # 'txindex thread start', + 'net thread start', + 'addcon thread start', + 'msghand thread start', + ] + if self.is_wallet_compiled(): + lines_to_terminate_after.append('Verifying wallet') + + for terminate_line in lines_to_terminate_after: + self.log.info(f"Starting node and will exit after line '{terminate_line}'") + node.start( + # TODO: add -txindex=1 to fully test index initiatlization. + # extra_args=['-txindex=1'], + ) + logfile = open(node.debug_log_path, 'r', encoding='utf8') + + MAX_SECS_TO_WAIT = 30 + start = time.time() + num_lines = 0 + + while True: + line = logfile.readline() + if line: + num_lines += 1 + + if line and terminate_line.lower() in line.lower(): + self.log.debug(f"Terminating node after {num_lines} log lines seen") + sigterm_node() + break + + if (time.time() - start) > MAX_SECS_TO_WAIT: + raise AssertionError( + f"missed line {terminate_line}; terminating now after {num_lines} lines") + + if node.process.poll() is not None: + raise AssertionError(f"node failed to start (line: '{terminate_line}')") + + check_clean_start() + num_total_logs = len(node.debug_log_path.read_text().splitlines()) + self.stop_node(0) + + self.log.info( + f"Terminate at some random point in the init process (max logs: {num_total_logs})") + + for _ in range(40): + terminate_after = random.randint(1, num_total_logs) + self.log.debug(f"Starting node and will exit after {terminate_after} lines") + node.start( + # TODO: add -txindex=1 to fully test index initiatlization. + # extra_args=['-txindex=1'], + ) + logfile = open(node.debug_log_path, 'r', encoding='utf8') + + MAX_SECS_TO_WAIT = 10 + start = time.time() + num_lines = 0 + + while True: + line = logfile.readline() + if line: + num_lines += 1 + + if num_lines >= terminate_after or (time.time() - start) > MAX_SECS_TO_WAIT: + self.log.debug(f"Terminating node after {num_lines} log lines seen") + sigterm_node() + break + + if node.process.poll() is not None: + raise AssertionError("node failed to start") + + check_clean_start() + self.stop_node(0) + + self.log.info("Test startup errors after removing certain essential files") + + files_to_disturb = { + 'blocks/index/*.ldb': 'Error opening block database.', + 'chainstate/*.ldb': 'Error opening block database.', + 'blocks/blk*.dat': 'Error loading block database.', + } + + for file_patt, err_fragment in files_to_disturb.items(): + target_file = list(node.chain_path.glob(file_patt))[0] + + self.log.info(f"Tweaking file to ensure failure {target_file}") + bak_path = str(target_file) + ".bak" + target_file.rename(bak_path) + + # TODO: at some point, we should test perturbing the files instead of removing + # them, e.g. + # + # contents = target_file.read_bytes() + # tweaked_contents = bytearray(contents) + # tweaked_contents[50:250] = b'1' * 200 + # target_file.write_bytes(bytes(tweaked_contents)) + # + # At the moment I can't get this to work (bitcoind loads successfully?) so + # investigate doing this later. + + node.assert_start_raises_init_error( + # TODO: add -txindex=1 to fully test index initiatlization. + # extra_args=['-txindex=1'], + expected_msg=err_fragment, + match=ErrorMatch.PARTIAL_REGEX, + ) + + self.log.info(f"Restoring file from {bak_path} and restarting") + Path(bak_path).rename(target_file) + check_clean_start() + self.stop_node(0) + + +if __name__ == '__main__': + InitStressTest().main() diff --git a/test/functional/p2p_add_connections.py b/test/functional/p2p_add_connections.py index a04ba5db2d..b86502dc85 100755 --- a/test/functional/p2p_add_connections.py +++ b/test/functional/p2p_add_connections.py @@ -6,13 +6,7 @@ from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal - - -def check_node_connections(*, node, num_in, num_out): - info = node.getnetworkinfo() - assert_equal(info["connections_in"], num_in) - assert_equal(info["connections_out"], num_out) +from test_framework.util import check_node_connections class P2PAddConnections(BitcoinTestFramework): diff --git a/test/functional/p2p_ibd_txrelay.py b/test/functional/p2p_ibd_txrelay.py index 9044ed5cdb..65a94ad31c 100755 --- a/test/functional/p2p_ibd_txrelay.py +++ b/test/functional/p2p_ibd_txrelay.py @@ -2,11 +2,30 @@ # Copyright (c) 2020-2021 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test fee filters during and after IBD.""" +"""Test transaction relay behavior during IBD: +- Set fee filters to MAX_MONEY +- Don't request transactions +- Ignore all transaction messages +""" from decimal import Decimal +import time -from test_framework.messages import COIN +from test_framework.messages import ( + CInv, + COIN, + CTransaction, + from_hex, + msg_inv, + msg_tx, + MSG_WTX, +) +from test_framework.p2p import ( + NONPREF_PEER_TX_DELAY, + P2PDataStore, + P2PInterface, + p2p_lock +) from test_framework.test_framework import BitcoinTestFramework MAX_FEE_FILTER = Decimal(9170997) / COIN @@ -28,6 +47,31 @@ class P2PIBDTxRelayTest(BitcoinTestFramework): assert node.getblockchaininfo()['initialblockdownload'] self.wait_until(lambda: all(peer['minfeefilter'] == MAX_FEE_FILTER for peer in node.getpeerinfo())) + self.log.info("Check that nodes don't send getdatas for transactions while still in IBD") + peer_inver = self.nodes[0].add_p2p_connection(P2PDataStore()) + txid = 0xdeadbeef + peer_inver.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=txid)])) + # The node should not send a getdata, but if it did, it would first delay 2 seconds + self.nodes[0].setmocktime(int(time.time() + NONPREF_PEER_TX_DELAY)) + peer_inver.sync_send_with_ping() + with p2p_lock: + assert txid not in peer_inver.getdata_requests + self.nodes[0].disconnect_p2ps() + + self.log.info("Check that nodes don't process unsolicited transactions while still in IBD") + # A transaction hex pulled from tx_valid.json. There are no valid transactions since no UTXOs + # exist yet, but it should be a well-formed transaction. + rawhex = "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff473" + \ + "04402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e168" + \ + "1a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696a" + \ + "d990364e555c271ad504b88ac00000000" + assert self.nodes[1].decoderawtransaction(rawhex) # returns a dict, should not throw + tx = from_hex(CTransaction(), rawhex) + peer_txer = self.nodes[0].add_p2p_connection(P2PInterface()) + with self.nodes[0].assert_debug_log(expected_msgs=["received: tx"], unexpected_msgs=["was not accepted"]): + peer_txer.send_and_ping(msg_tx(tx)) + self.nodes[0].disconnect_p2ps() + # Come out of IBD by generating a block self.generate(self.nodes[0], 1) @@ -36,6 +80,10 @@ class P2PIBDTxRelayTest(BitcoinTestFramework): assert not node.getblockchaininfo()['initialblockdownload'] self.wait_until(lambda: all(peer['minfeefilter'] == NORMAL_FEE_FILTER for peer in node.getpeerinfo())) + self.log.info("Check that nodes process the same transaction, even when unsolicited, when no longer in IBD") + peer_txer = self.nodes[0].add_p2p_connection(P2PInterface()) + with self.nodes[0].assert_debug_log(expected_msgs=["was not accepted"]): + peer_txer.send_and_ping(msg_tx(tx)) if __name__ == '__main__': P2PIBDTxRelayTest().main() diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 4ac4f27d8a..a8034849cc 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -120,7 +120,9 @@ class PSBTTest(BitcoinTestFramework): self.nodes[0].walletpassphrase(passphrase="password", timeout=1000000) # Sign the transaction and send - signed_tx = self.nodes[0].walletprocesspsbt(psbtx)['psbt'] + signed_tx = self.nodes[0].walletprocesspsbt(psbt=psbtx, finalize=False)['psbt'] + finalized_tx = self.nodes[0].walletprocesspsbt(psbt=psbtx, finalize=True)['psbt'] + assert signed_tx != finalized_tx final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex'] self.nodes[0].sendrawtransaction(final_tx) diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py index c99868de72..251d3d5eae 100755 --- a/test/functional/test_framework/p2p.py +++ b/test/functional/test_framework/p2p.py @@ -89,6 +89,8 @@ P2P_SERVICES = NODE_NETWORK | NODE_WITNESS P2P_SUBVERSION = "/python-p2p-tester:0.0.3/" # Value for relay that this test framework sends in its `version` message P2P_VERSION_RELAY = 1 +# Delay after receiving a tx inv before requesting transactions from non-preferred peers, in seconds +NONPREF_PEER_TX_DELAY = 2 MESSAGEMAP = { b"addr": msg_addr, diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 269f2442a9..b3279666b2 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -20,6 +20,7 @@ import urllib.parse import collections import shlex import sys +from pathlib import Path from .authproxy import JSONRPCException from .descriptors import descsum_create @@ -380,13 +381,20 @@ class TestNode(): def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): wait_until_helper(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor) + @property + def chain_path(self) -> Path: + return Path(self.datadir) / self.chain + + @property + def debug_log_path(self) -> Path: + return self.chain_path / 'debug.log' + @contextlib.contextmanager def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2): if unexpected_msgs is None: unexpected_msgs = [] time_end = time.time() + timeout * self.timeout_factor - debug_log = os.path.join(self.datadir, self.chain, 'debug.log') - with open(debug_log, encoding='utf-8') as dl: + with open(self.debug_log_path, encoding='utf-8') as dl: dl.seek(0, 2) prev_size = dl.tell() @@ -394,7 +402,7 @@ class TestNode(): while True: found = True - with open(debug_log, encoding='utf-8') as dl: + with open(self.debug_log_path, encoding='utf-8') as dl: dl.seek(prev_size) log = dl.read() print_log = " - " + "\n - ".join(log.splitlines()) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 57ef6d99d5..c3a9029d55 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -269,6 +269,7 @@ def wait_until_helper(predicate, *, attempts=float('inf'), timeout=float('inf'), raise AssertionError("Predicate {} not true after {} seconds".format(predicate_source, timeout)) raise RuntimeError('Unreachable') + def sha256sum_file(filename): h = hashlib.sha256() with open(filename, 'rb') as f: @@ -445,6 +446,12 @@ def set_node_times(nodes, t): node.setmocktime(t) +def check_node_connections(*, node, num_in, num_out): + info = node.getnetworkinfo() + assert_equal(info["connections_in"], num_in) + assert_equal(info["connections_out"], num_out) + + # Transaction/Block functions ############################# diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index b9b4edf0ba..35cab8f6ec 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -278,6 +278,7 @@ BASE_SCRIPTS = [ 'wallet_taproot.py', 'p2p_fingerprint.py', 'feature_uacomment.py', + 'feature_init.py', 'wallet_coinbase_category.py --legacy-wallet', 'wallet_coinbase_category.py --descriptors', 'feature_filelock.py', diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh index 391f4825e8..5fa104fce6 100755 --- a/test/lint/lint-shell.sh +++ b/test/lint/lint-shell.sh @@ -20,12 +20,13 @@ if ! command -v shellcheck > /dev/null; then exit $EXIT_CODE fi -SHELLCHECK_CMD=(shellcheck --external-sources --check-sourced) +SHELLCHECK_CMD=(shellcheck --external-sources --check-sourced --source-path=SCRIPTDIR) EXCLUDE="--exclude=$(IFS=','; echo "${disabled[*]}")" # Check shellcheck directive used for sourced files mapfile -t SOURCED_FILES < <(git ls-files | xargs gawk '/^# shellcheck shell=/ {print FILENAME} {nextfile}') +mapfile -t GUIX_FILES < <(git ls-files contrib/guix contrib/shell | xargs gawk '/^#!\/usr\/bin\/env bash/ {print FILENAME} {nextfile}') mapfile -t FILES < <(git ls-files -- '*.sh' | grep -vE 'src/(leveldb|secp256k1|minisketch|univalue)/') -if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE" "${SOURCED_FILES[@]}" "${FILES[@]}"; then +if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE" "${SOURCED_FILES[@]}" "${GUIX_FILES[@]}" "${FILES[@]}"; then EXIT_CODE=1 fi |