diff options
Diffstat (limited to 'src/test/fuzz')
-rw-r--r-- | src/test/fuzz/coins_view.cpp | 4 | ||||
-rwxr-xr-x | src/test/fuzz/danger_link_all.sh | 28 | ||||
-rw-r--r-- | src/test/fuzz/fuzz.cpp | 13 | ||||
-rw-r--r-- | src/test/fuzz/integer.cpp | 4 | ||||
-rw-r--r-- | src/test/fuzz/net_permissions.cpp | 4 | ||||
-rw-r--r-- | src/test/fuzz/parse_iso8601.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/process_message.cpp | 1 | ||||
-rw-r--r-- | src/test/fuzz/process_messages.cpp | 1 | ||||
-rw-r--r-- | src/test/fuzz/rpc.cpp | 359 | ||||
-rw-r--r-- | src/test/fuzz/script.cpp | 56 | ||||
-rw-r--r-- | src/test/fuzz/script_assets_test_minimizer.cpp | 17 | ||||
-rw-r--r-- | src/test/fuzz/script_flags.cpp | 4 | ||||
-rw-r--r-- | src/test/fuzz/script_ops.cpp | 61 | ||||
-rw-r--r-- | src/test/fuzz/strprintf.cpp | 61 | ||||
-rw-r--r-- | src/test/fuzz/timedata.cpp | 4 | ||||
-rw-r--r-- | src/test/fuzz/tx_pool.cpp | 75 | ||||
-rw-r--r-- | src/test/fuzz/util.cpp | 18 | ||||
-rw-r--r-- | src/test/fuzz/util.h | 28 |
18 files changed, 551 insertions, 189 deletions
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index b21d2eae79..21dc80cc8d 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -258,10 +258,10 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) (void)GetTransactionSigOpCost(transaction, coins_view_cache, flags); }, [&] { - CCoinsStats stats; + CCoinsStats stats{CoinStatsHashType::HASH_SERIALIZED}; bool expected_code_path = false; try { - (void)GetUTXOStats(&coins_view_cache, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats, CoinStatsHashType::HASH_SERIALIZED); + (void)GetUTXOStats(&coins_view_cache, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats); } catch (const std::logic_error&) { expected_code_path = true; } diff --git a/src/test/fuzz/danger_link_all.sh b/src/test/fuzz/danger_link_all.sh deleted file mode 100755 index 2ddd00c658..0000000000 --- a/src/test/fuzz/danger_link_all.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2020 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -export LC_ALL=C.UTF-8 - -set -e - -ROOT_DIR="$(git rev-parse --show-toplevel)" - -# Run only once (break make recursion) -if [ -d "${ROOT_DIR}/lock_fuzz_link_all" ]; then - exit -fi -mkdir "${ROOT_DIR}/lock_fuzz_link_all" - -echo "Linking each fuzz target separately." -for FUZZING_HARNESS in $(PRINT_ALL_FUZZ_TARGETS_AND_ABORT=1 "${ROOT_DIR}/src/test/fuzz/fuzz" | sort -u); do - echo "Building src/test/fuzz/${FUZZING_HARNESS} ..." - git checkout -- "${ROOT_DIR}/src/test/fuzz/fuzz.cpp" - sed -i "s/std::getenv(\"FUZZ\")/\"${FUZZING_HARNESS}\"/g" "${ROOT_DIR}/src/test/fuzz/fuzz.cpp" - make - mv "${ROOT_DIR}/src/test/fuzz/fuzz" "${ROOT_DIR}/src/test/fuzz/${FUZZING_HARNESS}" -done -git checkout -- "${ROOT_DIR}/src/test/fuzz/fuzz.cpp" -rmdir "${ROOT_DIR}/lock_fuzz_link_all" -echo "Successfully built all fuzz targets." diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 1fab46ff13..0d8d960d56 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -29,13 +29,24 @@ static TypeTestOneInput* g_test_one_input{nullptr}; void initialize() { + bool should_abort{false}; if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) { for (const auto& t : FuzzTargets()) { if (std::get<2>(t.second)) continue; std::cout << t.first << std::endl; } - Assert(false); + should_abort = true; } + if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) { + std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl; + std::ofstream out_stream(out_path, std::ios::binary); + for (const auto& t : FuzzTargets()) { + if (std::get<2>(t.second)) continue; + out_stream << t.first << std::endl; + } + should_abort = true; + } + Assert(!should_abort); std::string_view fuzz_target{Assert(std::getenv("FUZZ"))}; const auto it = FuzzTargets().find(fuzz_target); Assert(it != FuzzTargets().end()); diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index 5bc99ddcb9..e9fa343896 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -122,10 +122,6 @@ FUZZ_TARGET_INIT(integer, initialize_integer) assert(dynamic_usage == incremental_dynamic_usage * i64s.size()); } (void)MillisToTimeval(i64); - const double d = ser_uint64_to_double(u64); - assert(ser_double_to_uint64(d) == u64); - const float f = ser_uint32_to_float(u32); - assert(ser_float_to_uint32(f) == u32); (void)SighashToStr(uch); (void)SipHashUint256(u64, u64, u256); (void)SipHashUint256Extra(u64, u64, u256, u32); diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp index 544a33047b..6fdf4b653c 100644 --- a/src/test/fuzz/net_permissions.cpp +++ b/src/test/fuzz/net_permissions.cpp @@ -25,7 +25,7 @@ FUZZ_TARGET(net_permissions) (void)NetPermissions::ToStrings(net_whitebind_permissions.m_flags); (void)NetPermissions::AddFlag(net_whitebind_permissions.m_flags, net_permission_flags); assert(NetPermissions::HasFlag(net_whitebind_permissions.m_flags, net_permission_flags)); - (void)NetPermissions::ClearFlag(net_whitebind_permissions.m_flags, net_permission_flags); + (void)NetPermissions::ClearFlag(net_whitebind_permissions.m_flags, NetPermissionFlags::PF_ISIMPLICIT); (void)NetPermissions::ToStrings(net_whitebind_permissions.m_flags); } @@ -35,7 +35,7 @@ FUZZ_TARGET(net_permissions) (void)NetPermissions::ToStrings(net_whitelist_permissions.m_flags); (void)NetPermissions::AddFlag(net_whitelist_permissions.m_flags, net_permission_flags); assert(NetPermissions::HasFlag(net_whitelist_permissions.m_flags, net_permission_flags)); - (void)NetPermissions::ClearFlag(net_whitelist_permissions.m_flags, net_permission_flags); + (void)NetPermissions::ClearFlag(net_whitelist_permissions.m_flags, NetPermissionFlags::PF_ISIMPLICIT); (void)NetPermissions::ToStrings(net_whitelist_permissions.m_flags); } } diff --git a/src/test/fuzz/parse_iso8601.cpp b/src/test/fuzz/parse_iso8601.cpp index dcb24ac127..a56f2aa48d 100644 --- a/src/test/fuzz/parse_iso8601.cpp +++ b/src/test/fuzz/parse_iso8601.cpp @@ -15,7 +15,7 @@ FUZZ_TARGET(parse_iso8601) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - const int64_t random_time = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + const int64_t random_time = fuzzed_data_provider.ConsumeIntegral<int32_t>(); const std::string random_string = fuzzed_data_provider.ConsumeRemainingBytesAsString(); const std::string iso8601_datetime = FormatISO8601DateTime(random_time); diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 96e1cfa08f..7b99193ad0 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -100,7 +100,6 @@ void fuzz_target(FuzzBufferType buffer, const std::string& LIMIT_TO_MESSAGE_TYPE g_setup->m_node.peerman->SendMessages(&p2p_node); } SyncWithValidationInterfaceQueue(); - LOCK2(::cs_main, g_cs_orphans); // See init.cpp for rationale for implicit locking order requirement g_setup->m_node.connman->StopNodes(); } diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 203c0ef8e1..11b236c9bd 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -80,6 +80,5 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages) } } SyncWithValidationInterfaceQueue(); - LOCK2(::cs_main, g_cs_orphans); // See init.cpp for rationale for implicit locking order requirement g_setup->m_node.connman->StopNodes(); } diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp new file mode 100644 index 0000000000..9195cc4873 --- /dev/null +++ b/src/test/fuzz/rpc.cpp @@ -0,0 +1,359 @@ +// 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 <base58.h> +#include <core_io.h> +#include <key.h> +#include <key_io.h> +#include <node/context.h> +#include <primitives/block.h> +#include <primitives/transaction.h> +#include <psbt.h> +#include <rpc/blockchain.h> +#include <rpc/client.h> +#include <rpc/request.h> +#include <rpc/server.h> +#include <rpc/util.h> +#include <span.h> +#include <streams.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <test/util/setup_common.h> +#include <tinyformat.h> +#include <univalue.h> +#include <util/strencodings.h> +#include <util/string.h> +#include <util/time.h> + +#include <cstdint> +#include <iostream> +#include <memory> +#include <optional> +#include <stdexcept> +#include <string> +#include <vector> + +namespace { +struct RPCFuzzTestingSetup : public TestingSetup { + RPCFuzzTestingSetup(const std::string& chain_name, const std::vector<const char*>& extra_args) : TestingSetup{chain_name, extra_args} + { + } + + UniValue CallRPC(const std::string& rpc_method, const std::vector<std::string>& arguments) + { + JSONRPCRequest request; + request.context = &m_node; + request.strMethod = rpc_method; + request.params = RPCConvertValues(rpc_method, arguments); + return tableRPC.execute(request); + } + + std::vector<std::string> GetRPCCommands() const + { + return tableRPC.listCommands(); + } +}; + +RPCFuzzTestingSetup* rpc_testing_setup = nullptr; +std::string g_limit_to_rpc_command; + +// RPC commands which are not appropriate for fuzzing: such as RPC commands +// reading or writing to a filename passed as an RPC parameter, RPC commands +// resulting in network activity, etc. +const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{ + "addconnection", // avoid DNS lookups + "addnode", // avoid DNS lookups + "addpeeraddress", // avoid DNS lookups + "analyzepsbt", // avoid signed integer overflow in CFeeRate::GetFee(unsigned long) (https://github.com/bitcoin/bitcoin/issues/20607) + "dumptxoutset", // avoid writing to disk + "dumpwallet", // avoid writing to disk + "echoipc", // avoid assertion failure (Assertion `"EnsureAnyNodeContext(request.context).init" && check' failed.) + "generatetoaddress", // avoid prohibitively slow execution (when `num_blocks` is large) + "generatetodescriptor", // avoid prohibitively slow execution (when `nblocks` is large) + "gettxoutproof", // avoid prohibitively slow execution + "importwallet", // avoid reading from disk + "loadwallet", // avoid reading from disk + "prioritisetransaction", // avoid signed integer overflow in CTxMemPool::PrioritiseTransaction(uint256 const&, long const&) (https://github.com/bitcoin/bitcoin/issues/20626) + "savemempool", // disabled as a precautionary measure: may take a file path argument in the future + "setban", // avoid DNS lookups + "stop", // avoid shutdown state +}; + +// RPC commands which are safe for fuzzing. +const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{ + "clearbanned", + "combinepsbt", + "combinerawtransaction", + "converttopsbt", + "createmultisig", + "createpsbt", + "createrawtransaction", + "decodepsbt", + "decoderawtransaction", + "decodescript", + "deriveaddresses", + "disconnectnode", + "echo", + "echojson", + "estimaterawfee", + "estimatesmartfee", + "finalizepsbt", + "generate", + "generateblock", + "getaddednodeinfo", + "getbestblockhash", + "getblock", + "getblockchaininfo", + "getblockcount", + "getblockfilter", + "getblockhash", + "getblockheader", + "getblockstats", + "getblocktemplate", + "getchaintips", + "getchaintxstats", + "getconnectioncount", + "getdescriptorinfo", + "getdifficulty", + "getindexinfo", + "getmemoryinfo", + "getmempoolancestors", + "getmempooldescendants", + "getmempoolentry", + "getmempoolinfo", + "getmininginfo", + "getnettotals", + "getnetworkhashps", + "getnetworkinfo", + "getnodeaddresses", + "getpeerinfo", + "getrawmempool", + "getrawtransaction", + "getrpcinfo", + "gettxout", + "gettxoutsetinfo", + "help", + "invalidateblock", + "joinpsbts", + "listbanned", + "logging", + "mockscheduler", + "ping", + "preciousblock", + "pruneblockchain", + "reconsiderblock", + "scantxoutset", + "sendrawtransaction", + "setmocktime", + "setnetworkactive", + "signmessagewithprivkey", + "signrawtransactionwithkey", + "submitblock", + "submitheader", + "syncwithvalidationinterfacequeue", + "testmempoolaccept", + "uptime", + "utxoupdatepsbt", + "validateaddress", + "verifychain", + "verifymessage", + "verifytxoutproof", + "waitforblock", + "waitforblockheight", + "waitfornewblock", +}; + +std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider) +{ + const size_t max_string_length = 4096; + const size_t max_base58_bytes_length{64}; + std::string r; + CallOneOf( + fuzzed_data_provider, + [&] { + // string argument + r = fuzzed_data_provider.ConsumeRandomLengthString(max_string_length); + }, + [&] { + // base64 argument + r = EncodeBase64(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length)); + }, + [&] { + // hex argument + r = HexStr(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length)); + }, + [&] { + // bool argument + r = fuzzed_data_provider.ConsumeBool() ? "true" : "false"; + }, + [&] { + // range argument + r = "[" + ToString(fuzzed_data_provider.ConsumeIntegral<int64_t>()) + "," + ToString(fuzzed_data_provider.ConsumeIntegral<int64_t>()) + "]"; + }, + [&] { + // integral argument (int64_t) + r = ToString(fuzzed_data_provider.ConsumeIntegral<int64_t>()); + }, + [&] { + // integral argument (uint64_t) + r = ToString(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + }, + [&] { + // floating point argument + r = strprintf("%f", fuzzed_data_provider.ConsumeFloatingPoint<double>()); + }, + [&] { + // tx destination argument + r = EncodeDestination(ConsumeTxDestination(fuzzed_data_provider)); + }, + [&] { + // uint160 argument + r = ConsumeUInt160(fuzzed_data_provider).ToString(); + }, + [&] { + // uint256 argument + r = ConsumeUInt256(fuzzed_data_provider).ToString(); + }, + [&] { + // base32 argument + r = EncodeBase32(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length)); + }, + [&] { + // base58 argument + r = EncodeBase58(MakeUCharSpan(fuzzed_data_provider.ConsumeRandomLengthString(max_base58_bytes_length))); + }, + [&] { + // base58 argument with checksum + r = EncodeBase58Check(MakeUCharSpan(fuzzed_data_provider.ConsumeRandomLengthString(max_base58_bytes_length))); + }, + [&] { + // hex encoded block + std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider); + if (!opt_block) { + return; + } + CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION}; + data_stream << *opt_block; + r = HexStr(data_stream); + }, + [&] { + // hex encoded block header + std::optional<CBlockHeader> opt_block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider); + if (!opt_block_header) { + return; + } + CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION}; + data_stream << *opt_block_header; + r = HexStr(data_stream); + }, + [&] { + // hex encoded tx + std::optional<CMutableTransaction> opt_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); + if (!opt_tx) { + return; + } + CDataStream data_stream{SER_NETWORK, fuzzed_data_provider.ConsumeBool() ? PROTOCOL_VERSION : (PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)}; + data_stream << *opt_tx; + r = HexStr(data_stream); + }, + [&] { + // base64 encoded psbt + std::optional<PartiallySignedTransaction> opt_psbt = ConsumeDeserializable<PartiallySignedTransaction>(fuzzed_data_provider); + if (!opt_psbt) { + return; + } + CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION}; + data_stream << *opt_psbt; + r = EncodeBase64({data_stream.begin(), data_stream.end()}); + }, + [&] { + // base58 encoded key + const std::vector<uint8_t> random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(32); + CKey key; + key.Set(random_bytes.begin(), random_bytes.end(), fuzzed_data_provider.ConsumeBool()); + if (!key.IsValid()) { + return; + } + r = EncodeSecret(key); + }, + [&] { + // hex encoded pubkey + const std::vector<uint8_t> random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(32); + CKey key; + key.Set(random_bytes.begin(), random_bytes.end(), fuzzed_data_provider.ConsumeBool()); + if (!key.IsValid()) { + return; + } + r = HexStr(key.GetPubKey()); + }); + return r; +} + +std::string ConsumeArrayRPCArgument(FuzzedDataProvider& fuzzed_data_provider) +{ + std::vector<std::string> scalar_arguments; + while (fuzzed_data_provider.ConsumeBool()) { + scalar_arguments.push_back(ConsumeScalarRPCArgument(fuzzed_data_provider)); + } + return "[\"" + Join(scalar_arguments, "\",\"") + "\"]"; +} + +std::string ConsumeRPCArgument(FuzzedDataProvider& fuzzed_data_provider) +{ + return fuzzed_data_provider.ConsumeBool() ? ConsumeScalarRPCArgument(fuzzed_data_provider) : ConsumeArrayRPCArgument(fuzzed_data_provider); +} + +RPCFuzzTestingSetup* InitializeRPCFuzzTestingSetup() +{ + static const auto setup = MakeNoLogFileContext<RPCFuzzTestingSetup>(); + SetRPCWarmupFinished(); + return setup.get(); +} +}; // namespace + +void initialize_rpc() +{ + rpc_testing_setup = InitializeRPCFuzzTestingSetup(); + const std::vector<std::string> supported_rpc_commands = rpc_testing_setup->GetRPCCommands(); + for (const std::string& rpc_command : supported_rpc_commands) { + const bool safe_for_fuzzing = std::find(RPC_COMMANDS_SAFE_FOR_FUZZING.begin(), RPC_COMMANDS_SAFE_FOR_FUZZING.end(), rpc_command) != RPC_COMMANDS_SAFE_FOR_FUZZING.end(); + const bool not_safe_for_fuzzing = std::find(RPC_COMMANDS_NOT_SAFE_FOR_FUZZING.begin(), RPC_COMMANDS_NOT_SAFE_FOR_FUZZING.end(), rpc_command) != RPC_COMMANDS_NOT_SAFE_FOR_FUZZING.end(); + if (!(safe_for_fuzzing || not_safe_for_fuzzing)) { + std::cerr << "Error: RPC command \"" << rpc_command << "\" not found in RPC_COMMANDS_SAFE_FOR_FUZZING or RPC_COMMANDS_NOT_SAFE_FOR_FUZZING. Please update " << __FILE__ << ".\n"; + std::terminate(); + } + if (safe_for_fuzzing && not_safe_for_fuzzing) { + std::cerr << "Error: RPC command \"" << rpc_command << "\" found in *both* RPC_COMMANDS_SAFE_FOR_FUZZING and RPC_COMMANDS_NOT_SAFE_FOR_FUZZING. Please update " << __FILE__ << ".\n"; + std::terminate(); + } + } + const char* limit_to_rpc_command_env = std::getenv("LIMIT_TO_RPC_COMMAND"); + if (limit_to_rpc_command_env != nullptr) { + g_limit_to_rpc_command = std::string{limit_to_rpc_command_env}; + } +} + +FUZZ_TARGET_INIT(rpc, initialize_rpc) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + SetMockTime(ConsumeTime(fuzzed_data_provider)); + const std::string rpc_command = fuzzed_data_provider.ConsumeRandomLengthString(64); + if (!g_limit_to_rpc_command.empty() && rpc_command != g_limit_to_rpc_command) { + return; + } + const bool safe_for_fuzzing = std::find(RPC_COMMANDS_SAFE_FOR_FUZZING.begin(), RPC_COMMANDS_SAFE_FOR_FUZZING.end(), rpc_command) != RPC_COMMANDS_SAFE_FOR_FUZZING.end(); + if (!safe_for_fuzzing) { + return; + } + std::vector<std::string> arguments; + while (fuzzed_data_provider.ConsumeBool()) { + arguments.push_back(ConsumeRPCArgument(fuzzed_data_provider)); + } + try { + rpc_testing_setup->CallRPC(rpc_command, arguments); + } catch (const UniValue&) { + } catch (const std::runtime_error&) { + } +} diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index e87ae5b04b..b87bcf2ef5 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -43,7 +43,7 @@ FUZZ_TARGET_INIT(script, initialize_script) if (!script_opt) return; const CScript script{*script_opt}; - std::vector<unsigned char> compressed; + CompressedScript compressed; if (CompressScript(script, compressed)) { const unsigned int size = compressed[0]; compressed.erase(compressed.begin()); @@ -55,22 +55,45 @@ FUZZ_TARGET_INIT(script, initialize_script) } CTxDestination address; - (void)ExtractDestination(script, address); - TxoutType type_ret; std::vector<CTxDestination> addresses; int required_ret; - (void)ExtractDestinations(script, type_ret, addresses, required_ret); - - const FlatSigningProvider signing_provider; - (void)InferDescriptor(script, signing_provider); - - (void)IsSegWitOutput(signing_provider, script); - - (void)IsSolvable(signing_provider, script); + bool extract_destinations_ret = ExtractDestinations(script, type_ret, addresses, required_ret); + bool extract_destination_ret = ExtractDestination(script, address); + if (!extract_destinations_ret) { + assert(!extract_destination_ret); + if (type_ret == TxoutType::MULTISIG) { + assert(addresses.empty() && required_ret == 0); + } else { + assert(type_ret == TxoutType::PUBKEY || + type_ret == TxoutType::NONSTANDARD || + type_ret == TxoutType::NULL_DATA); + } + } else { + assert(required_ret >= 1 && required_ret <= 16); + assert((unsigned long)required_ret == addresses.size()); + assert(type_ret == TxoutType::MULTISIG || required_ret == 1); + } + if (type_ret == TxoutType::NONSTANDARD || type_ret == TxoutType::NULL_DATA) { + assert(!extract_destinations_ret); + } + if (!extract_destination_ret) { + assert(type_ret == TxoutType::PUBKEY || + type_ret == TxoutType::NONSTANDARD || + type_ret == TxoutType::NULL_DATA || + type_ret == TxoutType::MULTISIG); + } else { + assert(address == addresses[0]); + } + if (type_ret == TxoutType::NONSTANDARD || + type_ret == TxoutType::NULL_DATA || + type_ret == TxoutType::MULTISIG) { + assert(!extract_destination_ret); + } TxoutType which_type; bool is_standard_ret = IsStandard(script, which_type); + assert(type_ret == which_type); if (!is_standard_ret) { assert(which_type == TxoutType::NONSTANDARD || which_type == TxoutType::NULL_DATA || @@ -87,6 +110,11 @@ FUZZ_TARGET_INIT(script, initialize_script) which_type == TxoutType::NONSTANDARD); } + const FlatSigningProvider signing_provider; + (void)InferDescriptor(script, signing_provider); + (void)IsSegWitOutput(signing_provider, script); + (void)IsSolvable(signing_provider, script); + (void)RecursiveDynamicUsage(script); std::vector<std::vector<unsigned char>> solutions; @@ -115,10 +143,12 @@ FUZZ_TARGET_INIT(script, initialize_script) { const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); + CompressedScript compressed_script; + compressed_script.assign(bytes.begin(), bytes.end()); // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short - if (bytes.size() >= 32) { + if (compressed_script.size() >= 32) { CScript decompressed_script; - DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), bytes); + DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script); } } diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp index cec5212f42..a80338b965 100644 --- a/src/test/fuzz/script_assets_test_minimizer.cpp +++ b/src/test/fuzz/script_assets_test_minimizer.cpp @@ -133,8 +133,7 @@ unsigned int ParseScriptFlags(const std::string& str) std::vector<std::string> words; boost::algorithm::split(words, str, boost::algorithm::is_any_of(",")); - for (const std::string& word : words) - { + for (const std::string& word : words) { auto it = FLAG_NAMES.find(word); if (it == FLAG_NAMES.end()) throw std::runtime_error("Unknown verification flag " + word); flags |= it->second; @@ -186,15 +185,19 @@ void Test(const std::string& str) } } -ECCVerifyHandle handle; - -} // namespace +void test_init() +{ + static ECCVerifyHandle handle; +} -FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, FuzzFrameworkEmptyInitFun, /* 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); try { Test(str); - } catch (const std::runtime_error&) {} + } catch (const std::runtime_error&) { + } } + +} // namespace diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp index aa911cdeda..1278dc87d4 100644 --- a/src/test/fuzz/script_flags.cpp +++ b/src/test/fuzz/script_flags.cpp @@ -41,6 +41,10 @@ FUZZ_TARGET_INIT(script_flags, initialize_script_flags) for (unsigned i = 0; i < tx.vin.size(); ++i) { CTxOut prevout; ds >> prevout; + if (!MoneyRange(prevout.nValue)) { + // prevouts should be consensus-valid + prevout.nValue = 1; + } spent_outputs.push_back(prevout); } PrecomputedTransactionData txdata; diff --git a/src/test/fuzz/script_ops.cpp b/src/test/fuzz/script_ops.cpp index eb1c808a88..4bc709ed35 100644 --- a/src/test/fuzz/script_ops.cpp +++ b/src/test/fuzz/script_ops.cpp @@ -14,55 +14,54 @@ FUZZ_TARGET(script_ops) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - CScript script = ConsumeScript(fuzzed_data_provider); + CScript script_mut = ConsumeScript(fuzzed_data_provider); while (fuzzed_data_provider.remaining_bytes() > 0) { CallOneOf( fuzzed_data_provider, [&] { CScript s = ConsumeScript(fuzzed_data_provider); - script = std::move(s); + script_mut = std::move(s); }, [&] { const CScript& s = ConsumeScript(fuzzed_data_provider); - script = s; + script_mut = s; }, [&] { - script << fuzzed_data_provider.ConsumeIntegral<int64_t>(); + script_mut << fuzzed_data_provider.ConsumeIntegral<int64_t>(); }, [&] { - script << ConsumeOpcodeType(fuzzed_data_provider); + script_mut << ConsumeOpcodeType(fuzzed_data_provider); }, [&] { - script << ConsumeScriptNum(fuzzed_data_provider); + script_mut << ConsumeScriptNum(fuzzed_data_provider); }, [&] { - script << ConsumeRandomLengthByteVector(fuzzed_data_provider); + script_mut << ConsumeRandomLengthByteVector(fuzzed_data_provider); }, [&] { - script.clear(); - }, - [&] { - (void)script.GetSigOpCount(false); - (void)script.GetSigOpCount(true); - (void)script.GetSigOpCount(script); - (void)script.HasValidOps(); - (void)script.IsPayToScriptHash(); - (void)script.IsPayToWitnessScriptHash(); - (void)script.IsPushOnly(); - (void)script.IsUnspendable(); - { - CScript::const_iterator pc = script.begin(); - opcodetype opcode; - (void)script.GetOp(pc, opcode); - std::vector<uint8_t> data; - (void)script.GetOp(pc, opcode, data); - (void)script.IsPushOnly(pc); - } - { - int version; - std::vector<uint8_t> program; - (void)script.IsWitnessProgram(version, program); - } + script_mut.clear(); }); } + const CScript& script = script_mut; + (void)script.GetSigOpCount(false); + (void)script.GetSigOpCount(true); + (void)script.GetSigOpCount(script); + (void)script.HasValidOps(); + (void)script.IsPayToScriptHash(); + (void)script.IsPayToWitnessScriptHash(); + (void)script.IsPushOnly(); + (void)script.IsUnspendable(); + { + CScript::const_iterator pc = script.begin(); + opcodetype opcode; + (void)script.GetOp(pc, opcode); + std::vector<uint8_t> data; + (void)script.GetOp(pc, opcode, data); + (void)script.IsPushOnly(pc); + } + { + int version; + std::vector<uint8_t> program; + (void)script.IsWitnessProgram(version, program); + } } diff --git a/src/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp index 2c92b159a5..18de0e1960 100644 --- a/src/test/fuzz/strprintf.cpp +++ b/src/test/fuzz/strprintf.cpp @@ -49,67 +49,6 @@ FUZZ_TARGET(str_printf) // Upstream bug report: https://github.com/c42f/tinyformat/issues/70 try { - (void)strprintf(format_string, (signed char*)nullptr); - (void)tinyformat::format(bilingual_string, (signed char*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (unsigned char*)nullptr); - (void)tinyformat::format(bilingual_string, (unsigned char*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (void*)nullptr); - (void)tinyformat::format(bilingual_string, (void*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (bool*)nullptr); - (void)tinyformat::format(bilingual_string, (bool*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (float*)nullptr); - (void)tinyformat::format(bilingual_string, (float*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (double*)nullptr); - (void)tinyformat::format(bilingual_string, (double*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (int16_t*)nullptr); - (void)tinyformat::format(bilingual_string, (int16_t*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (uint16_t*)nullptr); - (void)tinyformat::format(bilingual_string, (uint16_t*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (int32_t*)nullptr); - (void)tinyformat::format(bilingual_string, (int32_t*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (uint32_t*)nullptr); - (void)tinyformat::format(bilingual_string, (uint32_t*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (int64_t*)nullptr); - (void)tinyformat::format(bilingual_string, (int64_t*)nullptr); - } catch (const tinyformat::format_error&) { - } - try { - (void)strprintf(format_string, (uint64_t*)nullptr); - (void)tinyformat::format(bilingual_string, (uint64_t*)nullptr); - } catch (const tinyformat::format_error&) { - } - - try { CallOneOf( fuzzed_data_provider, [&] { diff --git a/src/test/fuzz/timedata.cpp b/src/test/fuzz/timedata.cpp index d7fa66298a..f7dc5f433e 100644 --- a/src/test/fuzz/timedata.cpp +++ b/src/test/fuzz/timedata.cpp @@ -15,10 +15,12 @@ FUZZ_TARGET(timedata) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const unsigned int max_size = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 1000); + // A max_size of 0 implies no limit, so cap the max number of insertions to avoid timeouts + auto max_to_insert = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 4000); // Divide by 2 to avoid signed integer overflow in .median() const int64_t initial_value = fuzzed_data_provider.ConsumeIntegral<int64_t>() / 2; CMedianFilter<int64_t> median_filter{max_size, initial_value}; - while (fuzzed_data_provider.remaining_bytes() > 0) { + while (fuzzed_data_provider.remaining_bytes() > 0 && --max_to_insert >= 0) { (void)median_filter.median(); assert(median_filter.size() > 0); assert(static_cast<size_t>(median_filter.size()) == median_filter.sorted().size()); diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index fe8d17b24a..068e207118 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <consensus/validation.h> +#include <miner.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> @@ -77,13 +78,44 @@ void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_pr ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999))); } +void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CChainState& chainstate) +{ + WITH_LOCK(::cs_main, tx_pool.check(chainstate)); + { + 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}; + auto block_template = assembler.CreateNewBlock(CScript{} << OP_TRUE); + Assert(block_template->block.vtx.size() >= 1); + } + const auto info_all = tx_pool.infoAll(); + if (!info_all.empty()) { + const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx; + WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK)); + std::vector<uint256> all_txids; + tx_pool.queryHashes(all_txids); + assert(all_txids.size() < info_all.size()); + WITH_LOCK(::cs_main, tx_pool.check(chainstate)); + } + SyncWithValidationInterfaceQueue(); +} + +void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chainstate) +{ + const auto time = ConsumeTime(fuzzed_data_provider, + chainstate.m_chain.Tip()->GetMedianTimePast() + 1, + std::numeric_limits<decltype(chainstate.m_chain.Tip()->nTime)>::max()); + SetMockTime(time); +} + FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const auto& node = g_setup->m_node; auto& chainstate = node.chainman->ActiveChainstate(); - SetMockTime(ConsumeTime(fuzzed_data_provider)); + MockTime(fuzzed_data_provider, chainstate); SetMempoolConstraints(*node.args, fuzzed_data_provider); // All RBF-spendable outpoints @@ -163,7 +195,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) }(); if (fuzzed_data_provider.ConsumeBool()) { - SetMockTime(ConsumeTime(fuzzed_data_provider)); + MockTime(fuzzed_data_provider, chainstate); } if (fuzzed_data_provider.ConsumeBool()) { SetMempoolConstraints(*node.args, fuzzed_data_provider); @@ -237,23 +269,17 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) } } } - WITH_LOCK(::cs_main, tx_pool.check(chainstate)); - const auto info_all = tx_pool.infoAll(); - if (!info_all.empty()) { - const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx; - WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK)); - std::vector<uint256> all_txids; - tx_pool.queryHashes(all_txids); - assert(all_txids.size() < info_all.size()); - WITH_LOCK(::cs_main, tx_pool.check(chainstate)); - } - SyncWithValidationInterfaceQueue(); + Finish(fuzzed_data_provider, tx_pool, chainstate); } FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const auto& node = g_setup->m_node; + auto& chainstate = node.chainman->ActiveChainstate(); + + MockTime(fuzzed_data_provider, chainstate); + SetMempoolConstraints(*node.args, fuzzed_data_provider); std::vector<uint256> txids; for (const auto& outpoint : g_outpoints_coinbase_init_mature) { @@ -265,11 +291,29 @@ 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_); while (fuzzed_data_provider.ConsumeBool()) { const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids); + if (fuzzed_data_provider.ConsumeBool()) { + MockTime(fuzzed_data_provider, chainstate); + } + if (fuzzed_data_provider.ConsumeBool()) { + SetMempoolConstraints(*node.args, fuzzed_data_provider); + } + if (fuzzed_data_provider.ConsumeBool()) { + tx_pool.RollingFeeUpdate(); + } + if (fuzzed_data_provider.ConsumeBool()) { + const auto& txid = fuzzed_data_provider.ConsumeBool() ? + mut_tx.GetHash() : + PickValue(fuzzed_data_provider, txids); + const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN); + tx_pool.PrioritiseTransaction(txid, delta); + } + const auto tx = MakeTransactionRef(mut_tx); const bool bypass_limits = fuzzed_data_provider.ConsumeBool(); ::fRequireStandard = fuzzed_data_provider.ConsumeBool(); @@ -278,8 +322,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool) if (accepted) { txids.push_back(tx->GetHash()); } - - SyncWithValidationInterfaceQueue(); } + Finish(fuzzed_data_provider, tx_pool, chainstate); } } // namespace diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index b8d846a995..bcf0b0ce72 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -5,6 +5,7 @@ #include <test/fuzz/util.h> #include <test/util/script.h> #include <util/rbf.h> +#include <util/time.h> #include <version.h> FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) @@ -216,6 +217,19 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_v } } +CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max) noexcept +{ + return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, max.value_or(MAX_MONEY)); +} + +int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min, const std::optional<int64_t>& max) noexcept +{ + // Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime. + static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z"); + static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z"); + return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(min.value_or(time_min), max.value_or(time_max)); +} + CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept { CMutableTransaction tx_mut; @@ -267,13 +281,13 @@ CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, co return ret; } -CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length, const bool maybe_p2wsh) noexcept +CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length, const bool maybe_p2wsh) noexcept { const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); CScript r_script{b.begin(), b.end()}; if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) { uint256 script_hash; - CSHA256().Write(&r_script[0], r_script.size()).Finalize(script_hash.begin()); + CSHA256().Write(r_script.data(), r_script.size()).Finalize(script_hash.begin()); r_script.clear(); r_script << OP_0 << ToByteVector(script_hash); } diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 8f4f87fbdc..48b7877896 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -26,7 +26,6 @@ #include <test/util/net.h> #include <txmempool.h> #include <uint256.h> -#include <util/time.h> #include <version.h> #include <algorithm> @@ -58,18 +57,20 @@ auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col) return *it; } -[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept { - const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length); + const std::string s = max_length ? + fuzzed_data_provider.ConsumeRandomLengthString(*max_length) : + fuzzed_data_provider.ConsumeRandomLengthString(); return {s.begin(), s.end()}; } -[[nodiscard]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept { return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)); } -[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept { return CDataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION}; } @@ -96,7 +97,7 @@ template <typename T> } template <typename T> -[[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept { const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION}; @@ -122,24 +123,15 @@ template <typename WeakEnumType, size_t size> return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE)); } -[[nodiscard]] inline CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider) noexcept -{ - return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY); -} +[[nodiscard]] CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max = std::nullopt) noexcept; -[[nodiscard]] inline int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider) noexcept -{ - // Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) is a no-op. - static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z"); - static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z"); - return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max); -} +[[nodiscard]] int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min = std::nullopt, const std::optional<int64_t>& max = std::nullopt) noexcept; [[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept; [[nodiscard]] CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size = 32) noexcept; -[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096, const bool maybe_p2wsh = false) noexcept; +[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt, const bool maybe_p2wsh = false) noexcept; [[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept; |