Changeset View
Changeset View
Standalone View
Standalone View
src/bitcoin-cli.cpp
Show First 20 Lines • Show All 524 Lines • ▼ Show 20 Lines | #endif | ||||
if (reply.empty()) { | if (reply.empty()) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"expected reply to have result, error and id properties"); | "expected reply to have result, error and id properties"); | ||||
} | } | ||||
return reply; | return reply; | ||||
} | } | ||||
/** | |||||
* ConnectAndCallRPC wraps CallRPC with -rpcwait and an exception handler. | |||||
* | |||||
* @param[in] rh Pointer to RequestHandler. | |||||
* @param[in] strMethod Reference to const string method to forward to CallRPC. | |||||
* @returns the RPC response as a UniValue object. | |||||
* @throws a CConnectionFailed std::runtime_error if connection failed or RPC | |||||
* server still in warmup. | |||||
*/ | |||||
static UniValue ConnectAndCallRPC(BaseRequestHandler *rh, | |||||
const std::string &strMethod, | |||||
const std::vector<std::string> &args) { | |||||
UniValue response(UniValue::VOBJ); | |||||
// Execute and handle connection failures with -rpcwait. | |||||
const bool fWait = gArgs.GetBoolArg("-rpcwait", false); | |||||
do { | |||||
try { | |||||
response = CallRPC(rh, strMethod, args); | |||||
if (fWait) { | |||||
const UniValue &error = find_value(response, "error"); | |||||
if (!error.isNull() && | |||||
error["code"].get_int() == RPC_IN_WARMUP) { | |||||
throw CConnectionFailed("server in warmup"); | |||||
} | |||||
} | |||||
break; // Connection succeeded, no need to retry. | |||||
} catch (const CConnectionFailed &) { | |||||
if (fWait) { | |||||
UninterruptibleSleep(std::chrono::milliseconds{1000}); | |||||
} else { | |||||
throw; | |||||
} | |||||
} | |||||
} while (fWait); | |||||
return response; | |||||
} | |||||
static int CommandLineRPC(int argc, char *argv[]) { | static int CommandLineRPC(int argc, char *argv[]) { | ||||
std::string strPrint; | std::string strPrint; | ||||
int nRet = 0; | int nRet = 0; | ||||
try { | try { | ||||
// Skip switches | // Skip switches | ||||
while (argc > 1 && IsSwitchChar(argv[1][0])) { | while (argc > 1 && IsSwitchChar(argv[1][0])) { | ||||
argc--; | argc--; | ||||
argv++; | argv++; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | try { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"too few parameters (need at least command)"); | "too few parameters (need at least command)"); | ||||
} | } | ||||
method = args[0]; | method = args[0]; | ||||
// Remove trailing method name from arguments vector | // Remove trailing method name from arguments vector | ||||
args.erase(args.begin()); | args.erase(args.begin()); | ||||
} | } | ||||
// Execute and handle connection failures with -rpcwait | const UniValue reply = ConnectAndCallRPC(rh.get(), method, args); | ||||
const bool fWait = gArgs.GetBoolArg("-rpcwait", false); | |||||
do { | |||||
try { | |||||
const UniValue reply = CallRPC(rh.get(), method, args); | |||||
// Parse reply | // Parse reply | ||||
const UniValue &result = find_value(reply, "result"); | UniValue result = find_value(reply, "result"); | ||||
const UniValue &error = find_value(reply, "error"); | const UniValue &error = find_value(reply, "error"); | ||||
if (!error.isNull()) { | if (!error.isNull()) { | ||||
// Error | // Error | ||||
int code = error["code"].get_int(); | |||||
if (fWait && code == RPC_IN_WARMUP) { | |||||
throw CConnectionFailed("server in warmup"); | |||||
} | |||||
strPrint = "error: " + error.write(); | strPrint = "error: " + error.write(); | ||||
nRet = abs(code); | nRet = abs(error["code"].get_int()); | ||||
if (error.isObject()) { | if (error.isObject()) { | ||||
UniValue errCode = find_value(error, "code"); | const UniValue &errCode = find_value(error, "code"); | ||||
UniValue errMsg = find_value(error, "message"); | const UniValue &errMsg = find_value(error, "message"); | ||||
strPrint = | strPrint = errCode.isNull() | ||||
errCode.isNull() | |||||
? "" | ? "" | ||||
: "error code: " + errCode.getValStr() + "\n"; | : ("error code: " + errCode.getValStr() + "\n"); | ||||
if (errMsg.isStr()) { | if (errMsg.isStr()) { | ||||
strPrint += "error message:\n" + errMsg.get_str(); | strPrint += ("error message:\n" + errMsg.get_str()); | ||||
} | } | ||||
if (errCode.isNum() && | if (errCode.isNum() && | ||||
errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) { | errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) { | ||||
strPrint += "\nTry adding " | strPrint += "\nTry adding \"-rpcwallet=<filename>\" option " | ||||
"\"-rpcwallet=<filename>\" option to " | "to bitcoin-cli command line."; | ||||
"bitcoin-cli command line."; | |||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
// Result | // Result | ||||
if (result.isNull()) { | if (result.isNull()) { | ||||
strPrint = ""; | strPrint = ""; | ||||
} else if (result.isStr()) { | } else if (result.isStr()) { | ||||
strPrint = result.get_str(); | strPrint = result.get_str(); | ||||
} else { | } else { | ||||
strPrint = result.write(2); | strPrint = result.write(2); | ||||
} | } | ||||
} | } | ||||
// Connection succeeded, no need to retry. | |||||
break; | |||||
} catch (const CConnectionFailed &) { | |||||
if (fWait) { | |||||
UninterruptibleSleep(std::chrono::milliseconds{1000}); | |||||
} else { | |||||
throw; | |||||
} | |||||
} | |||||
} while (fWait); | |||||
} catch (const std::exception &e) { | } catch (const std::exception &e) { | ||||
strPrint = std::string("error: ") + e.what(); | strPrint = std::string("error: ") + e.what(); | ||||
nRet = EXIT_FAILURE; | nRet = EXIT_FAILURE; | ||||
} catch (...) { | } catch (...) { | ||||
PrintExceptionContinue(nullptr, "CommandLineRPC()"); | PrintExceptionContinue(nullptr, "CommandLineRPC()"); | ||||
throw; | throw; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • Show Last 20 Lines |