Merge #10783: [RPC] Various rpc argument fixes

4dc1915 check for null values in rpc args and handle appropriately (Gregory Sanders)
999ef20 importmulti options are optional (Gregory Sanders)
a70d025 fixup some rpc param counting for rpc help (Gregory Sanders)

Pull request description:

  Audited where named args will fail to use correct default values or may fail when additional optional arguments are added.

  Previously for these parameters, it was fine to omit them as positional arguments, but it would trigger UniValue runtime errors to set them to null, or to omit them while passing named parameters with greater positions (which would internally set earlier missing arguments to null). Now null values are treated the same as missing values so these errors do not occur.

  Included a few other small fixes while working on it.

  I didn't bother fixing account-based rpc calls.

Tree-SHA512: 8baf781a35bd48de7878d4726850a580dab80323d3416c1c146b4fa9062f8a233c03f37e8ae3f3159e9d04a8f39c326627ca64c14e1cb7ce72538f934ab2ae1e
This commit is contained in:
Wladimir J. van der Laan 2017-07-20 17:01:51 +02:00
commit 041dad94b0
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
6 changed files with 51 additions and 51 deletions

View file

@ -210,7 +210,7 @@ UniValue waitfornewblock(const JSONRPCRequest& request)
+ HelpExampleRpc("waitfornewblock", "1000") + HelpExampleRpc("waitfornewblock", "1000")
); );
int timeout = 0; int timeout = 0;
if (request.params.size() > 0) if (!request.params[0].isNull())
timeout = request.params[0].get_int(); timeout = request.params[0].get_int();
CUpdatedBlock block; CUpdatedBlock block;
@ -252,7 +252,7 @@ UniValue waitforblock(const JSONRPCRequest& request)
uint256 hash = uint256S(request.params[0].get_str()); uint256 hash = uint256S(request.params[0].get_str());
if (request.params.size() > 1) if (!request.params[1].isNull())
timeout = request.params[1].get_int(); timeout = request.params[1].get_int();
CUpdatedBlock block; CUpdatedBlock block;
@ -295,7 +295,7 @@ UniValue waitforblockheight(const JSONRPCRequest& request)
int height = request.params[0].get_int(); int height = request.params[0].get_int();
if (request.params.size() > 1) if (!request.params[1].isNull())
timeout = request.params[1].get_int(); timeout = request.params[1].get_int();
CUpdatedBlock block; CUpdatedBlock block;
@ -434,7 +434,7 @@ UniValue getrawmempool(const JSONRPCRequest& request)
); );
bool fVerbose = false; bool fVerbose = false;
if (request.params.size() > 0) if (!request.params[0].isNull())
fVerbose = request.params[0].get_bool(); fVerbose = request.params[0].get_bool();
return mempoolToJSON(fVerbose); return mempoolToJSON(fVerbose);
@ -467,7 +467,7 @@ UniValue getmempoolancestors(const JSONRPCRequest& request)
} }
bool fVerbose = false; bool fVerbose = false;
if (request.params.size() > 1) if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool(); fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1"); uint256 hash = ParseHashV(request.params[0], "parameter 1");
@ -531,7 +531,7 @@ UniValue getmempooldescendants(const JSONRPCRequest& request)
} }
bool fVerbose = false; bool fVerbose = false;
if (request.params.size() > 1) if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool(); fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1"); uint256 hash = ParseHashV(request.params[0], "parameter 1");
@ -666,7 +666,7 @@ UniValue getblockheader(const JSONRPCRequest& request)
uint256 hash(uint256S(strHash)); uint256 hash(uint256S(strHash));
bool fVerbose = true; bool fVerbose = true;
if (request.params.size() > 1) if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool(); fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0) if (mapBlockIndex.count(hash) == 0)
@ -741,7 +741,7 @@ UniValue getblock(const JSONRPCRequest& request)
uint256 hash(uint256S(strHash)); uint256 hash(uint256S(strHash));
int verbosity = 1; int verbosity = 1;
if (request.params.size() > 1) { if (!request.params[1].isNull()) {
if(request.params[1].isNum()) if(request.params[1].isNum())
verbosity = request.params[1].get_int(); verbosity = request.params[1].get_int();
else else
@ -984,7 +984,7 @@ UniValue gettxout(const JSONRPCRequest& request)
int n = request.params[1].get_int(); int n = request.params[1].get_int();
COutPoint out(hash, n); COutPoint out(hash, n);
bool fMempool = true; bool fMempool = true;
if (request.params.size() > 2) if (!request.params[2].isNull())
fMempool = request.params[2].get_bool(); fMempool = request.params[2].get_bool();
Coin coin; Coin coin;
@ -1037,9 +1037,9 @@ UniValue verifychain(const JSONRPCRequest& request)
LOCK(cs_main); LOCK(cs_main);
if (request.params.size() > 0) if (!request.params[0].isNull())
nCheckLevel = request.params[0].get_int(); nCheckLevel = request.params[0].get_int();
if (request.params.size() > 1) if (!request.params[1].isNull())
nCheckDepth = request.params[1].get_int(); nCheckDepth = request.params[1].get_int();
return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth); return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);

