Merge #11050: Avoid treating null RPC arguments different from missing arguments

745d2e3 Clean up getbalance RPC parameter handling (Russell Yanofsky)
fd5d71e Update developer notes after params.size() cleanup (Russell Yanofsky)
e067673 Avoid treating null RPC arguments different from missing arguments (Russell Yanofsky)
e666efc Get rid of redundant RPC params.size() checks (Russell Yanofsky)

Pull request description:

  This is a followup to #10783.

  - The first commit doesn't change behavior at all, just simplifies code.
  - The second commit just changes RPC methods to treat null arguments the same as missing arguments instead of throwing type errors.
  - The third commit updates developer notes after the cleanup.
  - The forth commit does some additional code cleanup in `getbalance`.

  Followup changes that should happen in future PRs:

  - [ ] Replace uses of `.isTrue()` with calls to `.get_bool()` so numbers, objects, and strings cause type errors instead of being interpreted as false. https://github.com/bitcoin/bitcoin/pull/11050#discussion_r133850525
  - [ ] Add braces around if statements. https://github.com/bitcoin/bitcoin/pull/11050#discussion_r133851133
  - [ ] Maybe improve UniValue type error exceptions and eliminate RPCTypeCheck and RPCTypeCheckArgument functions. https://github.com/bitcoin/bitcoin/pull/11050#discussion_r133829303

Tree-SHA512: e72f696011d20acc0778e996659e41f9426bffce387b29ff63bf59ad1163d5146761e4445b2b9b9e069a80596a57c7f4402b75a15d5d20f69f775ae558cf67e9
This commit is contained in:
Wladimir J. van der Laan
2017-08-22 09:24:31 +02:00
7 changed files with 71 additions and 61 deletions

View File

