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 67 RPCFuzzTestingSetup* rpc_testing_setup =
nullptr;
68 std::string g_limit_to_rpc_command;
73 const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{
82 "generatetodescriptor",
94 const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
98 "combinerawtransaction",
102 "createrawtransaction",
104 "decoderawtransaction",
107 "descriptorprocesspsbt",
131 "getconnectioncount",
133 "getdescriptoractivity",
138 "getmempoolancestors",
139 "getmempooldescendants",
149 "getprioritisedtransactions",
156 "gettxspendingprevout",
165 "prioritisetransaction",
171 "sendrawtransaction",
174 "signmessagewithprivkey",
175 "signrawtransactionwithkey",
179 "syncwithvalidationinterfacequeue",
188 "waitforblockheight",
192 std::string ConsumeScalarRPCArgument(
FuzzedDataProvider& fuzzed_data_provider,
bool& good_data)
194 const size_t max_string_length = 4096;
195 const size_t max_base58_bytes_length{64};
198 fuzzed_data_provider,
213 r = fuzzed_data_provider.
ConsumeBool() ?
"true" :
"false";
257 std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider,
TX_WITH_WITNESS);
268 std::optional<CBlockHeader> opt_block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider);
269 if (!opt_block_header) {
274 data_stream << *opt_block_header;
279 std::optional<CMutableTransaction> opt_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider,
TX_WITH_WITNESS);
286 data_stream << allow_witness(*opt_tx);
291 std::optional<PartiallySignedTransaction> opt_psbt = ConsumeDeserializable<PartiallySignedTransaction>(fuzzed_data_provider);
297 data_stream << *opt_psbt;
321 std::string ConsumeArrayRPCArgument(
FuzzedDataProvider& fuzzed_data_provider,
bool& good_data)
323 std::vector<std::string> scalar_arguments;
326 scalar_arguments.push_back(ConsumeScalarRPCArgument(fuzzed_data_provider, good_data));
328 return "[\"" +
Join(scalar_arguments,
"\",\"") +
"\"]";
331 std::string ConsumeRPCArgument(
FuzzedDataProvider& fuzzed_data_provider,
bool& good_data)
333 return fuzzed_data_provider.
ConsumeBool() ? ConsumeScalarRPCArgument(fuzzed_data_provider, good_data) : ConsumeArrayRPCArgument(fuzzed_data_provider, good_data);
336 RPCFuzzTestingSetup* InitializeRPCFuzzTestingSetup()
338 static const auto setup = MakeNoLogFileContext<RPCFuzzTestingSetup>();
346 rpc_testing_setup = InitializeRPCFuzzTestingSetup();
347 const std::vector<std::string> supported_rpc_commands = rpc_testing_setup->GetRPCCommands();
348 for (
const std::string& rpc_command : supported_rpc_commands) {
349 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();
350 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();
351 if (!(safe_for_fuzzing || not_safe_for_fuzzing)) {
352 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";
355 if (safe_for_fuzzing && not_safe_for_fuzzing) {
356 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";
360 const char* limit_to_rpc_command_env = std::getenv(
"LIMIT_TO_RPC_COMMAND");
361 if (limit_to_rpc_command_env !=
nullptr) {
362 g_limit_to_rpc_command = std::string{limit_to_rpc_command_env};
370 bool good_data{
true};
373 if (!g_limit_to_rpc_command.empty() && rpc_command != g_limit_to_rpc_command) {
376 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();
377 if (!safe_for_fuzzing) {
380 std::vector<std::string> arguments;
383 arguments.push_back(ConsumeRPCArgument(fuzzed_data_provider, good_data));
386 rpc_testing_setup->CallRPC(rpc_command, arguments);
387 }
catch (
const UniValue& json_rpc_error) {
389 if (error_msg.starts_with(
"Internal bug detected")) {
391 assert(error_msg.find(
"trigger_internal_bug") != std::string::npos);
CPubKey GetPubKey() const
Compute the public key from a private key.
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
std::string EncodeBase64(Span< const unsigned char > input)
const std::string & get_str() const
std::string EncodeBase58(Span< const unsigned char > input)
Why base-58 instead of standard base-64 encoding?
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
UniValue execute(const JSONRPCRequest &request) const
Execute a method.
const UniValue & find_value(std::string_view key) const
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
void SetRPCWarmupFinished()
static UniValue CallRPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const std::optional< std::string > &rpcwallet={})
Double ended buffer combining vector and stream-like interfaces.
std::string ConsumeRandomLengthString(size_t max_length)
std::string ToString() const
std::string EncodeBase58Check(Span< const unsigned char > input)
Encode a byte span into a base58-encoded string, including checksum.
void SeedRandomStateForTest(SeedRand seedtype)
Seed the global RNG state for testing and log the seed value.
int64_t ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(Span
Like the Span constructor, but for (const) unsigned char member types only.
FUZZ_TARGET(rpc,.init=initialize_rpc)
std::string EncodeDestination(const CTxDestination &dest)
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
An encapsulated private key.
uint160 ConsumeUInt160(FuzzedDataProvider &fuzzed_data_provider) noexcept
Seed with a compile time constant of zeros.
uint256 ConsumeUInt256(FuzzedDataProvider &fuzzed_data_provider) noexcept
std::vector< std::string > listCommands() const
Returns a list of registered commands.
std::string EncodeSecret(const CKey &key)
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
CTxDestination ConsumeTxDestination(FuzzedDataProvider &fuzzed_data_provider) noexcept
Testing setup that configures a complete environment.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
CKey ConsumePrivateKey(FuzzedDataProvider &fuzzed_data_provider, std::optional< bool > compressed) noexcept
static constexpr TransactionSerParams TX_NO_WITNESS
static constexpr TransactionSerParams TX_WITH_WITNESS
bool IsValid() const
Check whether this private key is valid.
std::string EncodeBase32(Span< const unsigned char > input, bool pad)
Base32 encode.