7 #if defined(HAVE_CONFIG_H) 21 #include <event2/buffer.h> 22 #include <event2/keyvalq_struct.h> 27 static const char DEFAULT_RPCCONNECT[] =
"127.0.0.1";
28 static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
29 static const bool DEFAULT_NAMED=
false;
30 static const int CONTINUE_EXECUTION=-1;
40 strUsage +=
HelpMessageOpt(
"-datadir=<dir>",
_(
"Specify data directory"));
41 strUsage +=
HelpMessageOpt(
"-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)"));
43 strUsage +=
HelpMessageOpt(
"-named",
strprintf(
_(
"Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
44 strUsage +=
HelpMessageOpt(
"-rpcconnect=<ip>",
strprintf(
_(
"Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
45 strUsage +=
HelpMessageOpt(
"-rpcport=<port>",
strprintf(
_(
"Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));
46 strUsage +=
HelpMessageOpt(
"-rpcwait",
_(
"Wait for RPC server to start"));
47 strUsage +=
HelpMessageOpt(
"-rpcuser=<user>",
_(
"Username for JSON-RPC connections"));
48 strUsage +=
HelpMessageOpt(
"-rpcpassword=<pw>",
_(
"Password for JSON-RPC connections"));
49 strUsage +=
HelpMessageOpt(
"-rpcclienttimeout=<n>",
strprintf(
_(
"Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
50 strUsage +=
HelpMessageOpt(
"-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.")));
51 strUsage +=
HelpMessageOpt(
"-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."));
52 strUsage +=
HelpMessageOpt(
"-rpcwallet=<walletname>",
_(
"Send RPC for non-default wallet on RPC server (argument is wallet filename in ravend directory, required if ravend/-Qt runs with multiple wallets)"));
71 std::runtime_error(msg)
80 static int AppInitRPC(
int argc,
char* argv[])
89 strUsage +=
"\n" +
_(
"Usage:") +
"\n" +
91 " raven-cli [options] -named <command> [name=value] ... " +
strprintf(
_(
"Send command to %s (with named arguments)"),
_(
PACKAGE_NAME)) +
"\n" +
92 " raven-cli [options] help " +
_(
"List commands") +
"\n" +
93 " raven-cli [options] help <command> " +
_(
"Get help for a command") +
"\n";
98 fprintf(stdout,
"%s", strUsage.c_str());
100 fprintf(stderr,
"Error: too few parameters\n");
106 fprintf(stderr,
"Error: Specified data directory \"%s\" does not exist.\n",
gArgs.
GetArg(
"-datadir",
"").c_str());
111 }
catch (
const std::exception& e) {
112 fprintf(stderr,
"Error reading configuration file: %s\n", e.what());
118 }
catch (
const std::exception& e) {
119 fprintf(stderr,
"Error: %s\n", e.what());
124 fprintf(stderr,
"Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
127 return CONTINUE_EXECUTION;
144 #if LIBEVENT_VERSION_NUMBER >= 0x02010300 145 case EVREQ_HTTP_TIMEOUT:
146 return "timeout reached";
148 return "EOF reached";
149 case EVREQ_HTTP_INVALID_HEADER:
150 return "error while reading header, or invalid header";
151 case EVREQ_HTTP_BUFFER_ERROR:
152 return "error encountered while reading or writing";
153 case EVREQ_HTTP_REQUEST_CANCEL:
154 return "request was canceled";
155 case EVREQ_HTTP_DATA_TOO_LONG:
156 return "response body is larger than allowed";
163 static void http_request_done(
struct evhttp_request *req,
void *ctx)
167 if (req ==
nullptr) {
175 reply->
status = evhttp_request_get_response_code(req);
177 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
180 size_t size = evbuffer_get_length(buf);
181 const char *data = (
const char*)evbuffer_pullup(buf, size);
183 reply->
body = std::string(data, size);
184 evbuffer_drain(buf, size);
188 #if LIBEVENT_VERSION_NUMBER >= 0x02010300 189 static void http_error_cb(
enum evhttp_request_error err,
void *ctx)
202 virtual UniValue PrepareRequest(
const std::string& method,
const std::vector<std::string>& args) = 0;
210 const int ID_NETWORKINFO = 0;
211 const int ID_BLOCKCHAININFO = 1;
212 const int ID_WALLETINFO = 2;
231 if (!batch[ID_NETWORKINFO][
"error"].isNull()) {
232 return batch[ID_NETWORKINFO];
234 if (!batch[ID_BLOCKCHAININFO][
"error"].isNull()) {
235 return batch[ID_BLOCKCHAININFO];
237 result.
pushKV(
"version", batch[ID_NETWORKINFO][
"result"][
"version"]);
238 result.
pushKV(
"protocolversion", batch[ID_NETWORKINFO][
"result"][
"protocolversion"]);
239 if (!batch[ID_WALLETINFO].isNull()) {
240 result.
pushKV(
"walletversion", batch[ID_WALLETINFO][
"result"][
"walletversion"]);
241 result.
pushKV(
"balance", batch[ID_WALLETINFO][
"result"][
"balance"]);
243 result.
pushKV(
"blocks", batch[ID_BLOCKCHAININFO][
"result"][
"blocks"]);
244 result.
pushKV(
"timeoffset", batch[ID_NETWORKINFO][
"result"][
"timeoffset"]);
245 result.
pushKV(
"connections", batch[ID_NETWORKINFO][
"result"][
"connections"]);
246 result.
pushKV(
"proxy", batch[ID_NETWORKINFO][
"result"][
"networks"][0][
"proxy"]);
247 result.
pushKV(
"difficulty", batch[ID_BLOCKCHAININFO][
"result"][
"difficulty"]);
248 result.
pushKV(
"testnet",
UniValue(batch[ID_BLOCKCHAININFO][
"result"][
"chain"].get_str() ==
"test"));
249 if (!batch[ID_WALLETINFO].isNull()) {
250 result.
pushKV(
"walletversion", batch[ID_WALLETINFO][
"result"][
"walletversion"]);
251 result.
pushKV(
"balance", batch[ID_WALLETINFO][
"result"][
"balance"]);
252 result.
pushKV(
"keypoololdest", batch[ID_WALLETINFO][
"result"][
"keypoololdest"]);
253 result.
pushKV(
"keypoolsize", batch[ID_WALLETINFO][
"result"][
"keypoolsize"]);
254 if (!batch[ID_WALLETINFO][
"result"][
"unlocked_until"].isNull()) {
255 result.
pushKV(
"unlocked_until", batch[ID_WALLETINFO][
"result"][
"unlocked_until"]);
257 result.
pushKV(
"paytxfee", batch[ID_WALLETINFO][
"result"][
"paytxfee"]);
259 result.
pushKV(
"relayfee", batch[ID_NETWORKINFO][
"result"][
"relayfee"]);
260 result.
pushKV(
"warnings", batch[ID_NETWORKINFO][
"result"][
"warnings"]);
301 evhttp_connection_set_timeout(evcon.get(),
gArgs.
GetArg(
"-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
306 throw std::runtime_error(
"create http request failed");
307 #if LIBEVENT_VERSION_NUMBER >= 0x02010300 308 evhttp_request_set_error_cb(req.get(), http_error_cb);
312 std::string strRPCUserColonPass;
317 _(
"Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"),
325 struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
326 assert(output_headers);
327 evhttp_add_header(output_headers,
"Host", host.c_str());
328 evhttp_add_header(output_headers,
"Connection",
"close");
329 evhttp_add_header(output_headers,
"Authorization", (std::string(
"Basic ") +
EncodeBase64(strRPCUserColonPass)).c_str());
333 struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
334 assert(output_buffer);
335 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
338 std::string endpoint =
"/";
339 std::string walletName =
gArgs.
GetArg(
"-rpcwallet",
"");
340 if (!walletName.empty()) {
341 char *encodedURI = evhttp_uriencode(walletName.c_str(), walletName.size(),
false);
343 endpoint =
"/wallet/"+ std::string(encodedURI);
350 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str());
356 event_base_dispatch(base.get());
358 if (response.status == 0)
359 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));
361 throw std::runtime_error(
"incorrect rpcuser or rpcpassword (authorization failed)");
363 throw std::runtime_error(
strprintf(
"server returned HTTP error %d", response.status));
364 else if (response.body.empty())
365 throw std::runtime_error(
"no response from server");
369 if (!valReply.
read(response.body))
370 throw std::runtime_error(
"couldn't parse reply from server");
373 throw std::runtime_error(
"expected reply to have result, error and id properties");
380 std::string strPrint;
390 if (!std::getline(std::cin, rpcPass)) {
391 throw std::runtime_error(
"-stdinrpcpass specified but failed to read from standard input");
395 std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
399 while (std::getline(std::cin, line)) {
400 args.push_back(line);
403 std::unique_ptr<BaseRequestHandler> rh;
410 if (args.size() < 1) {
411 throw std::runtime_error(
"too few parameters (need at least command)");
414 args.erase(args.begin());
421 const UniValue reply = CallRPC(rh.get(), method, args);
429 int code = error[
"code"].
get_int();
432 strPrint =
"error: " + error.
write();
438 strPrint = errCode.
isNull() ?
"" :
"error code: "+errCode.
getValStr()+
"\n";
441 strPrint +=
"error message:\n"+errMsg.
get_str();
444 strPrint +=
"\nTry adding \"-rpcwallet=<filename>\" option to raven-cli command line.";
451 else if (result.isStr())
452 strPrint = result.get_str();
454 strPrint = result.write(2);
467 catch (
const boost::thread_interrupted&) {
470 catch (
const std::exception& e) {
471 strPrint = std::string(
"error: ") + e.what();
479 if (strPrint !=
"") {
480 fprintf((nRet == 0 ? stdout : stderr),
"%s\n", strPrint.c_str());
485 int main(
int argc,
char* argv[])
489 fprintf(stderr,
"Error: Initializing networking failed\n");
494 int ret = AppInitRPC(argc, argv);
495 if (ret != CONTINUE_EXECUTION)
498 catch (
const std::exception& e) {
506 int ret = EXIT_FAILURE;
510 catch (
const std::exception& e) {
No wallet specified (error when there are multiple wallets loaded)
std::string HelpMessageOpt(const std::string &option, const std::string &message)
Format a string to be used as option description in help messages.
std::unique_ptr< CBaseChainParams > CreateBaseChainParams(const std::string &chain)
Creates and returns a std::unique_ptr<CBaseChainParams> of the chosen chain.
void AppendParamsHelpMessages(std::string &strUsage, bool debugHelp)
Append the help messages for the chainparams options to the parameter string.
std::string HelpMessageCli()
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
raii_event_base obtain_event_base()
const char *const RAVEN_CONF_FILENAME
void ParseParameters(int argc, const char *const argv[])
void MilliSleep(int64_t n)
bool read(const char *raw, size_t len)
UniValue JSONRPCRequestObj(const std::string &strMethod, const UniValue ¶ms, const UniValue &id)
JSON-RPC protocol.
UniValue ProcessReply(const UniValue &reply) override
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
void PrintExceptionContinue(const std::exception *pex, const char *pszThread)
const std::string & get_str() const
raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg)
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
void ForceSetArg(const std::string &strArg, const std::string &strValue)
std::vector< UniValue > JSONRPCProcessBatchReply(const UniValue &in, size_t num)
Parse JSON-RPC batch reply into a vector.
void ReadConfigFile(const std::string &confPath)
const std::string & getValStr() const
virtual UniValue ProcessReply(const UniValue &batch_in)=0
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
Create a simulated getinfo request.
const UniValue & find_value(const UniValue &obj, const std::string &name)
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
bool GetAuthCookie(std::string *cookie_out)
Read the RPC authentication cookie from disk.
bool push_back(const UniValue &val)
int CommandLineRPC(int argc, char *argv[])
const char * http_errorstring(int code)
virtual UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args)=0
raii_evhttp_connection obtain_evhttp_connection_base(struct event_base *base, std::string host, uint16_t port)
bool pushKV(const std::string &key, const UniValue &val)
UniValue ProcessReply(const UniValue &batch_in) override
Collect values from the batch and form a simulated getinfo reply.
Class that handles the conversion from a command-line to a JSON-RPC request, as well as converting ba...
std::string FormatFullVersion()
CConnectionFailed(const std::string &msg)
bool IsSwitchChar(char c)
void SplitHostPort(std::string in, int &portOut, std::string &hostOut)
fs::path GetConfigFile(const std::string &confPath)
const UniValue & get_obj() const
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Process default single requests.
std::string ChainNameFromCommandLine()
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
const UniValue NullUniValue
bool error(const char *fmt, const Args &... args)
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert named arguments to command-specific RPC representation.
static const std::string TESTNET
const fs::path & GetDataDir(bool fNetSpecific)
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, const UniValue &id)
void SelectBaseParams(const std::string &chain)
Sets the params returned by Params() to those for the given network.
Process getinfo requests.
std::string HelpMessageGroup(const std::string &message)
Format a string to be used as group of options in help messages.
int main(int argc, char *argv[])
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Reply structure for request_done to fill in.
std::string EncodeBase64(const unsigned char *pch, size_t len)