diff --git a/ci/dash/lint-tidy.sh b/ci/dash/lint-tidy.sh index 0d2aa9383428..eafe932517e6 100755 --- a/ci/dash/lint-tidy.sh +++ b/ci/dash/lint-tidy.sh @@ -115,6 +115,7 @@ iwyu_tool.py \ "src/rpc/signmessage.cpp" \ "src/test/fuzz/string.cpp" \ "src/test/fuzz/txorphan.cpp" \ + "src/test/fuzz/util/" \ "src/util/bip32.cpp" \ "src/util/bytevectorhash.cpp" \ "src/util/check.cpp" \ diff --git a/contrib/README.md b/contrib/README.md index 221f57b26e56..21a0e0596cfe 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -38,3 +38,9 @@ Utilities to generate test vectors for the data-driven Dash tests. ### [Verify-Binaries](/contrib/verify-binaries) ### This script attempts to download and verify the signature file SHA256SUMS.asc from bitcoin.org. + +Command Line Tools +--------------------- + +### [Completions](/contrib/completions) ### +Shell completions for bash and fish. diff --git a/contrib/dash-cli.bash b/contrib/completions/bash/dash-cli.bash-completion similarity index 100% rename from contrib/dash-cli.bash rename to contrib/completions/bash/dash-cli.bash-completion diff --git a/contrib/dash-tx.bash b/contrib/completions/bash/dash-tx.bash-completion similarity index 100% rename from contrib/dash-tx.bash rename to contrib/completions/bash/dash-tx.bash-completion diff --git a/contrib/dashd.bash b/contrib/completions/bash/dashd.bash-completion similarity index 100% rename from contrib/dashd.bash rename to contrib/completions/bash/dashd.bash-completion diff --git a/contrib/completions/fish/dash-cli.fish b/contrib/completions/fish/dash-cli.fish new file mode 100644 index 000000000000..9a059d5f4ed4 --- /dev/null +++ b/contrib/completions/fish/dash-cli.fish @@ -0,0 +1,99 @@ +# Disable files from being included in completions by default +complete --command dash-cli --no-files + +function __fish_dash_cli_get_commands_helper + set --local cmd (commandline -oc) + + # Don't return commands if '-help or -?' in commandline + if string match --quiet --regex -- '^-help$|^-\?$' $cmd + return + end + + # Strip help cmd from token to avoid duplication errors + set --local cmd (string match --invert --regex -- '^help$' $cmd) + # Strip -stdin* options to avoid waiting for input while we fetch completions + # TODO: this appears to be broken when run as tab completion (requires ctrl+c to exit) + set --local cmd (string match --invert --regex -- '^-stdin.*$' $cmd) + + # Match, format and return commands + for command in ($cmd help 2>&1 | string match --invert -r '^\=\=.*' | string match --invert -r '^\\s*$') + echo $command + end +end + +function __fish_dash_cli_get_commands + argparse 'nohelp' 'commandsonly' -- $argv + set --local commands + + # Exclude description, exclude help + if set -q _flag_nohelp; and set -q _flag_commandsonly + set --append commands (__fish_dash_cli_get_commands_helper | string replace -r ' .*$' '' | string match --invert -r 'help') + # Include description, exclude help + else if set -q _flag_nohelp + set --append commands (__fish_dash_cli_get_commands_helper | string replace ' ' \t | string match --invert -r 'help') + # Exclude description, include help + else if set -q _flag_commandsonly + set --append commands (__fish_dash_cli_get_commands_helper | string replace -r ' .*$' '') + # Include description, include help + else + set --append commands (__fish_dash_cli_get_commands_helper | string replace ' ' \t) + end + + if string match -q -r '^.*error.*$' $commands[1] + # RPC offline or RPC wallet not loaded + return + else + for command in $commands + echo $command + end + end +end + + +function __fish_dash_cli_get_options + argparse 'nofiles' -- $argv + set --local cmd (commandline -oc) + # Don't return options if '-help or -?' in commandline + if string match --quiet --regex -- '^-help$|-\?$' $cmd + return + end + set --local options + + if set -q _flag_nofiles + set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$') + else + set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$') + end + + for option in $options + echo $option + end +end + +# Add options with file completion +# Don't offer after a command is given +complete \ + --command dash-cli \ + --no-files \ + --condition "not __fish_seen_subcommand_from (__fish_dash_cli_get_commands --commandsonly)" \ + --arguments "(__fish_dash_cli_get_options)" +# Enable file completions only if the commandline now contains a `*.=` style option +complete --command dash-cli \ + --condition 'string match --regex -- ".*=" (commandline -pt)' \ + --force-files + +# Add options without file completion +# Don't offer after a command is given +complete \ + --command dash-cli \ + --no-files \ + --condition "not __fish_seen_subcommand_from (__fish_dash_cli_get_commands --commandsonly)" \ + --arguments "(__fish_dash_cli_get_options --nofiles)" + +# Add commands +# Permit command completions after `dash-cli help` but not after other commands +complete \ + --command dash-cli \ + --no-files \ + --condition "not __fish_seen_subcommand_from (__fish_dash_cli_get_commands --commandsonly --nohelp)" \ + --arguments "(__fish_dash_cli_get_commands)" diff --git a/contrib/completions/fish/dash-qt.fish b/contrib/completions/fish/dash-qt.fish new file mode 100644 index 000000000000..1a6e95114e22 --- /dev/null +++ b/contrib/completions/fish/dash-qt.fish @@ -0,0 +1,35 @@ +# Disable files from being included in completions by default +complete --command dash-qt --no-files + +# Extract options +function __fish_dashqt_get_options + argparse 'nofiles' -- $argv + set --local cmd (commandline -opc)[1] + set --local options + + if set -q _flag_nofiles + set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$') + else + set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$') + end + + for option in $options + echo $option + end +end + + +# Add options with file completion +complete \ + --command dash-qt \ + --arguments "(__fish_dashqt_get_options)" +# Enable file completions only if the commandline now contains a `*.=` style option +complete -c dash-qt \ + --condition 'string match --regex -- ".*=" (commandline -pt)' \ + --force-files + +# Add options without file completion +complete \ + --command dash-qt \ + --arguments "(__fish_dashqt_get_options --nofiles)" + diff --git a/contrib/completions/fish/dash-tx.fish b/contrib/completions/fish/dash-tx.fish new file mode 100644 index 000000000000..50897166da4d --- /dev/null +++ b/contrib/completions/fish/dash-tx.fish @@ -0,0 +1,65 @@ +# Disable files from being included in completions by default +complete --command dash-tx --no-files + +# Modified version of __fish_seen_subcommand_from +# Uses regex to detect cmd= syntax +function __fish_dash_seen_cmd + set -l cmd (commandline -oc) + set -e cmd[1] + for i in $cmd + for j in $argv + if string match --quiet --regex -- "^$j.*" $i + return 0 + end + end + end + return 1 +end + +# Extract options +function __fish_dash_tx_get_options + set --local cmd (commandline -oc)[1] + if string match --quiet --regex -- '^-help$|-\?$' $cmd + return + end + + for option in ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=') + echo $option + end +end + +# Extract commands +function __fish_dash_tx_get_commands + argparse 'commandsonly' -- $argv + set --local cmd (commandline -oc)[1] + set --local commands + + if set -q _flag_commandsonly + set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '' | string replace -r '=.*' '') + else + set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '') + end + + for command in $commands + echo $command + end +end + +# Add options +complete \ + --command dash-tx \ + --condition "not __fish_dash_seen_cmd (__fish_bitcoin_tx_get_commands --commandsonly)" \ + --arguments "(__fish_dash_tx_get_options)" \ + --no-files + +# Add commands +complete \ + --command dash-tx \ + --arguments "(__fish_dash_tx_get_commands)" \ + --no-files + +# Add file completions for load and set commands +complete \ + --command dash-tx \ + --condition 'string match --regex -- "(load|set)=" (commandline -pt)' \ + --force-files diff --git a/contrib/completions/fish/dash-util.fish b/contrib/completions/fish/dash-util.fish new file mode 100644 index 000000000000..dde844efc6f6 --- /dev/null +++ b/contrib/completions/fish/dash-util.fish @@ -0,0 +1,38 @@ +# Disable files from being included in completions by default +complete --command dash-util --no-files + +# Extract options +function __fish_dash_util_get_options + set --local cmd (commandline -opc)[1] + set --local options + + set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=') + + for option in $options + echo $option + end +end + +# Extract commands +function __fish_dash_util_get_commands + set --local cmd (commandline -opc)[1] + set --local commands + + set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '') + for command in $commands + echo $command + end +end + +# Add options +complete \ + --command dash-util \ + --condition "not __fish_seen_subcommand_from (__fish_dash_util_get_commands)" \ + --arguments "(__fish_dash_util_get_options)" + +# Add commands +complete \ + --command dash-util \ + --condition "not __fish_seen_subcommand_from (__fish_dash_util_get_commands)" \ + --arguments "(__fish_dash_util_get_commands)" + diff --git a/contrib/completions/fish/dash-wallet.fish b/contrib/completions/fish/dash-wallet.fish new file mode 100644 index 000000000000..4720f1374717 --- /dev/null +++ b/contrib/completions/fish/dash-wallet.fish @@ -0,0 +1,35 @@ +# Disable files from being included in completions by default +complete --command dash-wallet --no-files + +# Extract options +function __fish_dash_wallet_get_options + set --local cmd (commandline -opc)[1] + for option in ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=') + echo $option + end +end + +# Extract commands +function __fish_dash_wallet_get_commands + set --local cmd (commandline -opc)[1] + for command in ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '') + echo $command + end +end + +# Add options +complete \ + --command dash-wallet \ + --condition "not __fish_seen_subcommand_from (__fish_dash_wallet_get_commands)" \ + --arguments "(__fish_dash_wallet_get_options)" + +# Add commands +complete \ + --command dash-wallet \ + --condition "not __fish_seen_subcommand_from (__fish_dash_wallet_get_commands)" \ + --arguments "(__fish_dash_wallet_get_commands)" + +# Add file completions for load and set commands +complete --command dash-wallet \ + --condition "string match -r -- '(dumpfile|datadir)*=' (commandline -pt)" \ + --force-files diff --git a/contrib/completions/fish/dashd.fish b/contrib/completions/fish/dashd.fish new file mode 100644 index 000000000000..d9e9f4a79710 --- /dev/null +++ b/contrib/completions/fish/dashd.fish @@ -0,0 +1,35 @@ +# Disable files from being included in completions by default +complete --command dashd --no-files + +# Extract options +function __fish_dashd_get_options + argparse 'nofiles' -- $argv + set --local cmd (commandline -opc)[1] + set --local options + + if set -q _flag_nofiles + set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$') + else + set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$') + end + + for option in $options + echo $option + end +end + + +# Add options with file completion +complete \ + --command dashd \ + --arguments "(__fish_dashd_get_options)" +# Enable file completions only if the commandline now contains a `*.=` style option +complete --command dashd \ + --condition 'string match --regex -- ".*=" (commandline -pt)' \ + --force-files + +# Add options without file completion +complete \ + --command dashd \ + --arguments "(__fish_dashd_get_options --nofiles)" + diff --git a/doc/release-notes-25934.md b/doc/release-notes-25934.md new file mode 100644 index 000000000000..b4f1ae0d3cf7 --- /dev/null +++ b/doc/release-notes-25934.md @@ -0,0 +1,8 @@ +Low-level changes +================= + +RPC +--- + +- RPC `listsinceblock` now accepts an optional `label` argument + to fetch incoming transactions having the specified label. (#25934) \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 22f28dbbd102..c5b08a2e17f7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -290,6 +290,7 @@ BITCOIN_CORE_H = \ kernel/checks.h \ kernel/coinstats.h \ kernel/context.h \ + kernel/mempool_entry.h \ kernel/mempool_limits.h \ kernel/mempool_options.h \ kernel/mempool_persist.h \ @@ -969,6 +970,7 @@ libbitcoin_common_a_SOURCES = \ coins.cpp \ common/bloom.cpp \ common/init.cpp \ + common/interfaces.cpp \ common/run_command.cpp \ compressor.cpp \ core_read.cpp \ @@ -1014,7 +1016,7 @@ endif # # util # -libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) +libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ bls/bls_batchverifier.h \ @@ -1026,9 +1028,6 @@ libbitcoin_util_a_SOURCES = \ clientversion.cpp \ coinjoin/common.cpp \ coinjoin/options.cpp \ - interfaces/echo.cpp \ - interfaces/handler.cpp \ - interfaces/init.cpp \ logging.cpp \ messagesigner.cpp \ random.cpp \ diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index a1fea6f7419f..988ac847fa5e 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp index 0cf4e83ef8ce..1ea232fec984 100644 --- a/src/bench/mempool_stress.cpp +++ b/src/bench/mempool_stress.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include diff --git a/src/bench/peer_eviction.cpp b/src/bench/peer_eviction.cpp index c3e3670de735..d83342be93bc 100644 --- a/src/bench/peer_eviction.cpp +++ b/src/bench/peer_eviction.cpp @@ -40,7 +40,7 @@ static void EvictionProtection0Networks250Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 250 /* num_candidates */, + /*num_candidates=*/250, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_network = NET_IPV4; @@ -51,7 +51,7 @@ static void EvictionProtection1Networks250Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 250 /* num_candidates */, + /*num_candidates=*/250, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = false; @@ -67,7 +67,7 @@ static void EvictionProtection2Networks250Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 250 /* num_candidates */, + /*num_candidates=*/250, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = false; @@ -85,7 +85,7 @@ static void EvictionProtection3Networks050Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 50 /* num_candidates */, + /*num_candidates=*/50, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = (c.id == 28 || c.id == 47); // 2 localhost @@ -103,7 +103,7 @@ static void EvictionProtection3Networks100Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 100 /* num_candidates */, + /*num_candidates=*/100, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = (c.id >= 55 && c.id < 60); // 5 localhost @@ -121,7 +121,7 @@ static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 250 /* num_candidates */, + /*num_candidates=*/250, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = (c.id >= 140 && c.id < 160); // 20 localhost diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp index dbfd187c07b0..7b8a80f6202d 100644 --- a/src/bench/rpc_mempool.cpp +++ b/src/bench/rpc_mempool.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/src/common/interfaces.cpp b/src/common/interfaces.cpp new file mode 100644 index 000000000000..b9b4f5dded3a --- /dev/null +++ b/src/common/interfaces.cpp @@ -0,0 +1,53 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +#include +#include +#include + +namespace common { +namespace { +class CleanupHandler : public interfaces::Handler +{ +public: + explicit CleanupHandler(std::function cleanup) : m_cleanup(std::move(cleanup)) {} + ~CleanupHandler() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; } + void disconnect() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; } + std::function m_cleanup; +}; + +class SignalHandler : public interfaces::Handler +{ +public: + explicit SignalHandler(boost::signals2::connection connection) : m_connection(std::move(connection)) {} + + void disconnect() override { m_connection.disconnect(); } + + boost::signals2::scoped_connection m_connection; +}; + +class EchoImpl : public interfaces::Echo +{ +public: + std::string echo(const std::string& echo) override { return echo; } +}; +} // namespace +} // namespace common + +namespace interfaces { +std::unique_ptr MakeCleanupHandler(std::function cleanup) +{ + return std::make_unique(std::move(cleanup)); +} + +std::unique_ptr MakeSignalHandler(boost::signals2::connection connection) +{ + return std::make_unique(std::move(connection)); +} + +std::unique_ptr MakeEcho() { return std::make_unique(); } +} // namespace interfaces diff --git a/src/init.cpp b/src/init.cpp index 46bfb1156341..5fb51e93a17d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2261,7 +2261,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) { - g_coin_stats_index = std::make_unique(interfaces::MakeChain(node), /* cache size */ 0, false, fReindex); + g_coin_stats_index = std::make_unique(interfaces::MakeChain(node), /*cache_size=*/0, false, fReindex); if (!g_coin_stats_index->Start()) { return false; } diff --git a/src/interfaces/echo.cpp b/src/interfaces/echo.cpp deleted file mode 100644 index 9bbb42217b02..000000000000 --- a/src/interfaces/echo.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2021 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include - -namespace interfaces { -namespace { -class EchoImpl : public Echo -{ -public: - std::string echo(const std::string& echo) override { return echo; } -}; -} // namespace -std::unique_ptr MakeEcho() { return std::make_unique(); } -} // namespace interfaces diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp deleted file mode 100644 index 756a2b9fb213..000000000000 --- a/src/interfaces/handler.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2018-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 - -#include - -#include -#include -#include - -namespace interfaces { -namespace { - -class HandlerImpl : public Handler -{ -public: - explicit HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {} - - void disconnect() override { m_connection.disconnect(); } - - boost::signals2::scoped_connection m_connection; -}; - -class CleanupHandler : public Handler -{ -public: - explicit CleanupHandler(std::function cleanup) : m_cleanup(std::move(cleanup)) {} - ~CleanupHandler() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; } - void disconnect() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; } - std::function m_cleanup; -}; - -} // namespace - -std::unique_ptr MakeHandler(boost::signals2::connection connection) -{ - return std::make_unique(std::move(connection)); -} - -std::unique_ptr MakeHandler(std::function cleanup) -{ - return std::make_unique(std::move(cleanup)); -} - -} // namespace interfaces diff --git a/src/interfaces/handler.h b/src/interfaces/handler.h index 11baf9dd65d1..f46f5e04a59e 100644 --- a/src/interfaces/handler.h +++ b/src/interfaces/handler.h @@ -29,10 +29,10 @@ class Handler }; //! Return handler wrapping a boost signal connection. -std::unique_ptr MakeHandler(boost::signals2::connection connection); +std::unique_ptr MakeSignalHandler(boost::signals2::connection connection); //! Return handler wrapping a cleanup function. -std::unique_ptr MakeHandler(std::function cleanup); +std::unique_ptr MakeCleanupHandler(std::function cleanup); } // namespace interfaces diff --git a/src/interfaces/init.cpp b/src/interfaces/init.cpp deleted file mode 100644 index 797049d2438d..000000000000 --- a/src/interfaces/init.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2021 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include - -namespace interfaces { -std::unique_ptr Init::makeNode() { return {}; } -std::unique_ptr Init::makeChain() { return {}; } -std::unique_ptr Init::makeCoinJoinLoader() { return {}; } -std::unique_ptr Init::makeWalletLoader(Chain& chain, CoinJoin::Loader& coinjoin_loader) { return {}; } -std::unique_ptr Init::makeEcho() { return {}; } -Ipc* Init::ipc() { return nullptr; } -} // namespace interfaces diff --git a/src/interfaces/init.h b/src/interfaces/init.h index 2679e33d5cb3..f2279517339a 100644 --- a/src/interfaces/init.h +++ b/src/interfaces/init.h @@ -5,6 +5,12 @@ #ifndef BITCOIN_INTERFACES_INIT_H #define BITCOIN_INTERFACES_INIT_H +#include +#include +#include +#include +#include + #include namespace node { @@ -12,14 +18,7 @@ struct NodeContext; } // namespace node namespace interfaces { -class Chain; -class Echo; class Ipc; -class Node; -class WalletLoader; -namespace CoinJoin { -class Loader; -} // namespace CoinJoin //! Initial interface created when a process is first started, and used to give //! and get access to other interfaces (Node, Chain, Wallet, etc). @@ -32,12 +31,12 @@ class Init { public: virtual ~Init() = default; - virtual std::unique_ptr makeNode(); - virtual std::unique_ptr makeChain(); - virtual std::unique_ptr makeCoinJoinLoader(); - virtual std::unique_ptr makeWalletLoader(interfaces::Chain&, CoinJoin::Loader&); - virtual std::unique_ptr makeEcho(); - virtual Ipc* ipc(); + virtual std::unique_ptr makeNode() { return nullptr; } + virtual std::unique_ptr makeChain() { return nullptr; } + virtual std::unique_ptr makeCoinJoinLoader() { return nullptr; } + virtual std::unique_ptr makeWalletLoader(interfaces::Chain&, CoinJoin::Loader&) { return nullptr; } + virtual std::unique_ptr makeEcho() { return nullptr; } + virtual Ipc* ipc() { return nullptr; } }; //! Return implementation of Init interface for the node process. If the argv diff --git a/src/kernel/mempool_entry.h b/src/kernel/mempool_entry.h new file mode 100644 index 000000000000..809320150ccc --- /dev/null +++ b/src/kernel/mempool_entry.h @@ -0,0 +1,187 @@ +// Copyright (c) 2009-2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_KERNEL_MEMPOOL_ENTRY_H +#define BITCOIN_KERNEL_MEMPOOL_ENTRY_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +class CBlockIndex; + +struct LockPoints { + // Will be set to the blockchain height and median time past + // values that would be necessary to satisfy all relative locktime + // constraints (BIP68) of this tx given our view of block chain history + int height{0}; + int64_t time{0}; + // As long as the current chain descends from the highest height block + // containing one of the inputs used in the calculation, then the cached + // values are still valid even after a reorg. + CBlockIndex* maxInputBlock{nullptr}; +}; + +struct CompareIteratorByHash { + // SFINAE for T where T is either a pointer type (e.g., a txiter) or a reference_wrapper + // (e.g. a wrapped CTxMemPoolEntry&) + template + bool operator()(const std::reference_wrapper& a, const std::reference_wrapper& b) const + { + return a.get().GetTx().GetHash() < b.get().GetTx().GetHash(); + } + template + bool operator()(const T& a, const T& b) const + { + return a->GetTx().GetHash() < b->GetTx().GetHash(); + } +}; + +/** \class CTxMemPoolEntry + * + * CTxMemPoolEntry stores data about the corresponding transaction, as well + * as data about all in-mempool transactions that depend on the transaction + * ("descendant" transactions). + * + * When a new entry is added to the mempool, we update the descendant state + * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for + * all ancestors of the newly added transaction. + * + */ + +class CTxMemPoolEntry +{ +public: + typedef std::reference_wrapper CTxMemPoolEntryRef; + // two aliases, should the types ever diverge + typedef std::set Parents; + typedef std::set Children; + +private: + CTxMemPoolEntry(const CTxMemPoolEntry&) = default; + struct ExplicitCopyTag { + explicit ExplicitCopyTag() = default; + }; + const CTransactionRef tx; + mutable Parents m_parents; + mutable Children m_children; + const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups + const size_t nTxSize; //!< ... and avoid recomputing tx size + const size_t nUsageSize; //!< ... and total memory usage + const int64_t nTime; //!< Local time when entering the mempool + const unsigned int entryHeight; //!< Chain height when entering the mempool + const bool spendsCoinbase; //!< keep track of transactions that spend a coinbase + const int64_t sigOpCount; //!< Legacy sig ops plus P2SH sig op count + CAmount m_modified_fee; //!< Used for determining the priority of the transaction for mining in a block + LockPoints lockPoints; //!< Track the height and time at which tx was final + + // Information about descendants of this transaction that are in the + // mempool; if we remove this transaction we must remove all of these + // descendants as well. + uint64_t nCountWithDescendants{1}; //!< number of descendant transactions + uint64_t nSizeWithDescendants; //!< ... and size + CAmount nModFeesWithDescendants; //!< ... and total fees (all including us) + + // Analogous statistics for ancestor transactions + uint64_t nCountWithAncestors{1}; + uint64_t nSizeWithAncestors; + CAmount nModFeesWithAncestors; + int64_t nSigOpCountWithAncestors; + +public: + CTxMemPoolEntry(const CTransactionRef& tx, CAmount fee, + int64_t time, unsigned int entry_height, + bool spends_coinbase, + int64_t sigops_count, LockPoints lp) + : tx{tx}, + nFee{fee}, + nTxSize(tx->GetTotalSize()), + nUsageSize{RecursiveDynamicUsage(tx)}, + nTime{time}, + entryHeight{entry_height}, + spendsCoinbase{spends_coinbase}, + sigOpCount{sigops_count}, + m_modified_fee{nFee}, + lockPoints{lp}, + nSizeWithDescendants{GetTxSize()}, + nModFeesWithDescendants{nFee}, + nSizeWithAncestors{GetTxSize()}, + nModFeesWithAncestors{nFee}, + nSigOpCountWithAncestors{sigOpCount} {} + + CTxMemPoolEntry(ExplicitCopyTag, const CTxMemPoolEntry& entry) : CTxMemPoolEntry(entry) {} + CTxMemPoolEntry& operator=(const CTxMemPoolEntry&) = delete; + CTxMemPoolEntry(CTxMemPoolEntry&&) = delete; + CTxMemPoolEntry& operator=(CTxMemPoolEntry&&) = delete; + + static constexpr ExplicitCopyTag ExplicitCopy{}; + const CTransaction& GetTx() const { return *this->tx; } + CTransactionRef GetSharedTx() const { return this->tx; } + const CAmount& GetFee() const { return nFee; } + size_t GetTxSize() const + { + return GetVirtualTransactionSize(nTxSize, sigOpCount, ::nBytesPerSigOp); + } + std::chrono::seconds GetTime() const { return std::chrono::seconds{nTime}; } + unsigned int GetHeight() const { return entryHeight; } + int64_t GetSigOpCount() const { return sigOpCount; } + CAmount GetModifiedFee() const { return m_modified_fee; } + size_t DynamicMemoryUsage() const { return nUsageSize; } + const LockPoints& GetLockPoints() const { return lockPoints; } + + // Adjusts the descendant state. + void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount); + // Adjusts the ancestor state + void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps); + // Updates the modified fees with descendants/ancestors. + void UpdateModifiedFee(CAmount fee_diff) + { + nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, fee_diff); + nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, fee_diff); + m_modified_fee = SaturatingAdd(m_modified_fee, fee_diff); + } + + // Update the LockPoints after a reorg + void UpdateLockPoints(const LockPoints& lp) + { + lockPoints = lp; + } + + uint64_t GetCountWithDescendants() const { return nCountWithDescendants; } + uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; } + CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; } + + bool GetSpendsCoinbase() const { return spendsCoinbase; } + + uint64_t GetCountWithAncestors() const { return nCountWithAncestors; } + uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; } + CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; } + int64_t GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; } + + const Parents& GetMemPoolParentsConst() const { return m_parents; } + const Children& GetMemPoolChildrenConst() const { return m_children; } + Parents& GetMemPoolParents() const { return m_parents; } + Children& GetMemPoolChildren() const { return m_children; } + + mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes + + // If this is a proTx, this will be the hash of the key for which this ProTx was valid + mutable uint256 validForProTxKey; + mutable bool isKeyChangeProTx{false}; + mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms +}; + +#endif // BITCOIN_KERNEL_MEMPOOL_ENTRY_H diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 740a4e966d27..37331cdc58ee 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -328,7 +329,7 @@ struct Peer { std::atomic m_last_mempool_req{0s}; /** The next time after which we will send an `inv` message containing * transaction announcements to this peer. */ - std::chrono::microseconds m_next_inv_send_time GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0}; + std::chrono::microseconds m_next_inv_send_time GUARDED_BY(m_tx_inventory_mutex){0}; }; /** @@ -1213,6 +1214,13 @@ static void PushInv(Peer& peer, const CInv& inv) } LOCK(inv_relay->m_tx_inventory_mutex); + // Only queue transactions for announcement once the version handshake + // is completed. The time of arrival for these transactions is + // otherwise at risk of leaking to a spy, if the spy is able to + // distinguish transactions received during the handshake from the rest + // in the announcement. + if (inv_relay->m_next_inv_send_time == 0s) return; + if (inv_relay->m_tx_inventory_known_filter.contains(inv.hash)) { LogPrint(BCLog::NET, "%s -- skipping known inv: %s peer=%d\n", __func__, inv.ToString(), peer.m_id); return; @@ -4146,6 +4154,20 @@ void PeerManagerImpl::ProcessMessage( } } + if (auto tx_relay = peer->GetTxRelay()) { + // `TxRelay::m_tx_inventory_to_send` must be empty before the + // version handshake is completed as + // `TxRelay::m_next_inv_send_time` is first initialised in + // `SendMessages` after the verack is received. Any transactions + // received during the version handshake would otherwise + // immediately be advertised without random delay, potentially + // leaking the time of arrival to a spy. + Assume(WITH_LOCK( + tx_relay->m_tx_inventory_mutex, + return tx_relay->m_tx_inventory_to_send.empty() && + tx_relay->m_next_inv_send_time == 0s)); + } + pfrom.fSuccessfullyConnected = true; return; } diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 4900dcf785af..e1fa46244324 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -95,7 +96,7 @@ using interfaces::FoundBlock; using interfaces::GOV; using interfaces::Handler; using interfaces::LLMQ; -using interfaces::MakeHandler; +using interfaces::MakeSignalHandler; using interfaces::MnEntry; using interfaces::MnEntryCPtr; using interfaces::MnList; @@ -1106,78 +1107,78 @@ class NodeImpl : public Node std::unique_ptr handleInitMessage(InitMessageFn fn) override { - return MakeHandler(::uiInterface.InitMessage_connect(fn)); + return MakeSignalHandler(::uiInterface.InitMessage_connect(fn)); } std::unique_ptr handleMessageBox(MessageBoxFn fn) override { - return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn)); + return MakeSignalHandler(::uiInterface.ThreadSafeMessageBox_connect(fn)); } std::unique_ptr handleQuestion(QuestionFn fn) override { - return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn)); + return MakeSignalHandler(::uiInterface.ThreadSafeQuestion_connect(fn)); } std::unique_ptr handleShowProgress(ShowProgressFn fn) override { - return MakeHandler(::uiInterface.ShowProgress_connect(fn)); + return MakeSignalHandler(::uiInterface.ShowProgress_connect(fn)); } std::unique_ptr handleInitWallet(InitWalletFn fn) override { - return MakeHandler(::uiInterface.InitWallet_connect(fn)); + return MakeSignalHandler(::uiInterface.InitWallet_connect(fn)); } std::unique_ptr handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override { - return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn)); } std::unique_ptr handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override { - return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn)); } std::unique_ptr handleNotifyAlertChanged(NotifyAlertChangedFn fn) override { - return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.NotifyAlertChanged_connect(fn)); } std::unique_ptr handleBannedListChanged(BannedListChangedFn fn) override { - return MakeHandler(::uiInterface.BannedListChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.BannedListChanged_connect(fn)); } std::unique_ptr handleNotifyBlockTip(NotifyBlockTipFn fn) override { - return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) { + return MakeSignalHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) { fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()}, GuessVerificationProgress(Params().TxData(), block)); })); } std::unique_ptr handleNotifyChainLock(NotifyChainLockFn fn) override { - return MakeHandler(::uiInterface.NotifyChainLock_connect([fn](const std::string& bestChainLockHash, int bestChainLockHeight) { + return MakeSignalHandler(::uiInterface.NotifyChainLock_connect([fn](const std::string& bestChainLockHash, int bestChainLockHeight) { fn(bestChainLockHash, bestChainLockHeight); })); } std::unique_ptr handleNotifyHeaderTip(NotifyHeaderTipFn fn) override { - return MakeHandler( + return MakeSignalHandler( ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, int64_t height, int64_t timestamp) { fn(sync_state, BlockTip{(int)height, timestamp, uint256{}}); })); } std::unique_ptr handleNotifyInstantSendChanged(NotifyInstantSendChangedFn fn) override { - return MakeHandler(::uiInterface.NotifyInstantSendChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.NotifyInstantSendChanged_connect(fn)); } std::unique_ptr handleNotifyGovernanceChanged(NotifyGovernanceChangedFn fn) override { - return MakeHandler(::uiInterface.NotifyGovernanceChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.NotifyGovernanceChanged_connect(fn)); } std::unique_ptr handleNotifyMasternodeListChanged(NotifyMasternodeListChangedFn fn) override { - return MakeHandler( + return MakeSignalHandler( ::uiInterface.NotifyMasternodeListChanged_connect([fn](const CDeterministicMNList& newList, const CBlockIndex* pindex) { fn(newList, pindex); })); } std::unique_ptr handleNotifyAdditionalDataSyncProgressChanged(NotifyAdditionalDataSyncProgressChangedFn fn) override { - return MakeHandler( + return MakeSignalHandler( ::uiInterface.NotifyAdditionalDataSyncProgressChanged_connect([fn](double nSyncProgress) { fn(nSyncProgress); })); diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 85bf397ffcbc..722aee710228 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -15,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 487693a498a3..cba411993db8 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -518,7 +518,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel * nBytes -= 34; // Fee - nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, nullptr /* returned_target */, nullptr /* reason */); + nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, /*returned_target=*/nullptr, /*reason=*/nullptr); if (nPayAmount > 0) { diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index 23dbaaad375d..4ea89b42627e 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -56,7 +56,7 @@ void PSBTOperationsDialog::openWithPSBT(PartiallySignedTransaction psbtx) bool complete = FinalizePSBT(psbtx); // Make sure all existing signatures are fully combined before checking for completeness. if (m_wallet_model) { size_t n_could_sign; - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, &n_could_sign, m_transaction_data, complete); + TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, &n_could_sign, m_transaction_data, complete); if (err != TransactionError::OK) { showStatus(tr("Failed to load transaction: %1") .arg(QString::fromStdString(TransactionErrorString(err).translated)), @@ -80,7 +80,7 @@ void PSBTOperationsDialog::signTransaction() WalletModel::UnlockContext ctx(m_wallet_model->requestUnlock()); - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, true /* sign */, true /* bip32derivs */, &n_signed, m_transaction_data, complete); + TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, &n_signed, m_transaction_data, complete); if (err != TransactionError::OK) { showStatus(tr("Failed to sign transaction: %1") @@ -248,7 +248,7 @@ size_t PSBTOperationsDialog::couldSignInputs(const PartiallySignedTransaction &p size_t n_signed; bool complete; - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, false /* bip32derivs */, &n_signed, m_transaction_data, complete); + TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/false, &n_signed, m_transaction_data, complete); if (err != TransactionError::OK) { return 0; diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 30d6223cb21a..6cd2edae2419 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -76,7 +76,7 @@ void AppTests::appTests() m_app.parameterSetup(); GUIUtil::loadFonts(); GUIUtil::setApplicationFont(); - QVERIFY(m_app.createOptionsModel(true /* reset settings */)); + QVERIFY(m_app.createOptionsModel(/*resetSettings=*/true)); QScopedPointer style( NetworkStyle::instantiate(Params().NetworkIDString())); m_app.createWindow(style.data()); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index d4f25cee6410..d836f5232a76 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -269,7 +269,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact int nChangePosRet = -1; auto& newTx = transaction.getWtx(); - const auto& res = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired); + const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired); newTx = res ? *res : nullptr; transaction.setTransactionFee(nFeeRequired); if (fSubtractFeeFromAmount && newTx) @@ -319,7 +319,7 @@ void WalletModel::sendCoins(WalletModelTransaction& transaction, bool fIsCoinJoi } auto& newTx = transaction.getWtx(); - wallet().commitTransaction(newTx, std::move(mapValue), std::move(vOrderForm)); + wallet().commitTransaction(newTx, /*value_map=*/std::move(mapValue), std::move(vOrderForm)); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << *newTx; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index ce1257653d10..974697e39e12 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2726,7 +2726,7 @@ static RPCHelpMan scantxoutset() result.pushKV("unspents", unspents); result.pushKV("total_amount", ValueFromAmount(total_in)); } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command"); + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str())); } return result; }, @@ -2775,12 +2775,13 @@ static RPCHelpMan scanblocks() }, { scan_result_status_none, - RPCResult{"When action=='start'", RPCResult::Type::OBJ, "", "", { + RPCResult{"When action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", { {RPCResult::Type::NUM, "from_height", "The height we started the scan from"}, {RPCResult::Type::NUM, "to_height", "The height we ended the scan at"}, - {RPCResult::Type::ARR, "relevant_blocks", "", {{RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},}}, - }, - }, + {RPCResult::Type::ARR, "relevant_blocks", "Blocks that may have matched a scanobject.", { + {RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"}, + }}, + }}, RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "", { {RPCResult::Type::NUM, "progress", "Approximate percent complete"}, {RPCResult::Type::NUM, "current_height", "Height of the block currently being scanned"}, @@ -2923,7 +2924,7 @@ static RPCHelpMan scanblocks() ret.pushKV("relevant_blocks", blocks); } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command"); + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str())); } return ret; }, diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index d433c04f13e7..3f2608630043 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index fbcb7b11ae13..3375c733d61e 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -115,7 +115,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& } UniValue unused_result; if (setDone.insert(pcmd->unique_id).second) - pcmd->actor(jreq, unused_result, true /* last_handler */); + pcmd->actor(jreq, unused_result, /*last_handler=*/true); } catch (const std::exception& e) { diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index 0089d0f2e8a2..61f7fca659e7 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp index 9d43f6b96f44..ac40bc714a41 100644 --- a/src/test/fuzz/net_permissions.cpp +++ b/src/test/fuzz/net_permissions.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp index e27b2545807e..0f204babfa31 100644 --- a/src/test/fuzz/node_eviction.cpp +++ b/src/test/fuzz/node_eviction.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp index ca725210cfc9..fb7e13d57e05 100644 --- a/src/test/fuzz/policy_estimator.cpp +++ b/src/test/fuzz/policy_estimator.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp index eadf9328f127..25af251aedf4 100644 --- a/src/test/fuzz/pow.cpp +++ b/src/test/fuzz/pow.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index d142a26a4630..f6fe8ed1caca 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 476e01c2c7a3..e22373f63eff 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp index 04883aaec85a..8b4b64ea94f4 100644 --- a/src/test/fuzz/socks5.cpp +++ b/src/test/fuzz/socks5.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 0a137913a507..a46313ac10b2 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -2,319 +2,16 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include -#include #include #include #include +#include #include #include #include #include -FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) - : m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()} -{ - m_socket = fuzzed_data_provider.ConsumeIntegralInRange(INVALID_SOCKET - 1, INVALID_SOCKET); -} - -FuzzedSock::~FuzzedSock() -{ - // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call - // close(m_socket) if m_socket is not INVALID_SOCKET. - // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which - // theoretically may concide with a real opened file descriptor). - m_socket = INVALID_SOCKET; -} - -FuzzedSock& FuzzedSock::operator=(Sock&& other) -{ - assert(false && "Move of Sock into FuzzedSock not allowed."); - return *this; -} - -ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const -{ - constexpr std::array send_errnos{ - EACCES, - EAGAIN, - EALREADY, - EBADF, - ECONNRESET, - EDESTADDRREQ, - EFAULT, - EINTR, - EINVAL, - EISCONN, - EMSGSIZE, - ENOBUFS, - ENOMEM, - ENOTCONN, - ENOTSOCK, - EOPNOTSUPP, - EPIPE, - EWOULDBLOCK, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - return len; - } - const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange(-1, len); - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos); - } - return r; -} - -ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const -{ - // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always return the first element and we want to avoid Recv() - // returning -1 and setting errno to EAGAIN repeatedly. - constexpr std::array recv_errnos{ - ECONNREFUSED, - EAGAIN, - EBADF, - EFAULT, - EINTR, - EINVAL, - ENOMEM, - ENOTCONN, - ENOTSOCK, - EWOULDBLOCK, - }; - assert(buf != nullptr || len == 0); - if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); - } - return r; - } - std::vector random_bytes; - bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; - if (m_peek_data.has_value()) { - // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. - random_bytes.assign({m_peek_data.value()}); - if ((flags & MSG_PEEK) == 0) { - m_peek_data.reset(); - } - pad_to_len_bytes = false; - } else if ((flags & MSG_PEEK) != 0) { - // New call with `MSG_PEEK`. - random_bytes = m_fuzzed_data_provider.ConsumeBytes(1); - if (!random_bytes.empty()) { - m_peek_data = random_bytes[0]; - pad_to_len_bytes = false; - } - } else { - random_bytes = m_fuzzed_data_provider.ConsumeBytes( - m_fuzzed_data_provider.ConsumeIntegralInRange(0, len)); - } - if (random_bytes.empty()) { - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); - } - return r; - } - std::memcpy(buf, random_bytes.data(), random_bytes.size()); - if (pad_to_len_bytes) { - if (len > random_bytes.size()) { - std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); - } - return len; - } - if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { - std::this_thread::sleep_for(std::chrono::milliseconds{2}); - } - return random_bytes.size(); -} - -int FuzzedSock::Connect(const sockaddr*, socklen_t) const -{ - // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always return the first element and we want to avoid Connect() - // returning -1 and setting errno to EAGAIN repeatedly. - constexpr std::array connect_errnos{ - ECONNREFUSED, - EAGAIN, - ECONNRESET, - EHOSTUNREACH, - EINPROGRESS, - EINTR, - ENETUNREACH, - ETIMEDOUT, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos); - return -1; - } - return 0; -} - -int FuzzedSock::Bind(const sockaddr*, socklen_t) const -{ - // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to - // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) - // repeatedly because proper code should retry on temporary errors, leading to an - // infinite loop. - constexpr std::array bind_errnos{ - EACCES, - EADDRINUSE, - EADDRNOTAVAIL, - EAGAIN, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, bind_errnos); - return -1; - } - return 0; -} - -int FuzzedSock::Listen(int) const -{ - // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to - // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) - // repeatedly because proper code should retry on temporary errors, leading to an - // infinite loop. - constexpr std::array listen_errnos{ - EADDRINUSE, - EINVAL, - EOPNOTSUPP, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos); - return -1; - } - return 0; -} - -std::unique_ptr FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const -{ - constexpr std::array accept_errnos{ - ECONNABORTED, - EINTR, - ENOMEM, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos); - return std::unique_ptr(); - } - return std::make_unique(m_fuzzed_data_provider); -} - -int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const -{ - constexpr std::array getsockopt_errnos{ - ENOMEM, - ENOBUFS, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos); - return -1; - } - if (opt_val == nullptr) { - return 0; - } - std::memcpy(opt_val, - ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(), - *opt_len); - return 0; -} - -int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const -{ - constexpr std::array setsockopt_errnos{ - ENOMEM, - ENOBUFS, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos); - return -1; - } - return 0; -} - -int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const -{ - constexpr std::array getsockname_errnos{ - ECONNRESET, - ENOBUFS, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos); - return -1; - } - *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len); - return 0; -} - -bool FuzzedSock::SetNonBlocking() const -{ - constexpr std::array setnonblocking_errnos{ - EBADF, - EPERM, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos); - return false; - } - return true; -} - -bool FuzzedSock::IsSelectable(bool is_select) const -{ - return m_selectable; -} - -bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, SocketEventsParams event_params, Event* occurred) const -{ - constexpr std::array wait_errnos{ - EBADF, - EINTR, - EINVAL, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos); - return false; - } - if (occurred != nullptr) { - *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0; - } - return true; -} - -bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock, SocketEventsParams event_params) const -{ - for (auto& [sock, events] : events_per_sock) { - (void)sock; - events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0; - } - return true; -} - -bool FuzzedSock::IsConnected(std::string& errmsg) const -{ - if (m_fuzzed_data_provider.ConsumeBool()) { - return true; - } - errmsg = "disconnected at random by the fuzzer"; - return false; -} - -void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept -{ - connman.Handshake(node, - /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(), - /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), - /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), - /*version=*/fuzzed_data_provider.ConsumeIntegralInRange(MIN_PEER_PROTO_VERSION, std::numeric_limits::max()), - /*relay_txs=*/fuzzed_data_provider.ConsumeBool()); -} std::vector ConstructPubKeyBytes(FuzzedDataProvider& fuzzed_data_provider, Span byte_data, const bool compressed) noexcept { @@ -484,11 +181,6 @@ bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) n return false; } -CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept -{ - return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral()}}}; -} - FILE* FuzzedFileProvider::open() { SetFuzzedErrNo(m_fuzzed_data_provider); diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 28d656c1fb03..7609ffc81ea6 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -13,9 +13,6 @@ #include #include #include -#include -#include -#include #include #include