Skip to content

Commit

Permalink
Merge bitcoin#11050: Avoid treating null RPC arguments different from…
Browse files Browse the repository at this point in the history
… 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 bitcoin#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. bitcoin#11050 (comment)
  - [ ] Add braces around if statements. bitcoin#11050 (comment)
  - [ ] Maybe improve UniValue type error exceptions and eliminate RPCTypeCheck and RPCTypeCheckArgument functions. bitcoin#11050 (comment)

Tree-SHA512: e72f696011d20acc0778e996659e41f9426bffce387b29ff63bf59ad1163d5146761e4445b2b9b9e069a80596a57c7f4402b75a15d5d20f69f775ae558cf67e9

More of 11050

Fixes for bitcoin#11050 backport

Fixes for bitcoin#11050
  • Loading branch information
laanwj authored and PastaPastaPasta committed Jan 2, 2020
1 parent 63f6041 commit 77b48b2
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 119 deletions.
10 changes: 4 additions & 6 deletions doc/developer-notes.md
Expand Up @@ -589,16 +589,14 @@ A few guidelines for introducing and reviewing new RPC interfaces:
is specified as-is in BIP22.

- Missing arguments and 'null' should be treated the same: as default values. If there is no
default value, both cases should fail in the same way.
default value, both cases should fail in the same way. The easiest way to follow this
guideline is detect unspecified arguments with `params[x].isNull()` instead of
`params.size() <= x`. The former returns true if the argument is either null or missing,
while the latter returns true if is missing, and false if it is null.

- *Rationale*: Avoids surprises when switching to name-based arguments. Missing name-based arguments
are passed as 'null'.

- *Exception*: Many legacy exceptions to this exist, one of the worst ones is
`getbalance` which follows a completely different code path based on the
number of arguments. We are still in the process of cleaning these up. Do not introduce
new ones.

- Try not to overload methods on argument type. E.g. don't make `getblock(true)` and `getblock("hash")`
do different things.

Expand Down
22 changes: 11 additions & 11 deletions src/rpc/blockchain.cpp
Expand Up @@ -826,14 +826,14 @@ UniValue getblockheaders(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

int nCount = MAX_HEADERS_RESULTS;
if (request.params.size() > 1)
if (!request.params[1].isNull())
nCount = request.params[1].get_int();

if (nCount <= 0 || nCount > (int)MAX_HEADERS_RESULTS)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Count is out of range");

bool fVerbose = true;
if (request.params.size() > 2)
if (!request.params[2].isNull())
fVerbose = request.params[2].get_bool();

CBlockIndex* pblockindex = mapBlockIndex[hash];
Expand Down Expand Up @@ -923,7 +923,7 @@ UniValue getmerkleblocks(const JSONRPCRequest& request)
}

int nCount = MAX_HEADERS_RESULTS;
if (request.params.size() > 2)
if (!request.params[2].isNull())
nCount = request.params[2].get_int();

