48 void CallRPC(
const std::string& rpc_method,
const std::vector<std::string>& arguments)
55 }
catch (
const std::runtime_error&) {
61 std::vector<std::string> GetRPCCommands()
const
67RPCFuzzTestingSetup* rpc_testing_setup =
nullptr;
68std::string g_limit_to_rpc_command;
73const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{
81 "generatetodescriptor",
92const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
96 "combinerawtransaction",
100 "createrawtransaction",
102 "decoderawtransaction",
105 "descriptorprocesspsbt",
129 "getconnectioncount",
131 "getdescriptoractivity",
136 "getmempoolancestors",
137 "getmempooldescendants",
147 "getprioritisedtransactions",
154 "gettxspendingprevout",
163 "prioritisetransaction",
169 "sendrawtransaction",
172 "signmessagewithprivkey",
173 "signrawtransactionwithkey",
177 "syncwithvalidationinterfacequeue",
186 "waitforblockheight",
190std::string ConsumeScalarRPCArgument(
FuzzedDataProvider& fuzzed_data_provider,
bool& good_data)
192 const size_t max_string_length = 4096;
193 const size_t max_base58_bytes_length{64};
196 fuzzed_data_provider,
211 r = fuzzed_data_provider.
ConsumeBool() ?
"true" :
"false";
255 std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider,
TX_WITH_WITNESS);
266 std::optional<CBlockHeader> opt_block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider);
267 if (!opt_block_header) {
272 data_stream << *opt_block_header;
277 std::optional<CMutableTransaction> opt_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider,
TX_WITH_WITNESS);
284 data_stream << allow_witness(*opt_tx);
289 std::optional<PartiallySignedTransaction> opt_psbt = ConsumeDeserializable<PartiallySignedTransaction>(fuzzed_data_provider);
295 data_stream << *opt_psbt;
319std::string ConsumeArrayRPCArgument(
FuzzedDataProvider& fuzzed_data_provider,
bool& good_data)
321 std::vector<std::string> scalar_arguments;
324 scalar_arguments.push_back(ConsumeScalarRPCArgument(fuzzed_data_provider, good_data));
326 return "[\"" +
Join(scalar_arguments,
"\",\"") +
"\"]";
329std::string ConsumeRPCArgument(
FuzzedDataProvider& fuzzed_data_provider,
bool& good_data)
331 return fuzzed_data_provider.
ConsumeBool() ? ConsumeScalarRPCArgument(fuzzed_data_provider, good_data) : ConsumeArrayRPCArgument(fuzzed_data_provider, good_data);
334RPCFuzzTestingSetup* InitializeRPCFuzzTestingSetup()
336 static const auto setup = MakeNoLogFileContext<RPCFuzzTestingSetup>();
344 rpc_testing_setup = InitializeRPCFuzzTestingSetup();
345 const std::vector<std::string> supported_rpc_commands = rpc_testing_setup->GetRPCCommands();
346 for (
const std::string& rpc_command : supported_rpc_commands) {
347 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();
348 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();
349 if (!(safe_for_fuzzing || not_safe_for_fuzzing)) {
350 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";
353 if (safe_for_fuzzing && not_safe_for_fuzzing) {
354 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";
358 const char* limit_to_rpc_command_env = std::getenv(
"LIMIT_TO_RPC_COMMAND");
359 if (limit_to_rpc_command_env !=
nullptr) {
360 g_limit_to_rpc_command = std::string{limit_to_rpc_command_env};
368 bool good_data{
true};
371 if (!g_limit_to_rpc_command.empty() && rpc_command != g_limit_to_rpc_command) {
374 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();
375 if (!safe_for_fuzzing) {
378 std::vector<std::string> arguments;
381 arguments.push_back(ConsumeRPCArgument(fuzzed_data_provider, good_data));
384 rpc_testing_setup->CallRPC(rpc_command, arguments);
385 }
catch (
const UniValue& json_rpc_error) {
387 if (error_msg.starts_with(
"Internal bug detected")) {
389 assert(error_msg.find(
"trigger_internal_bug") != std::string::npos);
std::string EncodeBase58(std::span< const unsigned char > input)
Why base-58 instead of standard base-64 encoding?
std::string EncodeBase58Check(std::span< const unsigned char > input)
Encode a byte span into a base58-encoded string, including checksum.
static UniValue CallRPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const std::optional< std::string > &rpcwallet={})
An encapsulated private key.
bool IsValid() const
Check whether this private key is valid.
CPubKey GetPubKey() const
Compute the public key from a private key.
std::vector< std::string > listCommands() const
Returns a list of registered commands.
UniValue execute(const JSONRPCRequest &request) const
Execute a method.
Double ended buffer combining vector and stream-like interfaces.
std::string ConsumeRandomLengthString(size_t max_length)
const std::string & get_str() const
const UniValue & find_value(std::string_view key) const
std::string ToString() const
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::string EncodeSecret(const CKey &key)
std::string EncodeDestination(const CTxDestination &dest)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
static constexpr TransactionSerParams TX_NO_WITNESS
static constexpr TransactionSerParams TX_WITH_WITNESS
FUZZ_TARGET(rpc,.init=initialize_rpc)
void SetRPCWarmupFinished()
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
Testing setup that configures a complete environment.
int64_t ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
CKey ConsumePrivateKey(FuzzedDataProvider &fuzzed_data_provider, std::optional< bool > compressed) noexcept
CTxDestination ConsumeTxDestination(FuzzedDataProvider &fuzzed_data_provider) noexcept
uint256 ConsumeUInt256(FuzzedDataProvider &fuzzed_data_provider) noexcept
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
uint160 ConsumeUInt160(FuzzedDataProvider &fuzzed_data_provider) noexcept
void SeedRandomStateForTest(SeedRand seedtype)
Seed the global RNG state for testing and log the seed value.
@ ZEROS
Seed with a compile time constant of zeros.
std::string EncodeBase32(std::span< const unsigned char > input, bool pad)
Base32 encode.
std::string EncodeBase64(std::span< const unsigned char > input)
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.