@@ -37,6 +37,7 @@ std::string HelpMessageCli()
37
37
strUsage += HelpMessageOpt (" -?" , _ (" This help message" ));
38
38
strUsage += HelpMessageOpt (" -conf=<file>" , strprintf (_ (" Specify configuration file (default: %s)" ), BITCOIN_CONF_FILENAME));
39
39
strUsage += HelpMessageOpt (" -datadir=<dir>" , _ (" Specify data directory" ));
40
+ 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)" ));
40
41
AppendParamsHelpMessages (strUsage);
41
42
strUsage += HelpMessageOpt (" -named" , strprintf (_ (" Pass named instead of positional arguments (default: %s)" ), DEFAULT_NAMED));
42
43
strUsage += HelpMessageOpt (" -rpcconnect=<ip>" , strprintf (_ (" Send commands to node running on <ip> (default: %s)" ), DEFAULT_RPCCONNECT));
@@ -191,7 +192,96 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
191
192
}
192
193
#endif
193
194
194
- static UniValue CallRPC (const std::string& strMethod, const UniValue& params)
195
+ /* * Class that handles the conversion from a command-line to a JSON-RPC request,
196
+ * as well as converting back to a JSON object that can be shown as result.
197
+ */
198
+ class BaseRequestHandler
199
+ {
200
+ public:
201
+ virtual UniValue PrepareRequest (const std::string& method, const std::vector<std::string>& args) = 0;
202
+ virtual UniValue ProcessReply (const UniValue &batch_in) = 0;
203
+ };
204
+
205
+ /* * Process getinfo requests */
206
+ class GetinfoRequestHandler : public BaseRequestHandler
207
+ {
208
+ public:
209
+ const int ID_NETWORKINFO = 0 ;
210
+ const int ID_BLOCKCHAININFO = 1 ;
211
+ const int ID_WALLETINFO = 2 ;
212
+
213
+ /* * Create a simulated `getinfo` request. */
214
+ UniValue PrepareRequest (const std::string& method, const std::vector<std::string>& args) override
215
+ {
216
+ UniValue result (UniValue::VARR);
217
+ result.push_back (JSONRPCRequestObj (" getnetworkinfo" , NullUniValue, ID_NETWORKINFO));
218
+ result.push_back (JSONRPCRequestObj (" getblockchaininfo" , NullUniValue, ID_BLOCKCHAININFO));
219
+ result.push_back (JSONRPCRequestObj (" getwalletinfo" , NullUniValue, ID_WALLETINFO));
220
+ return result;
221
+ }
222
+
223
+ /* * Collect values from the batch and form a simulated `getinfo` reply. */
224
+ UniValue ProcessReply (const UniValue &batch_in) override
225
+ {
226
+ UniValue result (UniValue::VOBJ);
227
+ std::vector<UniValue> batch = JSONRPCProcessBatchReply (batch_in, 3 );
228
+ // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on
229
+ // getwalletinfo() is allowed to fail in case there is no wallet.
230
+ if (!batch[ID_NETWORKINFO][" error" ].isNull ()) {
231
+ return batch[ID_NETWORKINFO];
232
+ }
233
+ if (!batch[ID_BLOCKCHAININFO][" error" ].isNull ()) {
234
+ return batch[ID_BLOCKCHAININFO];
235
+ }
236
+ result.pushKV (" version" , batch[ID_NETWORKINFO][" result" ][" version" ]);
237
+ result.pushKV (" protocolversion" , batch[ID_NETWORKINFO][" result" ][" protocolversion" ]);
238
+ if (!batch[ID_WALLETINFO].isNull ()) {
239
+ result.pushKV (" walletversion" , batch[ID_WALLETINFO][" result" ][" walletversion" ]);
240
+ result.pushKV (" balance" , batch[ID_WALLETINFO][" result" ][" balance" ]);
241
+ }
242
+ result.pushKV (" blocks" , batch[ID_BLOCKCHAININFO][" result" ][" blocks" ]);
243
+ result.pushKV (" timeoffset" , batch[ID_NETWORKINFO][" result" ][" timeoffset" ]);
244
+ result.pushKV (" connections" , batch[ID_NETWORKINFO][" result" ][" connections" ]);
245
+ result.pushKV (" proxy" , batch[ID_NETWORKINFO][" result" ][" networks" ][0 ][" proxy" ]);
246
+ result.pushKV (" difficulty" , batch[ID_BLOCKCHAININFO][" result" ][" difficulty" ]);
247
+ result.pushKV (" testnet" , UniValue (batch[ID_BLOCKCHAININFO][" result" ][" chain" ].get_str () == " test" ));
248
+ if (!batch[ID_WALLETINFO].isNull ()) {
249
+ result.pushKV (" walletversion" , batch[ID_WALLETINFO][" result" ][" walletversion" ]);
250
+ result.pushKV (" balance" , batch[ID_WALLETINFO][" result" ][" balance" ]);
251
+ result.pushKV (" keypoololdest" , batch[ID_WALLETINFO][" result" ][" keypoololdest" ]);
252
+ result.pushKV (" keypoolsize" , batch[ID_WALLETINFO][" result" ][" keypoolsize" ]);
253
+ if (!batch[ID_WALLETINFO][" result" ][" unlocked_until" ].isNull ()) {
254
+ result.pushKV (" unlocked_until" , batch[ID_WALLETINFO][" result" ][" unlocked_until" ]);
255
+ }
256
+ result.pushKV (" paytxfee" , batch[ID_WALLETINFO][" result" ][" paytxfee" ]);
257
+ }
258
+ result.pushKV (" relayfee" , batch[ID_NETWORKINFO][" result" ][" relayfee" ]);
259
+ result.pushKV (" warnings" , batch[ID_NETWORKINFO][" result" ][" warnings" ]);
260
+ return JSONRPCReplyObj (result, NullUniValue, 1 );
261
+ }
262
+ };
263
+
264
+ /* * Process default single requests */
265
+ class DefaultRequestHandler : public BaseRequestHandler {
266
+ public:
267
+ UniValue PrepareRequest (const std::string& method, const std::vector<std::string>& args) override
268
+ {
269
+ UniValue params;
270
+ if (gArgs .GetBoolArg (" -named" , DEFAULT_NAMED)) {
271
+ params = RPCConvertNamedValues (method, args);
272
+ } else {
273
+ params = RPCConvertValues (method, args);
274
+ }
275
+ return JSONRPCRequestObj (method, params, 1 );
276
+ }
277
+
278
+ UniValue ProcessReply (const UniValue &reply) override
279
+ {
280
+ return reply.get_obj ();
281
+ }
282
+ };
283
+
284
+ static UniValue CallRPC (BaseRequestHandler *rh, const std::string& strMethod, const std::vector<std::string>& args)
195
285
{
196
286
std::string host;
197
287
// In preference order, we choose the following for the port:
@@ -238,7 +328,7 @@ static UniValue CallRPC(const std::string& strMethod, const UniValue& params)
238
328
evhttp_add_header (output_headers, " Authorization" , (std::string (" Basic " ) + EncodeBase64 (strRPCUserColonPass)).c_str ());
239
329
240
330
// Attach request data
241
- std::string strRequest = JSONRPCRequestObj (strMethod, params, 1 ).write () + " \n " ;
331
+ std::string strRequest = rh-> PrepareRequest (strMethod, args ).write () + " \n " ;
242
332
struct evbuffer * output_buffer = evhttp_request_get_output_buffer (req.get ());
243
333
assert (output_buffer);
244
334
evbuffer_add (output_buffer, strRequest.data (), strRequest.size ());
@@ -277,7 +367,7 @@ static UniValue CallRPC(const std::string& strMethod, const UniValue& params)
277
367
UniValue valReply (UniValue::VSTR);
278
368
if (!valReply.read (response.body ))
279
369
throw std::runtime_error (" couldn't parse reply from server" );
280
- const UniValue& reply = valReply. get_obj ( );
370
+ const UniValue reply = rh-> ProcessReply (valReply );
281
371
if (reply.empty ())
282
372
throw std::runtime_error (" expected reply to have result, error and id properties" );
283
373
@@ -309,24 +399,25 @@ int CommandLineRPC(int argc, char *argv[])
309
399
args.push_back (line);
310
400
}
311
401
}
312
- if (args.size () < 1 ) {
313
- throw std::runtime_error (" too few parameters (need at least command)" );
314
- }
315
- std::string strMethod = args[0 ];
316
- args.erase (args.begin ()); // Remove trailing method name from arguments vector
317
-
318
- UniValue params;
319
- if (gArgs .GetBoolArg (" -named" , DEFAULT_NAMED)) {
320
- params = RPCConvertNamedValues (strMethod, args);
402
+ std::unique_ptr<BaseRequestHandler> rh;
403
+ std::string method;
404
+ if (gArgs .GetBoolArg (" -getinfo" , false )) {
405
+ rh.reset (new GetinfoRequestHandler ());
406
+ method = " " ;
321
407
} else {
322
- params = RPCConvertValues (strMethod, args);
408
+ rh.reset (new DefaultRequestHandler ());
409
+ if (args.size () < 1 ) {
410
+ throw std::runtime_error (" too few parameters (need at least command)" );
411
+ }
412
+ method = args[0 ];
413
+ args.erase (args.begin ()); // Remove trailing method name from arguments vector
323
414
}
324
415
325
416
// Execute and handle connection failures with -rpcwait
326
417
const bool fWait = gArgs .GetBoolArg (" -rpcwait" , false );
327
418
do {
328
419
try {
329
- const UniValue reply = CallRPC (strMethod, params );
420
+ const UniValue reply = CallRPC (rh. get (), method, args );
330
421
331
422
// Parse reply
332
423
const UniValue& result = find_value (reply, " result" );
0 commit comments