if (nCount <= 0 || nCount > (int)MAX_HEADERS_RESULTS) {
Expand Down Expand Up @@ -1565,10 +1565,10 @@ UniValue getchaintips(const JSONRPCRequest& request)
int nBranchMin = -1;
int nCountMax = INT_MAX;

if(request.params.size() >= 1)
if(!request.params[0].isNull())
nCountMax = request.params[0].get_int();

if(request.params.size() == 2)
if(!request.params[1].isNull())
nBranchMin = request.params[1].get_int();

/* Construct the output array. */
Expand Down Expand Up @@ -1790,11 +1790,11 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month

if (request.params.size() > 0 && !request.params[0].isNull()) {
if (!request.params[0].isNull()) {
blockcount = request.params[0].get_int();
}

bool havehash = request.params.size() > 1 && !request.params[1].isNull();
bool havehash = !request.params[1].isNull();
uint256 hash;
if (havehash) {
hash = uint256S(request.params[1].get_str());
Expand Down Expand Up @@ -2123,26 +2123,26 @@ UniValue getspecialtxes(const JSONRPCRequest& request)
uint256 hash(uint256S(strHash));

int nTxType = -1;
if (request.params.size() > 1) {
if (!request.params[1].isNull()) {
nTxType = request.params[1].get_int();
}

int nCount = 10;
if (request.params.size() > 2) {
if (!request.params[2].isNull()) {
nCount = request.params[2].get_int();
if (nCount < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
}

int nSkip = 0;
if (request.params.size() > 3) {
if (!request.params[3].isNull()) {
nSkip = request.params[3].get_int();
if (nSkip < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative skip");
}

int nVerbosity = 0;
if (request.params.size() > 4) {
if (!request.params[4].isNull()) {
nVerbosity = request.params[4].get_int();
if (nVerbosity < 0 || nVerbosity > 2) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbosity must be in range 0..2");
Expand Down
30 changes: 20 additions & 10 deletions src/rpc/governance.cpp
Expand Up @@ -38,7 +38,7 @@ UniValue gobject_count(const JSONRPCRequest& request)

std::string strMode{"json"};

if (request.params.size() == 2) {
if (!request.params[1].isNull()) {
strMode = request.params[1].get_str();
}

Expand Down Expand Up @@ -195,7 +195,7 @@ UniValue gobject_prepare(const JSONRPCRequest& request)
// If specified, spend this outpoint as the proposal fee
COutPoint outpoint;
outpoint.SetNull();
if (request.params.size() == 8) {
if (!request.params[6].isNull() && !request.params[7].isNull()) {
uint256 collateralHash = ParseHashV(request.params[6], "outputHash");
int32_t collateralIndex = ParseInt32V(request.params[7], "outputIndex");
if (collateralHash.IsNull() || collateralIndex < 0) {
Expand All @@ -207,7 +207,9 @@ UniValue gobject_prepare(const JSONRPCRequest& request)
CWalletTx wtx;
if (!pwallet->GetBudgetSystemCollateralTX(wtx, govobj.GetHash(), govobj.GetMinCollateralFee(), outpoint)) {
std::string err = "Error making collateral transaction for governance object. Please check your wallet balance and make sure your wallet is unlocked.";
if (request.params.size() == 8) err += "Please verify your specified output is valid and is enough for the combined proposal fee and transaction fee.";
if (!request.params[6].isNull() && !request.params[7].isNull()) {
err += "Please verify your specified output is valid and is enough for the combined proposal fee and transaction fee.";
}
throw JSONRPCError(RPC_INTERNAL_ERROR, err);
}

Expand Down Expand Up @@ -260,7 +262,7 @@ UniValue gobject_submit(const JSONRPCRequest& request)

uint256 txidFee;

if (request.params.size() == 6) {
if (!request.params[5].isNull()) {
txidFee = ParseHashV(request.params[5], "fee-txid, parameter 6");
}
uint256 hashParent;
Expand Down Expand Up @@ -688,12 +690,16 @@ UniValue gobject_list(const JSONRPCRequest& request)
gobject_list_help();

std::string strCachedSignal = "valid";
if (request.params.size() >= 2) strCachedSignal = request.params[1].get_str();
if (!request.params[1].isNull()) {
strCachedSignal = request.params[1].get_str();
}
if (strCachedSignal != "valid" && strCachedSignal != "funding" && strCachedSignal != "delete" && strCachedSignal != "endorsed" && strCachedSignal != "all")
return "Invalid signal, should be 'valid', 'funding', 'delete', 'endorsed' or 'all'";

std::string strType = "all";
if (request.params.size() == 3) strType = request.params[2].get_str();
if (!request.params[2].isNull()) {
strType = request.params[2].get_str();
}
if (strType != "proposals" && strType != "triggers" && strType != "all")
return "Invalid type, should be 'proposals', 'triggers' or 'all'";

Expand All @@ -717,12 +723,16 @@ UniValue gobject_diff(const JSONRPCRequest& request)
gobject_diff_help();

std::string strCachedSignal = "valid";
if (request.params.size() >= 2) strCachedSignal = request.params[1].get_str();
if (!request.params[1].isNull()) {
strCachedSignal = request.params[1].get_str();
}
if (strCachedSignal != "valid" && strCachedSignal != "funding" && strCachedSignal != "delete" && strCachedSignal != "endorsed" && strCachedSignal != "all")
return "Invalid signal, should be 'valid', 'funding', 'delete', 'endorsed' or 'all'";

std::string strType = "all";
if (request.params.size() == 3) strType = request.params[2].get_str();
if (!request.params[2].isNull()) {
strType = request.params[2].get_str();
}
if (strType != "proposals" && strType != "triggers" && strType != "all")
return "Invalid type, should be 'proposals', 'triggers' or 'all'";

Expand Down Expand Up @@ -837,7 +847,7 @@ UniValue gobject_getcurrentvotes(const JSONRPCRequest& request)
uint256 hash = ParseHashV(request.params[1], "Governance hash");

COutPoint mnCollateralOutpoint;
if (request.params.size() == 4) {
if (!request.params[2].isNull() && !request.params[3].isNull()) {
uint256 txid = ParseHashV(request.params[2], "Masternode Collateral hash");
std::string strVout = request.params[3].get_str();
mnCollateralOutpoint = COutPoint(txid, (uint32_t)atoi(strVout));
Expand Down Expand Up @@ -897,7 +907,7 @@ UniValue gobject_getcurrentvotes(const JSONRPCRequest& request)
UniValue gobject(const JSONRPCRequest& request)
{
std::string strCommand;
if (request.params.size() >= 1)
if (!request.params[0].isNull())
strCommand = request.params[0].get_str();

if (request.fHelp && strCommand.empty()) {
Expand Down
12 changes: 6 additions & 6 deletions src/rpc/masternode.cpp
Expand Up @@ -309,15 +309,15 @@ UniValue masternode_winners(const JSONRPCRequest& request)
int nLast = 10;
std::string strFilter = "";

if (request.params.size() >= 2) {
if (!request.params[1].isNull()) {
nLast = atoi(request.params[1].get_str());
}

if (request.params.size() == 3) {
if (!request.params[2].isNull()) {
strFilter = request.params[2].get_str();
}

if (request.params.size() > 3)
if (!request.params[3].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'masternode winners ( \"count\" \"filter\" )'");

UniValue obj(UniValue::VOBJ);
Expand Down Expand Up @@ -352,7 +352,7 @@ UniValue masternode_winners(const JSONRPCRequest& request)
UniValue masternode(const JSONRPCRequest& request)
{
std::string strCommand;
if (request.params.size() >= 1) {
if (!request.params[0].isNull()) {
strCommand = request.params[0].get_str();
}

Expand Down Expand Up @@ -388,8 +388,8 @@ UniValue masternodelist(const JSONRPCRequest& request)
std::string strMode = "json";
std::string strFilter = "";

if (request.params.size() >= 1) strMode = request.params[0].get_str();
if (request.params.size() == 2) strFilter = request.params[1].get_str();
if (!request.params[0].isNull()) strMode = request.params[0].get_str();
if (!request.params[1].isNull()) strFilter = request.params[1].get_str();

std::transform(strMode.begin(), strMode.end(), strMode.begin(), ::tolower);

Expand Down
2 changes: 1 addition & 1 deletion src/rpc/mining.cpp
Expand Up @@ -867,7 +867,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
unsigned int conf_target = ParseConfirmTarget(request.params[0]);
bool conservative = true;
if (request.params.size() > 1 && !request.params[1].isNull()) {
if (!request.params[1].isNull()) {
FeeEstimateMode fee_mode;
if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
Expand Down
6 changes: 3 additions & 3 deletions src/rpc/misc.cpp
Expand Up @@ -1186,7 +1186,7 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
+ HelpExampleRpc("getmemoryinfo", "")
);

std::string mode = (request.params.size() < 1 || request.params[0].isNull()) ? "stats" : request.params[0].get_str();
std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
if (mode == "stats") {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("locked", RPCLockedMemoryInfo()));
Expand Down Expand Up @@ -1241,11 +1241,11 @@ UniValue logging(const JSONRPCRequest& request)
}

uint64_t originalLogCategories = logCategories;
if (request.params.size() > 0 && request.params[0].isArray()) {
if (request.params[0].isArray()) {
logCategories |= getCategoryMask(request.params[0]);
}

if (request.params.size() > 1 && request.params[1].isArray()) {
if (request.params[1].isArray()) {
logCategories &= ~getCategoryMask(request.params[1]);
}

Expand Down
12 changes: 6 additions & 6 deletions src/rpc/net.cpp
Expand Up @@ -200,7 +200,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
UniValue addnode(const JSONRPCRequest& request)
{
std::string strCommand;
if (request.params.size() == 2)
if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
Expand Down Expand Up @@ -267,7 +267,7 @@ UniValue disconnectnode(const JSONRPCRequest& request)

bool success;
const UniValue &address_arg = request.params[0];
const UniValue &id_arg = request.params.size() < 2 ? NullUniValue : request.params[1];
const UniValue &id_arg = request.params[1];

if (!address_arg.isNull() && id_arg.isNull()) {
/* handle disconnect-by-address */
Expand Down Expand Up @@ -321,7 +321,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)

std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();

if (request.params.size() == 1 && !request.params[0].isNull()) {
if (!request.params[0].isNull()) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
if (info.strAddedNode == request.params[0].get_str()) {
Expand Down Expand Up @@ -500,7 +500,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
UniValue setban(const JSONRPCRequest& request)
{
std::string strCommand;
if (request.params.size() >= 2)
if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
Expand Down Expand Up @@ -544,11 +544,11 @@ UniValue setban(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");

int64_t banTime = 0; //use standard bantime if not specified
if (request.params.size() >= 3 && !request.params[2].isNull())
if (!request.params[2].isNull())
banTime = request.params[2].get_int64();

bool absolute = false;
if (request.params.size() == 4 && request.params[3].isTrue())
if (request.params[3].isTrue())
absolute = true;

isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
Expand Down
12 changes: 6 additions & 6 deletions src/rpc/rawtransaction.cpp
Expand Up @@ -388,7 +388,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)

CMutableTransaction rawTx;

if (request.params.size() > 2 && !request.params[2].isNull()) {
if (!request.params[2].isNull()) {
int64_t nLockTime = request.params[2].get_int64();
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
Expand Down Expand Up @@ -766,7 +766,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)

bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
if (request.params.size() > 2 && !request.params[2].isNull()) {
if (!request.params[2].isNull()) {
fGivenKeys = true;
UniValue keys = request.params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
Expand All @@ -788,7 +788,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif

// Add previous txouts given in the RPC call:
if (request.params.size() > 1 && !request.params[1].isNull()) {
if (!request.params[1].isNull()) {
UniValue prevTxs = request.params[1].get_array();
for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
const UniValue& p = prevTxs[idx];
Expand Down Expand Up @@ -859,7 +859,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif

int nHashType = SIGHASH_ALL;
if (request.params.size() > 3 && !request.params[3].isNull()) {
if (!request.params[3].isNull()) {
static std::map<std::string, int> mapSigHashValues = {
{std::string("ALL"), int(SIGHASH_ALL)},
{std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
Expand Down Expand Up @@ -955,11 +955,11 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
const uint256& hashTx = tx->GetHash();

CAmount nMaxRawTxFee = maxTxFee;
if (request.params.size() > 1 && request.params[1].get_bool())
if (!request.params[1].isNull() && request.params[1].get_bool())
nMaxRawTxFee = 0;

bool fBypassLimits = false;
if (request.params.size() > 3)
if (!request.params[3].isNull())
fBypassLimits = request.params[3].get_bool();

CCoinsViewCache &view = *pcoinsTip;
Expand Down

0 comments on commit 77b48b2

Please sign in to comment.