diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index e960a5ed4b7..f4b12211dd7 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,7 @@ #include #include #include +#include #include #include @@ -937,7 +939,7 @@ static RPCHelpMan pruneblockchain() }; } -CoinStatsHashType ParseHashType(const std::string& hash_type_input) +CoinStatsHashType ParseHashType(std::string_view hash_type_input) { if (hash_type_input == "hash_serialized_3") { return CoinStatsHashType::HASH_SERIALIZED; @@ -1039,7 +1041,7 @@ static RPCHelpMan gettxoutsetinfo() UniValue ret(UniValue::VOBJ); const CBlockIndex* pindex{nullptr}; - const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())}; + const CoinStatsHashType hash_type{ParseHashType(self.Arg("hash_type"))}; bool index_requested = request.params[2].isNull() || request.params[2].get_bool(); NodeContext& node = EnsureAnyNodeContext(request.context); @@ -2516,7 +2518,8 @@ static RPCHelpMan scanblocks() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { UniValue ret(UniValue::VOBJ); - if (request.params[0].get_str() == "status") { + auto action{self.Arg("action")}; + if (action == "status") { BlockFiltersScanReserver reserver; if (reserver.reserve()) { // no scan in progress @@ -2525,7 +2528,7 @@ static RPCHelpMan scanblocks() ret.pushKV("progress", g_scanfilter_progress.load()); ret.pushKV("current_height", g_scanfilter_progress_height.load()); return ret; - } else if (request.params[0].get_str() == "abort") { + } else if (action == "abort") { BlockFiltersScanReserver reserver; if (reserver.reserve()) { // reserve was possible which means no scan was running @@ -2534,12 +2537,12 @@ static RPCHelpMan scanblocks() // set the abort flag g_scanfilter_should_abort_scan = true; return true; - } else if (request.params[0].get_str() == "start") { + } else if (action == "start") { BlockFiltersScanReserver reserver; if (!reserver.reserve()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\""); } - const std::string filtertype_name{request.params[4].isNull() ? "basic" : request.params[4].get_str()}; + auto filtertype_name{self.Arg("filtertype")}; BlockFilterType filtertype; if (!BlockFilterTypeByName(filtertype_name, filtertype)) { @@ -2551,7 +2554,7 @@ static RPCHelpMan scanblocks() BlockFilterIndex* index = GetBlockFilterIndex(filtertype); if (!index) { - throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name); + throw JSONRPCError(RPC_MISC_ERROR, tfm::format("Index is not enabled for filtertype %s", filtertype_name)); } NodeContext& node = EnsureAnyNodeContext(request.context); @@ -2650,9 +2653,8 @@ static RPCHelpMan scanblocks() ret.pushKV("to_height", start_index->nHeight); // start_index is always the last scanned block here ret.pushKV("relevant_blocks", std::move(blocks)); ret.pushKV("completed", completed); - } - else { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str())); + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, tfm::format("Invalid action '%s'", action)); } return ret; }, @@ -2917,10 +2919,7 @@ static RPCHelpMan getblockfilter() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { uint256 block_hash = ParseHashV(request.params[0], "blockhash"); - std::string filtertype_name = BlockFilterTypeName(BlockFilterType::BASIC); - if (!request.params[1].isNull()) { - filtertype_name = request.params[1].get_str(); - } + auto filtertype_name{self.Arg("filtertype")}; BlockFilterType filtertype; if (!BlockFilterTypeByName(filtertype_name, filtertype)) { @@ -2929,7 +2928,7 @@ static RPCHelpMan getblockfilter() BlockFilterIndex* index = GetBlockFilterIndex(filtertype); if (!index) { - throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name); + throw JSONRPCError(RPC_MISC_ERROR, tfm::format("Index is not enabled for filtertype %s", filtertype_name)); } const CBlockIndex* block_index; @@ -3075,10 +3074,10 @@ static RPCHelpMan dumptxoutset() } const ArgsManager& args{EnsureAnyArgsman(request.context)}; - const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str())); + const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(self.Arg("path"))); // Write to a temporary path and then move into `path` on completion // to avoid confusion due to an interruption. - const fs::path temppath = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete")); + const fs::path temppath = path + ".incomplete"; if (fs::exists(path)) { throw JSONRPCError( diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp index 92c7a922f28..ceb341e46af 100644 --- a/src/rpc/fees.cpp +++ b/src/rpc/fees.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using common::FeeModeFromString; using common::FeeModesDetail; @@ -67,18 +68,15 @@ static RPCHelpMan estimatesmartfee() CHECK_NONFATAL(mempool.m_opts.signals)->SyncWithValidationInterfaceQueue(); unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); - bool conservative = false; - if (!request.params[1].isNull()) { - FeeEstimateMode fee_mode; - if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage()); - } - if (fee_mode == FeeEstimateMode::CONSERVATIVE) conservative = true; + FeeEstimateMode fee_mode; + if (!FeeModeFromString(self.Arg("estimate_mode"), fee_mode)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage()); } UniValue result(UniValue::VOBJ); UniValue errors(UniValue::VARR); FeeCalculation feeCalc; + bool conservative{fee_mode == FeeEstimateMode::CONSERVATIVE}; CFeeRate feeRate{fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative)}; if (feeRate != CFeeRate(0)) { CFeeRate min_mempool_feerate{mempool.GetMinFee()}; diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 147af369d34..1fda2a23594 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -28,6 +28,7 @@ #include #include +#include #include using node::DumpMempool; @@ -768,7 +769,7 @@ static RPCHelpMan importmempool() throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Can only import the mempool after the block download and sync is done."); } - const fs::path load_path{fs::u8path(request.params[0].get_str())}; + const fs::path load_path{fs::u8path(self.Arg("filepath"))}; const UniValue& use_current_time{request.params[1]["use_current_time"]}; const UniValue& apply_fee_delta{request.params[1]["apply_fee_delta_priority"]}; const UniValue& apply_unbroadcast{request.params[1]["apply_unbroadcast_set"]}; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 4c88caca27b..c97d4c75af0 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -36,11 +36,11 @@ #include #include #include +#include #include using node::NodeContext; using util::Join; -using util::TrimString; const std::vector CONNECTION_TYPE_DOC{ "outbound-full-relay (default automatic connections)", @@ -402,7 +402,7 @@ static RPCHelpMan addconnection() } const std::string address = request.params[0].get_str(); - const std::string conn_type_in{TrimString(request.params[1].get_str())}; + auto conn_type_in{util::TrimStringView(self.Arg("connection_type"))}; ConnectionType conn_type{}; if (conn_type_in == "outbound-full-relay") { conn_type = ConnectionType::OUTBOUND_FULL_RELAY; @@ -462,16 +462,15 @@ static RPCHelpMan disconnectnode() CConnman& connman = EnsureConnman(node); bool success; - const UniValue &address_arg = request.params[0]; - const UniValue &id_arg = request.params[1]; + auto address{self.MaybeArg("address")}; + auto node_id{self.MaybeArg("nodeid")}; - if (!address_arg.isNull() && id_arg.isNull()) { + if (address && !node_id) { /* handle disconnect-by-address */ - success = connman.DisconnectNode(address_arg.get_str()); - } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) { + success = connman.DisconnectNode(*address); + } else if (node_id && (!address || address->empty())) { /* handle disconnect-by-id */ - NodeId nodeid = (NodeId) id_arg.getInt(); - success = connman.DisconnectNode(nodeid); + success = connman.DisconnectNode(*node_id); } else { throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided."); } @@ -523,10 +522,10 @@ static RPCHelpMan getaddednodeinfo() std::vector vInfo = connman.GetAddedNodeInfo(/*include_connected=*/true); - if (!request.params[0].isNull()) { + if (auto node{self.MaybeArg("node")}) { bool found = false; for (const AddedNodeInfo& info : vInfo) { - if (info.m_params.m_added_node == request.params[0].get_str()) { + if (info.m_params.m_added_node == *node) { vInfo.assign(1, info); found = true; break; @@ -754,10 +753,8 @@ static RPCHelpMan setban() }, [&](const RPCHelpMan& help, const JSONRPCRequest& request) -> UniValue { - std::string strCommand; - if (!request.params[1].isNull()) - strCommand = request.params[1].get_str(); - if (strCommand != "add" && strCommand != "remove") { + auto command{help.Arg("command")}; + if (command != "add" && command != "remove") { throw std::runtime_error(help.ToString()); } NodeContext& node = EnsureAnyNodeContext(request.context); @@ -765,25 +762,23 @@ static RPCHelpMan setban() CSubNet subNet; CNetAddr netAddr; - bool isSubnet = false; - - if (request.params[0].get_str().find('/') != std::string::npos) - isSubnet = true; + std::string subnet_arg{help.Arg("subnet")}; + const bool isSubnet{subnet_arg.find('/') != subnet_arg.npos}; if (!isSubnet) { - const std::optional addr{LookupHost(request.params[0].get_str(), false)}; + const std::optional addr{LookupHost(subnet_arg, false)}; if (addr.has_value()) { netAddr = static_cast(MaybeFlipIPv6toCJDNS(CService{addr.value(), /*port=*/0})); } + } else { + subNet = LookupSubNet(subnet_arg); } - else - subNet = LookupSubNet(request.params[0].get_str()); - if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) + if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) { throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet"); + } - if (strCommand == "add") - { + if (command == "add") { if (isSubnet ? banman.IsBanned(subNet) : banman.IsBanned(netAddr)) { throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); } @@ -809,9 +804,7 @@ static RPCHelpMan setban() node.connman->DisconnectNode(netAddr); } } - } - else if(strCommand == "remove") - { + } else if(command == "remove") { if (!( isSubnet ? banman.Unban(subNet) : banman.Unban(netAddr) )) { throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously manually banned."); } @@ -1051,11 +1044,11 @@ static RPCHelpMan sendmsgtopeer() HelpExampleCli("sendmsgtopeer", "0 \"addr\" \"ffffff\"") + HelpExampleRpc("sendmsgtopeer", "0 \"addr\" \"ffffff\"")}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const NodeId peer_id{request.params[0].getInt()}; - const std::string& msg_type{request.params[1].get_str()}; + const auto msg_type{self.Arg("msg_type")}; if (msg_type.size() > CMessageHeader::MESSAGE_TYPE_SIZE) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Error: msg_type too long, max length is %i", CMessageHeader::MESSAGE_TYPE_SIZE)); } - auto msg{TryParseHex(request.params[2].get_str())}; + auto msg{TryParseHex(self.Arg("msg"))}; if (!msg.has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Error parsing input for msg"); } diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index a5da8785df4..c922b27f688 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #ifdef HAVE_MALLOC_INFO #include #endif +#include using node::NodeContext; @@ -176,7 +178,7 @@ static RPCHelpMan getmemoryinfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str(); + auto mode{self.Arg("mode")}; if (mode == "stats") { UniValue obj(UniValue::VOBJ); obj.pushKV("locked", RPCLockedMemoryInfo()); @@ -188,7 +190,7 @@ static RPCHelpMan getmemoryinfo() throw JSONRPCError(RPC_INVALID_PARAMETER, "mallocinfo mode not available"); #endif } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode); + throw JSONRPCError(RPC_INVALID_PARAMETER, tfm::format("unknown mode %s", mode)); } }, }; @@ -385,7 +387,7 @@ static RPCHelpMan getindexinfo() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { UniValue result(UniValue::VOBJ); - const std::string index_name = request.params[0].isNull() ? "" : request.params[0].get_str(); + const std::string index_name{self.MaybeArg("index_name").value_or("")}; if (g_txindex) { result.pushKVs(SummaryToJSON(g_txindex->GetSummary(), index_name)); diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp index 43624c98eac..5c1151f0e0b 100644 --- a/src/rpc/output_script.cpp +++ b/src/rpc/output_script.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -130,20 +131,17 @@ static RPCHelpMan createmultisig() } // Get the output type - OutputType output_type = OutputType::LEGACY; - if (!request.params[2].isNull()) { - std::optional parsed = ParseOutputType(request.params[2].get_str()); - if (!parsed) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[2].get_str())); - } else if (parsed.value() == OutputType::BECH32M) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "createmultisig cannot create bech32m multisig addresses"); - } - output_type = parsed.value(); + auto address_type{self.Arg("address_type")}; + auto output_type{ParseOutputType(address_type)}; + if (!output_type) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, tfm::format("Unknown address type '%s'", address_type)); + } else if (output_type.value() == OutputType::BECH32M) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "createmultisig cannot create bech32m multisig addresses"); } FlatSigningProvider keystore; CScript inner; - const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner); + const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type.value(), keystore, inner); // Make the descriptor std::unique_ptr descriptor = InferDescriptor(GetScriptForDestination(dest), keystore); @@ -154,7 +152,7 @@ static RPCHelpMan createmultisig() result.pushKV("descriptor", descriptor->ToString()); UniValue warnings(UniValue::VARR); - if (descriptor->GetOutputType() != output_type) { + if (descriptor->GetOutputType() != output_type.value()) { // Only warns if the user has explicitly chosen an address type we cannot generate warnings.push_back("Unable to make chosen address type, please ensure no uncompressed public keys are present."); } @@ -198,7 +196,7 @@ static RPCHelpMan getdescriptorinfo() { FlatSigningProvider provider; std::string error; - auto descs = Parse(request.params[0].get_str(), provider, error); + auto descs = Parse(self.Arg("descriptor"), provider, error); if (descs.empty()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } @@ -303,7 +301,7 @@ static RPCHelpMan deriveaddresses() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const std::string desc_str = request.params[0].get_str(); + auto desc_str{self.Arg("descriptor")}; int64_t range_begin = 0; int64_t range_end = 0; diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 2edf13fd236..5fd733d056b 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include using util::SplitString; @@ -65,7 +66,7 @@ struct RPCCommandExecution } }; -std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const +std::string CRPCTable::help(std::string_view strCommand, const JSONRPCRequest& helpreq) const { std::string strRet; std::string category; @@ -130,16 +131,13 @@ static RPCHelpMan help() RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue { - std::string strCommand; - if (jsonRequest.params.size() > 0) { - strCommand = jsonRequest.params[0].get_str(); - } - if (strCommand == "dump_all_command_conversions") { + auto command{self.MaybeArg("command")}; + if (command == "dump_all_command_conversions") { // Used for testing only, undocumented return tableRPC.dumpArgMap(jsonRequest); } - return tableRPC.help(strCommand, jsonRequest); + return tableRPC.help(command.value_or(""), jsonRequest); }, }; } diff --git a/src/rpc/server.h b/src/rpc/server.h index 84accccba9e..cb68c1def79 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -89,7 +89,7 @@ private: std::map> mapCommands; public: CRPCTable(); - std::string help(const std::string& name, const JSONRPCRequest& helpreq) const; + std::string help(std::string_view name, const JSONRPCRequest& helpreq) const; /** * Execute a method. diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index dbe90d93fb4..4813324c050 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -724,6 +724,7 @@ static void CheckRequiredOrDefault(const RPCArg& param) TMPL_INST(nullptr, const UniValue*, maybe_arg;); TMPL_INST(nullptr, std::optional, maybe_arg ? std::optional{maybe_arg->get_real()} : std::nullopt;); TMPL_INST(nullptr, std::optional, maybe_arg ? std::optional{maybe_arg->get_bool()} : std::nullopt;); +TMPL_INST(nullptr, std::optional, maybe_arg ? std::optional{maybe_arg->getInt()} : std::nullopt;); TMPL_INST(nullptr, std::optional, maybe_arg ? std::optional{maybe_arg->get_str()} : std::nullopt;); // Required arg or optional arg with default value.