aboutsummaryrefslogtreecommitdiff
path: root/src/bitcoin-cli.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bitcoin-cli.cpp')
-rw-r--r--src/bitcoin-cli.cpp328
1 files changed, 243 insertions, 85 deletions
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 1c330cf5e..b332b5e58 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -1,25 +1,26 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2009-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "chainparamsbase.h"
-#include "clientversion.h"
-#include "rpc/client.h"
-#include "rpc/protocol.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <chainparamsbase.h>
+#include <clientversion.h>
+#include <fs.h>
+#include <rpc/client.h>
+#include <rpc/protocol.h>
+#include <util.h>
+#include <utilstrencodings.h>
-#include <boost/filesystem/operations.hpp>
+#include <memory>
#include <stdio.h>
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
-#include "support/events.h"
+#include <support/events.h>
#include <univalue.h>
@@ -28,24 +29,43 @@ static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const bool DEFAULT_NAMED=false;
static const int CONTINUE_EXECUTION=-1;
-std::string HelpMessageCli()
+static void SetupCliArgs()
{
- std::string strUsage;
- strUsage += HelpMessageGroup(_("Options:"));
- strUsage += HelpMessageOpt("-?", _("This help message"));
- strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
- strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
- AppendParamsHelpMessages(strUsage);
- strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
- strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
- strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort()));
- strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
- strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
- strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
- strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout during HTTP requests (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
- strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));
-
- return strUsage;
+ const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
+ const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
+
+ gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", false, OptionsCategory::OPTIONS);
+ SetupChainParamsBaseOptions();
+ gArgs.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpcclienttimeout=<n>", strprintf("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpcconnect=<ip>", strprintf("Send commands to node running on <ip> (default: %s)", DEFAULT_RPCCONNECT), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpccookiefile=<loc>", _("Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)"), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpcport=<port>", strprintf("Connect to JSON-RPC on <port> (default: %u or testnet: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpcwait", "Wait for RPC server to start", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpcwallet=<walletname>", "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind)", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-stdin", "Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-stdinrpcpass", strprintf("Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password."), false, OptionsCategory::OPTIONS);
+
+ // Hidden
+ gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
+ gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
+}
+
+/** libevent event log callback */
+static void libevent_log_cb(int severity, const char *msg)
+{
+#ifndef EVENT_LOG_ERR // EVENT_LOG_ERR was added in 2.0.19; but before then _EVENT_LOG_ERR existed.
+# define EVENT_LOG_ERR _EVENT_LOG_ERR
+#endif
+ // Ignore everything other than errors
+ if (severity >= EVENT_LOG_ERR) {
+ throw std::runtime_error(strprintf("libevent error: %s", msg));
+ }
}
//////////////////////////////////////////////////////////////////////////////
@@ -76,17 +96,22 @@ static int AppInitRPC(int argc, char* argv[])
//
// Parameters
//
- ParseParameters(argc, argv);
- if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) {
- std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n";
- if (!IsArgSet("-version")) {
- strUsage += "\n" + _("Usage:") + "\n" +
- " bitcoin-cli [options] <command> [params] " + strprintf(_("Send command to %s"), _(PACKAGE_NAME)) + "\n" +
- " bitcoin-cli [options] -named <command> [name=value] ... " + strprintf(_("Send command to %s (with named arguments)"), _(PACKAGE_NAME)) + "\n" +
- " bitcoin-cli [options] help " + _("List commands") + "\n" +
- " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
-
- strUsage += "\n" + HelpMessageCli();
+ SetupCliArgs();
+ std::string error;
+ if (!gArgs.ParseParameters(argc, argv, error)) {
+ fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ return EXIT_FAILURE;
+ }
+ if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
+ std::string strUsage = strprintf("%s RPC client version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n";
+ if (!gArgs.IsArgSet("-version")) {
+ strUsage += "\nUsage:\n"
+ " bitcoin-cli [options] <command> [params] " + strprintf("Send command to %s", PACKAGE_NAME) + "\n" +
+ " bitcoin-cli [options] -named <command> [name=value] ... " + strprintf("Send command to %s (with named arguments)", PACKAGE_NAME) + "\n" +
+ " bitcoin-cli [options] help List commands\n" +
+ " bitcoin-cli [options] help <command> Get help for a command\n";
+
+ strUsage += "\n" + gArgs.GetHelpMessage();
}
fprintf(stdout, "%s", strUsage.c_str());
@@ -96,24 +121,22 @@ static int AppInitRPC(int argc, char* argv[])
}
return EXIT_SUCCESS;
}
- if (!boost::filesystem::is_directory(GetDataDir(false))) {
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
+ if (!fs::is_directory(GetDataDir(false))) {
+ fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return EXIT_FAILURE;
}
- try {
- ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
- } catch (const std::exception& e) {
- fprintf(stderr,"Error reading configuration file: %s\n", e.what());
+ if (!gArgs.ReadConfigFiles(error, true)) {
+ fprintf(stderr, "Error reading configuration file: %s\n", error.c_str());
return EXIT_FAILURE;
}
// Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
try {
- SelectBaseParams(ChainNameFromCommandLine());
+ SelectBaseParams(gArgs.GetChainName());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
return EXIT_FAILURE;
}
- if (GetBoolArg("-rpcssl", false))
+ if (gArgs.GetBoolArg("-rpcssl", false))
{
fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
return EXIT_FAILURE;
@@ -132,7 +155,7 @@ struct HTTPReply
std::string body;
};
-const char *http_errorstring(int code)
+static const char *http_errorstring(int code)
{
switch(code) {
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
@@ -158,8 +181,8 @@ static void http_request_done(struct evhttp_request *req, void *ctx)
{
HTTPReply *reply = static_cast<HTTPReply*>(ctx);
- if (req == NULL) {
- /* If req is NULL, it means an error occurred while connecting: the
+ if (req == nullptr) {
+ /* If req is nullptr, it means an error occurred while connecting: the
* error code will have been passed to http_error_cb.
*/
reply->status = 0;
@@ -187,21 +210,120 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
}
#endif
-UniValue CallRPC(const std::string& strMethod, const UniValue& params)
+/** Class that handles the conversion from a command-line to a JSON-RPC request,
+ * as well as converting back to a JSON object that can be shown as result.
+ */
+class BaseRequestHandler
+{
+public:
+ virtual ~BaseRequestHandler() {}
+ virtual UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) = 0;
+ virtual UniValue ProcessReply(const UniValue &batch_in) = 0;
+};
+
+/** Process getinfo requests */
+class GetinfoRequestHandler: public BaseRequestHandler
+{
+public:
+ const int ID_NETWORKINFO = 0;
+ const int ID_BLOCKCHAININFO = 1;
+ const int ID_WALLETINFO = 2;
+
+ /** Create a simulated `getinfo` request. */
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ if (!args.empty()) {
+ throw std::runtime_error("-getinfo takes no arguments");
+ }
+ UniValue result(UniValue::VARR);
+ result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
+ result.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue, ID_BLOCKCHAININFO));
+ result.push_back(JSONRPCRequestObj("getwalletinfo", NullUniValue, ID_WALLETINFO));
+ return result;
+ }
+
+ /** Collect values from the batch and form a simulated `getinfo` reply. */
+ UniValue ProcessReply(const UniValue &batch_in) override
+ {
+ UniValue result(UniValue::VOBJ);
+ std::vector<UniValue> batch = JSONRPCProcessBatchReply(batch_in, 3);
+ // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on
+ // getwalletinfo() is allowed to fail in case there is no wallet.
+ if (!batch[ID_NETWORKINFO]["error"].isNull()) {
+ return batch[ID_NETWORKINFO];
+ }
+ if (!batch[ID_BLOCKCHAININFO]["error"].isNull()) {
+ return batch[ID_BLOCKCHAININFO];
+ }
+ result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]);
+ result.pushKV("protocolversion", batch[ID_NETWORKINFO]["result"]["protocolversion"]);
+ if (!batch[ID_WALLETINFO].isNull()) {
+ result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
+ result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
+ }
+ result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]);
+ result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]);
+ result.pushKV("connections", batch[ID_NETWORKINFO]["result"]["connections"]);
+ result.pushKV("proxy", batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]);
+ result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
+ result.pushKV("testnet", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"].get_str() == "test"));
+ if (!batch[ID_WALLETINFO].isNull()) {
+ result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
+ result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
+ result.pushKV("keypoololdest", batch[ID_WALLETINFO]["result"]["keypoololdest"]);
+ result.pushKV("keypoolsize", batch[ID_WALLETINFO]["result"]["keypoolsize"]);
+ if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) {
+ result.pushKV("unlocked_until", batch[ID_WALLETINFO]["result"]["unlocked_until"]);
+ }
+ result.pushKV("paytxfee", batch[ID_WALLETINFO]["result"]["paytxfee"]);
+ }
+ result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]);
+ result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]);
+ return JSONRPCReplyObj(result, NullUniValue, 1);
+ }
+};
+
+/** Process default single requests */
+class DefaultRequestHandler: public BaseRequestHandler {
+public:
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ UniValue params;
+ if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
+ params = RPCConvertNamedValues(method, args);
+ } else {
+ params = RPCConvertValues(method, args);
+ }
+ return JSONRPCRequestObj(method, params, 1);
+ }
+
+ UniValue ProcessReply(const UniValue &reply) override
+ {
+ return reply.get_obj();
+ }
+};
+
+static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, const std::vector<std::string>& args)
{
- std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
- int port = GetArg("-rpcport", BaseParams().RPCPort());
+ std::string host;
+ // In preference order, we choose the following for the port:
+ // 1. -rpcport
+ // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
+ // 3. default port for chain
+ int port = BaseParams().RPCPort();
+ SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host);
+ port = gArgs.GetArg("-rpcport", port);
// Obtain event base
raii_event_base base = obtain_event_base();
// Synchronously look up hostname
raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
- evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
+ evhttp_connection_set_timeout(evcon.get(), gArgs.GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
HTTPReply response;
raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
- if (req == NULL)
+ if (req == nullptr)
throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
evhttp_request_set_error_cb(req.get(), http_error_cb);
@@ -209,16 +331,14 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
// Get credentials
std::string strRPCUserColonPass;
- if (GetArg("-rpcpassword", "") == "") {
+ bool failedToGetAuthCookie = false;
+ if (gArgs.GetArg("-rpcpassword", "") == "") {
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
- throw std::runtime_error(strprintf(
- _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
- GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
-
+ failedToGetAuthCookie = true;
}
} else {
- strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
+ strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
}
struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
@@ -228,12 +348,25 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
// Attach request data
- std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
+ std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n";
struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
assert(output_buffer);
evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
- int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
+ // check if we should use a special wallet endpoint
+ std::string endpoint = "/";
+ if (!gArgs.GetArgs("-rpcwallet").empty()) {
+ std::string walletName = gArgs.GetArg("-rpcwallet", "");
+ char *encodedURI = evhttp_uriencode(walletName.c_str(), walletName.size(), false);
+ if (encodedURI) {
+ endpoint = "/wallet/"+ std::string(encodedURI);
+ free(encodedURI);
+ }
+ else {
+ throw CConnectionFailed("uri-encode failed");
+ }
+ }
+ int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str());
req.release(); // ownership moved to evcon in above call
if (r != 0) {
throw CConnectionFailed("send http request failed");
@@ -241,11 +374,21 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
event_base_dispatch(base.get());
- if (response.status == 0)
- throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
- else if (response.status == HTTP_UNAUTHORIZED)
- throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
- else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
+ if (response.status == 0) {
+ std::string responseErrorMessage;
+ if (response.error != -1) {
+ responseErrorMessage = strprintf(" (error code %d - \"%s\")", response.error, http_errorstring(response.error));
+ }
+ throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\nMake sure the bitcoind server is running and that you are connecting to the correct RPC port.", host, port, responseErrorMessage));
+ } else if (response.status == HTTP_UNAUTHORIZED) {
+ if (failedToGetAuthCookie) {
+ throw std::runtime_error(strprintf(
+ "Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
+ GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
+ } else {
+ throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
+ }
+ } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
else if (response.body.empty())
throw std::runtime_error("no response from server");
@@ -254,14 +397,14 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body))
throw std::runtime_error("couldn't parse reply from server");
- const UniValue& reply = valReply.get_obj();
+ const UniValue reply = rh->ProcessReply(valReply);
if (reply.empty())
throw std::runtime_error("expected reply to have result, error and id properties");
return reply;
}
-int CommandLineRPC(int argc, char *argv[])
+static int CommandLineRPC(int argc, char *argv[])
{
std::string strPrint;
int nRet = 0;
@@ -271,30 +414,40 @@ int CommandLineRPC(int argc, char *argv[])
argc--;
argv++;
}
+ std::string rpcPass;
+ if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
+ if (!std::getline(std::cin, rpcPass)) {
+ throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
+ }
+ gArgs.ForceSetArg("-rpcpassword", rpcPass);
+ }
std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
- if (GetBoolArg("-stdin", false)) {
+ if (gArgs.GetBoolArg("-stdin", false)) {
// Read one arg per line from stdin and append
std::string line;
- while (std::getline(std::cin,line))
+ while (std::getline(std::cin, line)) {
args.push_back(line);
+ }
}
- if (args.size() < 1)
- throw std::runtime_error("too few parameters (need at least command)");
- std::string strMethod = args[0];
- args.erase(args.begin()); // Remove trailing method name from arguments vector
-
- UniValue params;
- if(GetBoolArg("-named", DEFAULT_NAMED)) {
- params = RPCConvertNamedValues(strMethod, args);
+ std::unique_ptr<BaseRequestHandler> rh;
+ std::string method;
+ if (gArgs.GetBoolArg("-getinfo", false)) {
+ rh.reset(new GetinfoRequestHandler());
+ method = "";
} else {
- params = RPCConvertValues(strMethod, args);
+ rh.reset(new DefaultRequestHandler());
+ if (args.size() < 1) {
+ throw std::runtime_error("too few parameters (need at least command)");
+ }
+ method = args[0];
+ args.erase(args.begin()); // Remove trailing method name from arguments vector
}
// Execute and handle connection failures with -rpcwait
- const bool fWait = GetBoolArg("-rpcwait", false);
+ const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
do {
try {
- const UniValue reply = CallRPC(strMethod, params);
+ const UniValue reply = CallRPC(rh.get(), method, args);
// Parse reply
const UniValue& result = find_value(reply, "result");
@@ -315,6 +468,10 @@ int CommandLineRPC(int argc, char *argv[])
if (errMsg.isStr())
strPrint += "error message:\n"+errMsg.get_str();
+
+ if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
+ strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
+ }
}
} else {
// Result
@@ -344,7 +501,7 @@ int CommandLineRPC(int argc, char *argv[])
nRet = EXIT_FAILURE;
}
catch (...) {
- PrintExceptionContinue(NULL, "CommandLineRPC()");
+ PrintExceptionContinue(nullptr, "CommandLineRPC()");
throw;
}
@@ -361,6 +518,7 @@ int main(int argc, char* argv[])
fprintf(stderr, "Error: Initializing networking failed\n");
return EXIT_FAILURE;
}
+ event_set_log_callback(&libevent_log_cb);
try {
int ret = AppInitRPC(argc, argv);
@@ -371,7 +529,7 @@ int main(int argc, char* argv[])
PrintExceptionContinue(&e, "AppInitRPC()");
return EXIT_FAILURE;
} catch (...) {
- PrintExceptionContinue(NULL, "AppInitRPC()");
+ PrintExceptionContinue(nullptr, "AppInitRPC()");
return EXIT_FAILURE;
}
@@ -382,7 +540,7 @@ int main(int argc, char* argv[])
catch (const std::exception& e) {
PrintExceptionContinue(&e, "CommandLineRPC()");
} catch (...) {
- PrintExceptionContinue(NULL, "CommandLineRPC()");
+ PrintExceptionContinue(nullptr, "CommandLineRPC()");
}
return ret;
}