@@ -280,7 +280,7 @@ UniValue setaccount(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
std::string strAccount;
if (request.params.size() > 1)
if (!request.params[1].isNull())
strAccount = AccountFromValue(request.params[1]);
// Only add the account if the address is yours.
@@ -462,26 +462,26 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
// Wallet comments
CWalletTx wtx;
if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty())
if (!request.params[2].isNull() && !request.params[2].get_str().empty())
wtx.mapValue["comment"] = request.params[2].get_str();
if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
if (request.params.size() > 4 && !request.params[4].isNull()) {
if (!request.params[4].isNull()) {
fSubtractFeeFromAmount = request.params[4].get_bool();
}
CCoinControl coin_control;
if (request.params.size() > 5 && !request.params[5].isNull()) {
if (!request.params[5].isNull()) {
coin_control.signalRbf = request.params[5].get_bool();
}
if (request.params.size() > 6 && !request.params[6].isNull()) {
if (!request.params[6].isNull()) {
coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
if (request.params.size() > 7 && !request.params[7].isNull()) {
if (!request.params[7].isNull()) {
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
@@ -768,18 +768,31 @@ UniValue getbalance(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
if (request.params.size() == 0)
return ValueFromAmount(pwallet->GetBalance());
const UniValue& account_value = request.params[0];
const UniValue& minconf = request.params[1];
const UniValue& include_watchonly = request.params[2];
const std::string& account_param = request.params[0].get_str();
if (account_value.isNull()) {
if (!minconf.isNull()) {
throw JSONRPCError(RPC_INVALID_PARAMETER,
"getbalance minconf option is only currently supported if an account is specified");
}
if (!include_watchonly.isNull()) {
throw JSONRPCError(RPC_INVALID_PARAMETER,
"getbalance include_watchonly option is only currently supported if an account is specified");
}
return ValueFromAmount(pwallet->GetBalance());
}
const std::string& account_param = account_value.get_str();
const std::string* account = account_param != "*" ? &account_param : nullptr;
int nMinDepth = 1;
if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int();
if (!minconf.isNull())
nMinDepth = minconf.get_int();
isminefilter filter = ISMINE_SPENDABLE;
if(!request.params[2].isNull())
if(request.params[2].get_bool())
if(!include_watchonly.isNull())
if(include_watchonly.get_bool())
filter = filter | ISMINE_WATCH_ONLY;
return ValueFromAmount(pwallet->GetLegacyBalance(filter, nMinDepth, account));
@@ -838,11 +851,11 @@ UniValue movecmd(const JSONRPCRequest& request)
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
if (request.params.size() > 3)
if (!request.params[3].isNull())
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)request.params[3].get_int();
std::string strComment;
if (request.params.size() > 4)
if (!request.params[4].isNull())
strComment = request.params[4].get_str();
if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) {
@@ -899,14 +912,14 @@ UniValue sendfrom(const JSONRPCRequest& request)
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
if (request.params.size() > 3)
if (!request.params[3].isNull())
nMinDepth = request.params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
if (request.params.size() > 4 && !request.params[4].isNull() && !request.params[4].get_str().empty())
if (!request.params[4].isNull() && !request.params[4].get_str().empty())
wtx.mapValue["comment"] = request.params[4].get_str();
if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty())
if (!request.params[5].isNull() && !request.params[5].get_str().empty())
wtx.mapValue["to"] = request.params[5].get_str();
EnsureWalletIsUnlocked(pwallet);
@@ -986,23 +999,23 @@ UniValue sendmany(const JSONRPCRequest& request)
CWalletTx wtx;
wtx.strFromAccount = strAccount;
if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
if (request.params.size() > 4 && !request.params[4].isNull())
if (!request.params[4].isNull())
subtractFeeFromAmount = request.params[4].get_array();
CCoinControl coin_control;
if (request.params.size() > 5 && !request.params[5].isNull()) {
if (!request.params[5].isNull()) {
coin_control.signalRbf = request.params[5].get_bool();
}
if (request.params.size() > 6 && !request.params[6].isNull()) {
if (!request.params[6].isNull()) {
coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
if (request.params.size() > 7 && !request.params[7].isNull()) {
if (!request.params[7].isNull()) {
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
@@ -1105,7 +1118,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount;
if (request.params.size() > 2)
if (!request.params[2].isNull())
strAccount = AccountFromValue(request.params[2]);
// Construct using pay-to-script-hash:
@@ -1711,10 +1724,10 @@ UniValue listaccounts(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
int nMinDepth = 1;
if (request.params.size() > 0)
if (!request.params[0].isNull())
nMinDepth = request.params[0].get_int();
isminefilter includeWatchonly = ISMINE_SPENDABLE;
if(request.params.size() > 1)
if(!request.params[1].isNull())
if(request.params[1].get_bool())
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
@@ -2363,19 +2376,18 @@ UniValue lockunspent(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
if (request.params.size() == 1)
RPCTypeCheck(request.params, {UniValue::VBOOL});
else
RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VARR});
RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
bool fUnlock = request.params[0].get_bool();
if (request.params.size() == 1) {
if (request.params[1].isNull()) {
if (fUnlock)
pwallet->UnlockAllCoins();
return true;
}
RPCTypeCheckArgument(request.params[1], UniValue::VARR);
UniValue outputs = request.params[1].get_array();
for (unsigned int idx = 0; idx < outputs.size(); idx++) {
const UniValue& output = outputs[idx];
@@ -2672,19 +2684,19 @@ UniValue listunspent(const JSONRPCRequest& request)
);
int nMinDepth = 1;
if (request.params.size() > 0 && !request.params[0].isNull()) {
if (!request.params[0].isNull()) {
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
nMinDepth = request.params[0].get_int();
}
int nMaxDepth = 9999999;
if (request.params.size() > 1 && !request.params[1].isNull()) {
if (!request.params[1].isNull()) {
RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
nMaxDepth = request.params[1].get_int();
}
std::set<CBitcoinAddress> setAddress;
if (request.params.size() > 2 && !request.params[2].isNull()) {
if (!request.params[2].isNull()) {
RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.params[2].get_array();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
@@ -2699,7 +2711,7 @@ UniValue listunspent(const JSONRPCRequest& request)
}
bool include_unsafe = true;
if (request.params.size() > 3 && !request.params[3].isNull()) {
if (!request.params[3].isNull()) {
RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
include_unsafe = request.params[3].get_bool();
}
@@ -3114,7 +3126,7 @@ UniValue generate(const JSONRPCRequest& request)
int num_generate = request.params[0].get_int();
uint64_t max_tries = 1000000;
if (request.params.size() > 1 && !request.params[1].isNull()) {
if (!request.params[1].isNull()) {
max_tries = request.params[1].get_int();
}