rpc: refactor: use more (Maybe)Arg<std::string_view>

Use the {Arg,MaybeArg}<std::string_view> helper in all places where
it is a trivial change. In many places, this simplifies the logic
and reduces duplication of default values.
This commit is contained in:
stickies-v
2025-07-15 22:23:44 +01:00
parent 037830ca0d
commit b63428ac9c
9 changed files with 69 additions and 79 deletions

View File

@@ -40,6 +40,7 @@
#include <serialize.h>
#include <streams.h>
#include <sync.h>
#include <tinyformat.h>
#include <txdb.h>
#include <txmempool.h>
#include <undo.h>
@@ -60,6 +61,7 @@
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
@@ -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<std::string_view>("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<std::string_view>("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<std::string_view>("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<std::string_view>("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<std::string_view>("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(

View File

@@ -21,6 +21,7 @@
#include <array>
#include <cmath>
#include <string>
#include <string_view>
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<std::string_view>("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()};

View File

@@ -28,6 +28,7 @@
#include <util/time.h>
#include <util/vector.h>
#include <string_view>
#include <utility>
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<std::string_view>("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"]};

View File

@@ -36,11 +36,11 @@
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
using node::NodeContext;
using util::Join;
using util::TrimString;
const std::vector<std::string> 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<std::string_view>("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<std::string_view>("address")};
auto node_id{self.MaybeArg<int64_t>("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<int64_t>();
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<AddedNodeInfo> vInfo = connman.GetAddedNodeInfo(/*include_connected=*/true);
if (!request.params[0].isNull()) {
if (auto node{self.MaybeArg<std::string_view>("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<std::string_view>("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<std::string_view>("subnet")};
const bool isSubnet{subnet_arg.find('/') != subnet_arg.npos};
if (!isSubnet) {
const std::optional<CNetAddr> addr{LookupHost(request.params[0].get_str(), false)};
const std::optional<CNetAddr> addr{LookupHost(subnet_arg, false)};
if (addr.has_value()) {
netAddr = static_cast<CNetAddr>(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<int64_t>()};
const std::string& msg_type{request.params[1].get_str()};
const auto msg_type{self.Arg<std::string_view>("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<unsigned char>(request.params[2].get_str())};
auto msg{TryParseHex<unsigned char>(self.Arg<std::string_view>("msg"))};
if (!msg.has_value()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Error parsing input for msg");
}

View File

@@ -21,6 +21,7 @@
#include <rpc/server_util.h>
#include <rpc/util.h>
#include <scheduler.h>
#include <tinyformat.h>
#include <univalue.h>
#include <util/any.h>
#include <util/check.h>
@@ -30,6 +31,7 @@
#ifdef HAVE_MALLOC_INFO
#include <malloc.h>
#endif
#include <string_view>
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<std::string_view>("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<std::string_view>("index_name").value_or("")};
if (g_txindex) {
result.pushKVs(SummaryToJSON(g_txindex->GetSummary(), index_name));

View File

@@ -22,6 +22,7 @@
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
@@ -130,20 +131,17 @@ static RPCHelpMan createmultisig()
}
// Get the output type
OutputType output_type = OutputType::LEGACY;
if (!request.params[2].isNull()) {
std::optional<OutputType> 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<std::string_view>("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> 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<std::string_view>("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<std::string_view>("descriptor")};
int64_t range_begin = 0;
int64_t range_end = 0;

View File

@@ -26,6 +26,7 @@
#include <chrono>
#include <memory>
#include <mutex>
#include <string_view>
#include <unordered_map>
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<std::string_view>("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);
},
};
}

View File

@@ -89,7 +89,7 @@ private:
std::map<std::string, std::vector<const CRPCCommand*>> 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.

View File

@@ -724,6 +724,7 @@ static void CheckRequiredOrDefault(const RPCArg& param)
TMPL_INST(nullptr, const UniValue*, maybe_arg;);
TMPL_INST(nullptr, std::optional<double>, maybe_arg ? std::optional{maybe_arg->get_real()} : std::nullopt;);
TMPL_INST(nullptr, std::optional<bool>, maybe_arg ? std::optional{maybe_arg->get_bool()} : std::nullopt;);
TMPL_INST(nullptr, std::optional<int64_t>, maybe_arg ? std::optional{maybe_arg->getInt<int64_t>()} : std::nullopt;);
TMPL_INST(nullptr, std::optional<std::string_view>, maybe_arg ? std::optional<std::string_view>{maybe_arg->get_str()} : std::nullopt;);
// Required arg or optional arg with default value.