Skip to content

Commit

Permalink
Better error for “wrong number of params” in RPC
Browse files Browse the repository at this point in the history
Doesn’t rely on `fHelp` throwing an exception, and adds a test.
  • Loading branch information
sellout committed May 19, 2023
1 parent 4ddf2a9 commit 37eb4bf
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 7 deletions.
1 change: 1 addition & 0 deletions qa/pull-tester/rpc-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
'wallet_zero_value.py',
'threeofthreerestore.py',
'show_help.py',
'errors.py'
]

ZMQ_SCRIPTS = [
Expand Down
39 changes: 39 additions & 0 deletions qa/rpc-tests/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Copyright (c) 2018-2023 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .

#
# Test RPC call failure cases. Tests should mostly correspond to code in rpc/server.cpp.
#

from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import start_nodes

class BlockchainTest(BitcoinTestFramework):
"""
Test RPC call failure cases.
"""

def __init__(self):
super().__init__()
self.num_nodes = 2

def setup_network(self, split=False):
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
self.sync_all()

def run_test(self):
node = self.nodes[0]

try:
node.gettxoutsetinfo(1)
except JSONRPCException as e:
errorString = e.error['message']
assert("Too many parameters for method `gettxoutsetinfo`. Needed exactly 0, but received 1" in errorString)

if __name__ == '__main__':
BlockchainTest().main()
10 changes: 7 additions & 3 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,17 @@ std::string FormatConversionFailure(const std::string& strMethod, const Conversi
},
[&](const WrongNumberOfParams& err) {
return tinyformat::format(
"%s for method, %s. Needed between %u and %u, but received %u",
"%s for method `%s`. Needed %s, but received %u",
err.providedParams < err.requiredParams
? "Not enough parameters"
: "Too many parameters",
strMethod,
err.requiredParams,
err.requiredParams + err.optionalParams,
err.optionalParams == 0
? tinyformat::format("exactly %u", err.requiredParams)
: tinyformat::format(
"from %u to %u",
err.requiredParams,
err.requiredParams + err.optionalParams),
err.providedParams);
},
[](const UnparseableParam& err) {
Expand Down
29 changes: 25 additions & 4 deletions src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,12 +495,33 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params
if (paramRange != rpcCvtTable.end()) {
auto numRequired = paramRange->second.first.size();
auto numOptional = paramRange->second.second.size();
return pcmd->actor(
params,
params.size() < numRequired || numRequired + numOptional < params.size());
if (params.size() < numRequired || numRequired + numOptional < params.size()) {
std::string helpMsg;
try {
// help gets thrown – if it doesn’t throw, then no help message
pcmd->actor(params, true);
} catch (const std::runtime_error& err) {
helpMsg = std::string("\n\n") + err.what();
}
throw JSONRPCError(
RPC_INVALID_PARAMS,
strprintf(
"%s for method `%s`. Needed %s, but received %u%s",
params.size() < numRequired
? "Not enough parameters"
: "Too many parameters",
strMethod,
numOptional == 0
? strprintf("exactly %u", numRequired)
: strprintf("from %u to %u", numRequired, numRequired + numOptional),
params.size(),
helpMsg));
} else {
return pcmd->actor(params, false);
}
} else {
throw JSONRPCError(
RPC_METHOD_NOT_FOUND,
RPC_INTERNAL_ERROR,
"Parameters for "
+ strMethod
+ " not found – this is an internal error, please report it.");
Expand Down

0 comments on commit 37eb4bf

Please sign in to comment.