Skip to content

Commit 29f2cbd

Browse files
committed
cli: extract connection exception handler, -rpcwait logic
to ConnectAndCallRPC() to be callable for individual connections. This is needed for RPCs that need to be called and handled sequentially, rather than alone or in a batch. For example, when fetching the balances for each loaded wallet, -getinfo will call RPC listwallets, and then, depending on the result, RPC getbalances. It may be somewhat helpful to review this commit with `git show -w`.
1 parent 5f19155 commit 29f2cbd

File tree

1 file changed

+64
-51
lines changed

1 file changed

+64
-51
lines changed

src/bitcoin-cli.cpp

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,40 @@ static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, co
418418
return reply;
419419
}
420420

421+
/**
422+
* ConnectAndCallRPC wraps CallRPC with -rpcwait and an exception handler.
423+
*
424+
* @param[in] rh Pointer to RequestHandler.
425+
* @param[in] strMethod Reference to const string method to forward to CallRPC.
426+
* @returns the RPC response as a UniValue object.
427+
* @throws a CConnectionFailed std::runtime_error if connection failed or RPC server still in warmup.
428+
*/
429+
static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args)
430+
{
431+
UniValue response(UniValue::VOBJ);
432+
// Execute and handle connection failures with -rpcwait.
433+
const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
434+
do {
435+
try {
436+
response = CallRPC(rh, strMethod, args);
437+
if (fWait) {
438+
const UniValue& error = find_value(response, "error");
439+
if (!error.isNull() && error["code"].get_int() == RPC_IN_WARMUP) {
440+
throw CConnectionFailed("server in warmup");
441+
}
442+
}
443+
break; // Connection succeeded, no need to retry.
444+
} catch (const CConnectionFailed&) {
445+
if (fWait) {
446+
UninterruptibleSleep(std::chrono::milliseconds{1000});
447+
} else {
448+
throw;
449+
}
450+
}
451+
} while (fWait);
452+
return response;
453+
}
454+
421455
static int CommandLineRPC(int argc, char *argv[])
422456
{
423457
std::string strPrint;
@@ -485,62 +519,41 @@ static int CommandLineRPC(int argc, char *argv[])
485519
method = args[0];
486520
args.erase(args.begin()); // Remove trailing method name from arguments vector
487521
}
488-
489-
// Execute and handle connection failures with -rpcwait
490-
const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
491-
do {
492-
try {
493-
const UniValue reply = CallRPC(rh.get(), method, args);
494-
495-
// Parse reply
496-
const UniValue& result = find_value(reply, "result");
497-
const UniValue& error = find_value(reply, "error");
498-
499-
if (!error.isNull()) {
500-
// Error
501-
int code = error["code"].get_int();
502-
if (fWait && code == RPC_IN_WARMUP)
503-
throw CConnectionFailed("server in warmup");
504-
strPrint = "error: " + error.write();
505-
nRet = abs(code);
506-
if (error.isObject())
507-
{
508-
UniValue errCode = find_value(error, "code");
509-
UniValue errMsg = find_value(error, "message");
510-
strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
511-
512-
if (errMsg.isStr())
513-
strPrint += "error message:\n"+errMsg.get_str();
514-
515-
if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
516-
strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
517-
}
518-
}
519-
} else {
520-
// Result
521-
if (result.isNull())
522-
strPrint = "";
523-
else if (result.isStr())
524-
strPrint = result.get_str();
525-
else
526-
strPrint = result.write(2);
522+
const UniValue reply = ConnectAndCallRPC(rh.get(), method, args);
523+
524+
// Parse reply
525+
UniValue result = find_value(reply, "result");
526+
const UniValue& error = find_value(reply, "error");
527+
if (!error.isNull()) {
528+
// Error
529+
strPrint = "error: " + error.write();
530+
nRet = abs(error["code"].get_int());
531+
if (error.isObject()) {
532+
const UniValue& errCode = find_value(error, "code");
533+
const UniValue& errMsg = find_value(error, "message");
534+
strPrint = errCode.isNull() ? "" : ("error code: " + errCode.getValStr() + "\n");
535+
536+
if (errMsg.isStr()) {
537+
strPrint += ("error message:\n" + errMsg.get_str());
538+
}
539+
if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
540+
strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
527541
}
528-
// Connection succeeded, no need to retry.
529-
break;
530542
}
531-
catch (const CConnectionFailed&) {
532-
if (fWait)
533-
UninterruptibleSleep(std::chrono::milliseconds{1000});
534-
else
535-
throw;
543+
} else {
544+
// Result
545+
if (result.isNull()) {
546+
strPrint = "";
547+
} else if (result.isStr()) {
548+
strPrint = result.get_str();
549+
} else {
550+
strPrint = result.write(2);
536551
}
537-
} while (fWait);
538-
}
539-
catch (const std::exception& e) {
552+
}
553+
} catch (const std::exception& e) {
540554
strPrint = std::string("error: ") + e.what();
541555
nRet = EXIT_FAILURE;
542-
}
543-
catch (...) {
556+
} catch (...) {
544557
PrintExceptionContinue(nullptr, "CommandLineRPC()");
545558
throw;
546559
}

0 commit comments

Comments
 (0)