View file

@ -102,7 +102,7 @@ UniValue getnetworkhashps(const JSONRPCRequest& request)
); );
LOCK(cs_main); LOCK(cs_main);
return GetNetworkHashPS(request.params.size() > 0 ? request.params[0].get_int() : 120, request.params.size() > 1 ? request.params[1].get_int() : -1); return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1);
} }
UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript) UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
@ -172,7 +172,7 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
int nGenerate = request.params[0].get_int(); int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000; uint64_t nMaxTries = 1000000;
if (request.params.size() > 2) { if (!request.params[2].isNull()) {
nMaxTries = request.params[2].get_int(); nMaxTries = request.params[2].get_int();
} }
@ -374,7 +374,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
UniValue lpval = NullUniValue; UniValue lpval = NullUniValue;
std::set<std::string> setClientRules; std::set<std::string> setClientRules;
int64_t nMaxVersionPreVB = -1; int64_t nMaxVersionPreVB = -1;
if (request.params.size() > 0) if (!request.params[0].isNull())
{ {
const UniValue& oparam = request.params[0].get_obj(); const UniValue& oparam = request.params[0].get_obj();
const UniValue& modeval = find_value(oparam, "mode"); const UniValue& modeval = find_value(oparam, "mode");

View file

@ -310,7 +310,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo(); std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
if (request.params.size() == 1) { if (request.params.size() == 1 && !request.params[0].isNull()) {
bool found = false; bool found = false;
for (const AddedNodeInfo& info : vInfo) { for (const AddedNodeInfo& info : vInfo) {
if (info.strAddedNode == request.params[0].get_str()) { if (info.strAddedNode == request.params[0].get_str()) {

View file

@ -137,7 +137,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
// Accept either a bool (true) or a num (>=1) to indicate verbose output. // Accept either a bool (true) or a num (>=1) to indicate verbose output.
bool fVerbose = false; bool fVerbose = false;
if (request.params.size() > 1) { if (!request.params[1].isNull()) {
if (request.params[1].isNum()) { if (request.params[1].isNum()) {
if (request.params[1].get_int() != 0) { if (request.params[1].get_int() != 0) {
fVerbose = true; fVerbose = true;
@ -211,7 +211,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
CBlockIndex* pblockindex = NULL; CBlockIndex* pblockindex = NULL;
uint256 hashBlock; uint256 hashBlock;
if (request.params.size() > 1) if (!request.params[1].isNull())
{ {
hashBlock = uint256S(request.params[1].get_str()); hashBlock = uint256S(request.params[1].get_str());
if (!mapBlockIndex.count(hashBlock)) if (!mapBlockIndex.count(hashBlock))
@ -412,7 +412,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
} }
} }
if (request.params.size() > 3 && rbfOptIn != SignalsOptInRBF(rawTx)) { if (!request.params[3].isNull() && rbfOptIn != SignalsOptInRBF(rawTx)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
} }

View file

@ -106,12 +106,12 @@ UniValue importprivkey(const JSONRPCRequest& request)
std::string strSecret = request.params[0].get_str(); std::string strSecret = request.params[0].get_str();
std::string strLabel = ""; std::string strLabel = "";
if (request.params.size() > 1) if (!request.params[1].isNull())
strLabel = request.params[1].get_str(); strLabel = request.params[1].get_str();
// Whether to perform rescan after import // Whether to perform rescan after import
bool fRescan = true; bool fRescan = true;
if (request.params.size() > 2) if (!request.params[2].isNull())
fRescan = request.params[2].get_bool(); fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode) if (fRescan && fPruneMode)
@ -245,12 +245,12 @@ UniValue importaddress(const JSONRPCRequest& request)
std::string strLabel = ""; std::string strLabel = "";
if (request.params.size() > 1) if (!request.params[1].isNull())
strLabel = request.params[1].get_str(); strLabel = request.params[1].get_str();
// Whether to perform rescan after import // Whether to perform rescan after import
bool fRescan = true; bool fRescan = true;
if (request.params.size() > 2) if (!request.params[2].isNull())
fRescan = request.params[2].get_bool(); fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode) if (fRescan && fPruneMode)
@ -258,7 +258,7 @@ UniValue importaddress(const JSONRPCRequest& request)
// Whether to import a p2sh version, too // Whether to import a p2sh version, too
bool fP2SH = false; bool fP2SH = false;
if (request.params.size() > 3) if (!request.params[3].isNull())
fP2SH = request.params[3].get_bool(); fP2SH = request.params[3].get_bool();
LOCK2(cs_main, pwallet->cs_wallet); LOCK2(cs_main, pwallet->cs_wallet);
@ -410,12 +410,12 @@ UniValue importpubkey(const JSONRPCRequest& request)
std::string strLabel = ""; std::string strLabel = "";
if (request.params.size() > 1) if (!request.params[1].isNull())
strLabel = request.params[1].get_str(); strLabel = request.params[1].get_str();
// Whether to perform rescan after import // Whether to perform rescan after import
bool fRescan = true; bool fRescan = true;
if (request.params.size() > 2) if (!request.params[2].isNull())
fRescan = request.params[2].get_bool(); fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode) if (fRescan && fPruneMode)
@ -1028,7 +1028,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
// clang-format off // clang-format off
if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
throw std::runtime_error( throw std::runtime_error(
"importmulti \"requests\" \"options\"\n\n" "importmulti \"requests\" ( \"options\" )\n\n"
"Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options).\n\n" "Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options).\n\n"
"Arguments:\n" "Arguments:\n"
"1. requests (array, required) Data to be imported\n" "1. requests (array, required) Data to be imported\n"
@ -1071,7 +1071,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
//Default options //Default options
bool fRescan = true; bool fRescan = true;
if (mainRequest.params.size() > 1) { if (!mainRequest.params[1].isNull()) {
const UniValue& options = mainRequest.params[1]; const UniValue& options = mainRequest.params[1];
if (options.exists("rescan")) { if (options.exists("rescan")) {

View file

@ -146,7 +146,7 @@ UniValue getnewaddress(const JSONRPCRequest& request)
// Parse the account first so we don't generate a key if there's an error // Parse the account first so we don't generate a key if there's an error
std::string strAccount; std::string strAccount;
if (request.params.size() > 0) if (!request.params[0].isNull())
strAccount = AccountFromValue(request.params[0]); strAccount = AccountFromValue(request.params[0]);
if (!pwallet->IsLocked()) { if (!pwallet->IsLocked()) {
@ -217,7 +217,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
return NullUniValue; return NullUniValue;
} }
if (request.fHelp || request.params.size() > 1) if (request.fHelp || request.params.size() > 0)
throw std::runtime_error( throw std::runtime_error(
"getrawchangeaddress\n" "getrawchangeaddress\n"
"\nReturns a new Bitcoin address, for receiving change.\n" "\nReturns a new Bitcoin address, for receiving change.\n"
@ -496,7 +496,7 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
return NullUniValue; return NullUniValue;
} }
if (request.fHelp) if (request.fHelp || request.params.size() != 0)
throw std::runtime_error( throw std::runtime_error(
"listaddressgroupings\n" "listaddressgroupings\n"
"\nLists groups of addresses which have had their common ownership\n" "\nLists groups of addresses which have had their common ownership\n"
@ -641,7 +641,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
// Minimum confirmations // Minimum confirmations
int nMinDepth = 1; int nMinDepth = 1;
if (request.params.size() > 1) if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int(); nMinDepth = request.params[1].get_int();
// Tally // Tally
@ -692,7 +692,7 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
// Minimum confirmations // Minimum confirmations
int nMinDepth = 1; int nMinDepth = 1;
if (request.params.size() > 1) if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int(); nMinDepth = request.params[1].get_int();
// Get the set of pub keys assigned to account // Get the set of pub keys assigned to account
@ -769,10 +769,10 @@ UniValue getbalance(const JSONRPCRequest& request)
const std::string* account = account_param != "*" ? &account_param : nullptr; const std::string* account = account_param != "*" ? &account_param : nullptr;
int nMinDepth = 1; int nMinDepth = 1;
if (request.params.size() > 1) if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int(); nMinDepth = request.params[1].get_int();
isminefilter filter = ISMINE_SPENDABLE; isminefilter filter = ISMINE_SPENDABLE;
if(request.params.size() > 2) if(!request.params[2].isNull())
if(request.params[2].get_bool()) if(request.params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY; filter = filter | ISMINE_WATCH_ONLY;
@ -975,7 +975,7 @@ UniValue sendmany(const JSONRPCRequest& request)
std::string strAccount = AccountFromValue(request.params[0]); std::string strAccount = AccountFromValue(request.params[0]);
UniValue sendTo = request.params[1].get_obj(); UniValue sendTo = request.params[1].get_obj();
int nMinDepth = 1; int nMinDepth = 1;
if (request.params.size() > 2) if (!request.params[2].isNull())
nMinDepth = request.params[2].get_int(); nMinDepth = request.params[2].get_int();
CWalletTx wtx; CWalletTx wtx;
@ -1222,16 +1222,16 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
{ {
// Minimum confirmations // Minimum confirmations
int nMinDepth = 1; int nMinDepth = 1;
if (params.size() > 0) if (!params[0].isNull())
nMinDepth = params[0].get_int(); nMinDepth = params[0].get_int();
// Whether to include empty accounts // Whether to include empty accounts
bool fIncludeEmpty = false; bool fIncludeEmpty = false;
if (params.size() > 1) if (!params[1].isNull())
fIncludeEmpty = params[1].get_bool(); fIncludeEmpty = params[1].get_bool();
isminefilter filter = ISMINE_SPENDABLE; isminefilter filter = ISMINE_SPENDABLE;
if(params.size() > 2) if(!params[2].isNull())
if(params[2].get_bool()) if(params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY; filter = filter | ISMINE_WATCH_ONLY;
@ -1593,16 +1593,16 @@ UniValue listtransactions(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet); LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = "*"; std::string strAccount = "*";
if (request.params.size() > 0) if (!request.params[0].isNull())
strAccount = request.params[0].get_str(); strAccount = request.params[0].get_str();
int nCount = 10; int nCount = 10;
if (request.params.size() > 1) if (!request.params[1].isNull())
nCount = request.params[1].get_int(); nCount = request.params[1].get_int();
int nFrom = 0; int nFrom = 0;
if (request.params.size() > 2) if (!request.params[2].isNull())
nFrom = request.params[2].get_int(); nFrom = request.params[2].get_int();
isminefilter filter = ISMINE_SPENDABLE; isminefilter filter = ISMINE_SPENDABLE;
if(request.params.size() > 3) if(!request.params[3].isNull())
if(request.params[3].get_bool()) if(request.params[3].get_bool())
filter = filter | ISMINE_WATCH_ONLY; filter = filter | ISMINE_WATCH_ONLY;
@ -1742,7 +1742,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
return NullUniValue; return NullUniValue;
} }
if (request.fHelp) if (request.fHelp || request.params.size() > 3)
throw std::runtime_error( throw std::runtime_error(
"listsinceblock ( \"blockhash\" target_confirmations include_watchonly)\n" "listsinceblock ( \"blockhash\" target_confirmations include_watchonly)\n"
"\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n" "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
@ -1789,7 +1789,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
int target_confirms = 1; int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE; isminefilter filter = ISMINE_SPENDABLE;
if (request.params.size() > 0) if (!request.params[0].isNull())
{ {
uint256 blockId; uint256 blockId;
@ -1808,7 +1808,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
} }
} }
if (request.params.size() > 1) if (!request.params[1].isNull())
{ {
target_confirms = request.params[1].get_int(); target_confirms = request.params[1].get_int();
@ -1900,7 +1900,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
hash.SetHex(request.params[0].get_str()); hash.SetHex(request.params[0].get_str());
isminefilter filter = ISMINE_SPENDABLE; isminefilter filter = ISMINE_SPENDABLE;
if(request.params.size() > 1) if(!request.params[1].isNull())
if(request.params[1].get_bool()) if(request.params[1].get_bool())
filter = filter | ISMINE_WATCH_ONLY; filter = filter | ISMINE_WATCH_ONLY;
@ -2022,7 +2022,7 @@ UniValue keypoolrefill(const JSONRPCRequest& request)
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
unsigned int kpSize = 0; unsigned int kpSize = 0;
if (request.params.size() > 0) { if (!request.params[0].isNull()) {
if (request.params[0].get_int() < 0) if (request.params[0].get_int() < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size."); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
kpSize = (unsigned int)request.params[0].get_int(); kpSize = (unsigned int)request.params[0].get_int();
@ -2615,7 +2615,7 @@ UniValue listunspent(const JSONRPCRequest& request)
CAmount nMinimumSumAmount = MAX_MONEY; CAmount nMinimumSumAmount = MAX_MONEY;
uint64_t nMaximumCount = 0; uint64_t nMaximumCount = 0;
if (request.params.size() > 4) { if (!request.params[4].isNull()) {
const UniValue& options = request.params[4].get_obj(); const UniValue& options = request.params[4].get_obj();
if (options.exists("minimumAmount")) if (options.exists("minimumAmount"))
@ -2684,7 +2684,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
return NullUniValue; return NullUniValue;
} }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error( throw std::runtime_error(
"fundrawtransaction \"hexstring\" ( options )\n" "fundrawtransaction \"hexstring\" ( options )\n"
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n" "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
@ -2746,7 +2746,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
UniValue subtractFeeFromOutputs; UniValue subtractFeeFromOutputs;
std::set<int> setSubtractFeeFromOutputs; std::set<int> setSubtractFeeFromOutputs;
if (request.params.size() > 1) { if (!request.params[1].isNull()) {
if (request.params[1].type() == UniValue::VBOOL) { if (request.params[1].type() == UniValue::VBOOL) {
// backward compatibility bool only fallback // backward compatibility bool only fallback
coinControl.fAllowWatchOnly = request.params[1].get_bool(); coinControl.fAllowWatchOnly = request.params[1].get_bool();
@ -2911,7 +2911,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
CAmount totalFee = 0; CAmount totalFee = 0;
CCoinControl coin_control; CCoinControl coin_control;
coin_control.signalRbf = true; coin_control.signalRbf = true;
if (request.params.size() > 1) { if (!request.params[1].isNull()) {
UniValue options = request.params[1]; UniValue options = request.params[1];
RPCTypeCheckObj(options, RPCTypeCheckObj(options,
{ {