Bitcoin Core  0.18.99
P2P Digital Currency
server.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <rpc/server.h>
7 
8 #include <fs.h>
9 #include <key_io.h>
10 #include <random.h>
11 #include <rpc/util.h>
12 #include <shutdown.h>
13 #include <sync.h>
14 #include <ui_interface.h>
15 #include <util/strencodings.h>
16 #include <util/system.h>
17 
18 #include <boost/signals2/signal.hpp>
19 #include <boost/algorithm/string/classification.hpp>
20 #include <boost/algorithm/string/split.hpp>
21 
22 #include <memory> // for unique_ptr
23 #include <unordered_map>
24 
25 static CCriticalSection cs_rpcWarmup;
26 static std::atomic<bool> g_rpc_running{false};
27 static bool fRPCInWarmup GUARDED_BY(cs_rpcWarmup) = true;
28 static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server started";
29 /* Timer-creating functions */
30 static RPCTimerInterface* timerInterface = nullptr;
31 /* Map of name to timer. */
32 static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
33 static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler);
34 
36 {
37  std::string method;
38  int64_t start;
39 };
40 
42 {
44  std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex);
45 };
46 
47 static RPCServerInfo g_rpc_server_info;
48 
50 {
51  std::list<RPCCommandExecutionInfo>::iterator it;
52  explicit RPCCommandExecution(const std::string& method)
53  {
54  LOCK(g_rpc_server_info.mutex);
55  it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {method, GetTimeMicros()});
56  }
58  {
59  LOCK(g_rpc_server_info.mutex);
60  g_rpc_server_info.active_commands.erase(it);
61  }
62 };
63 
64 static struct CRPCSignals
65 {
66  boost::signals2::signal<void ()> Started;
67  boost::signals2::signal<void ()> Stopped;
68 } g_rpcSignals;
69 
70 void RPCServer::OnStarted(std::function<void ()> slot)
71 {
72  g_rpcSignals.Started.connect(slot);
73 }
74 
75 void RPCServer::OnStopped(std::function<void ()> slot)
76 {
77  g_rpcSignals.Stopped.connect(slot);
78 }
79 
80 std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
81 {
82  std::string strRet;
83  std::string category;
84  std::set<intptr_t> setDone;
85  std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
86 
87  for (const auto& entry : mapCommands)
88  vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front()));
89  sort(vCommands.begin(), vCommands.end());
90 
91  JSONRPCRequest jreq(helpreq);
92  jreq.fHelp = true;
93  jreq.params = UniValue();
94 
95  for (const std::pair<std::string, const CRPCCommand*>& command : vCommands)
96  {
97  const CRPCCommand *pcmd = command.second;
98  std::string strMethod = pcmd->name;
99  if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
100  continue;
101  jreq.strMethod = strMethod;
102  try
103  {
104  UniValue unused_result;
105  if (setDone.insert(pcmd->unique_id).second)
106  pcmd->actor(jreq, unused_result, true /* last_handler */);
107  }
108  catch (const std::exception& e)
109  {
110  // Help text is returned in an exception
111  std::string strHelp = std::string(e.what());
112  if (strCommand == "")
113  {
114  if (strHelp.find('\n') != std::string::npos)
115  strHelp = strHelp.substr(0, strHelp.find('\n'));
116 
117  if (category != pcmd->category)
118  {
119  if (!category.empty())
120  strRet += "\n";
121  category = pcmd->category;
122  strRet += "== " + Capitalize(category) + " ==\n";
123  }
124  }
125  strRet += strHelp + "\n";
126  }
127  }
128  if (strRet == "")
129  strRet = strprintf("help: unknown command: %s\n", strCommand);
130  strRet = strRet.substr(0,strRet.size()-1);
131  return strRet;
132 }
133 
134 UniValue help(const JSONRPCRequest& jsonRequest)
135 {
136  if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
137  throw std::runtime_error(
138  RPCHelpMan{"help",
139  "\nList all commands, or get help for a specified command.\n",
140  {
141  {"command", RPCArg::Type::STR, /* default */ "all commands", "The command to get help on"},
142  },
143  RPCResult{
144  "\"text\" (string) The help text\n"
145  },
146  RPCExamples{""},
147  }.ToString()
148  );
149 
150  std::string strCommand;
151  if (jsonRequest.params.size() > 0)
152  strCommand = jsonRequest.params[0].get_str();
153 
154  return tableRPC.help(strCommand, jsonRequest);
155 }
156 
157 
158 UniValue stop(const JSONRPCRequest& jsonRequest)
159 {
160  // Accept the deprecated and ignored 'detach' boolean argument
161  // Also accept the hidden 'wait' integer argument (milliseconds)
162  // For instance, 'stop 1000' makes the call wait 1 second before returning
163  // to the client (intended for testing)
164  if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
165  throw std::runtime_error(
166  RPCHelpMan{"stop",
167  "\nStop Bitcoin server.",
168  {},
169  RPCResults{},
170  RPCExamples{""},
171  }.ToString());
172  // Event loop will exit after current HTTP requests have been handled, so
173  // this reply will get back to the client.
174  StartShutdown();
175  if (jsonRequest.params[0].isNum()) {
176  MilliSleep(jsonRequest.params[0].get_int());
177  }
178  return "Bitcoin server stopping";
179 }
180 
181 static UniValue uptime(const JSONRPCRequest& jsonRequest)
182 {
183  if (jsonRequest.fHelp || jsonRequest.params.size() > 0)
184  throw std::runtime_error(
185  RPCHelpMan{"uptime",
186  "\nReturns the total uptime of the server.\n",
187  {},
188  RPCResult{
189  "ttt (numeric) The number of seconds that the server has been running\n"
190  },
191  RPCExamples{
192  HelpExampleCli("uptime", "")
193  + HelpExampleRpc("uptime", "")
194  },
195  }.ToString());
196 
197  return GetTime() - GetStartupTime();
198 }
199 
200 static UniValue getrpcinfo(const JSONRPCRequest& request)
201 {
202  if (request.fHelp || request.params.size() > 0) {
203  throw std::runtime_error(
204  RPCHelpMan{"getrpcinfo",
205  "\nReturns details of the RPC server.\n",
206  {},
207  RPCResult{
208  "{\n"
209  " \"active_commands\" (array) All active commands\n"
210  " [\n"
211  " { (object) Information about an active command\n"
212  " \"method\" (string) The name of the RPC command \n"
213  " \"duration\" (numeric) The running time in microseconds\n"
214  " },...\n"
215  " ]\n"
216  "}\n"
217  },
218  RPCExamples{
219  HelpExampleCli("getrpcinfo", "")
220  + HelpExampleRpc("getrpcinfo", "")},
221  }.ToString()
222  );
223  }
224 
225  LOCK(g_rpc_server_info.mutex);
226  UniValue active_commands(UniValue::VARR);
227  for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) {
228  UniValue entry(UniValue::VOBJ);
229  entry.pushKV("method", info.method);
230  entry.pushKV("duration", GetTimeMicros() - info.start);
231  active_commands.push_back(entry);
232  }
233 
234  UniValue result(UniValue::VOBJ);
235  result.pushKV("active_commands", active_commands);
236 
237  return result;
238 }
239 
240 // clang-format off
241 static const CRPCCommand vRPCCommands[] =
242 { // category name actor (function) argNames
243  // --------------------- ------------------------ ----------------------- ----------
244  /* Overall control/query calls */
245  { "control", "getrpcinfo", &getrpcinfo, {} },
246  { "control", "help", &help, {"command"} },
247  { "control", "stop", &stop, {"wait"} },
248  { "control", "uptime", &uptime, {} },
249 };
250 // clang-format on
251 
253 {
254  unsigned int vcidx;
255  for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
256  {
257  const CRPCCommand *pcmd;
258 
259  pcmd = &vRPCCommands[vcidx];
260  mapCommands[pcmd->name].push_back(pcmd);
261  }
262 }
263 
264 bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
265 {
266  if (IsRPCRunning())
267  return false;
268 
269  mapCommands[name].push_back(pcmd);
270  return true;
271 }
272 
273 bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)
274 {
275  auto it = mapCommands.find(name);
276  if (it != mapCommands.end()) {
277  auto new_end = std::remove(it->second.begin(), it->second.end(), pcmd);
278  if (it->second.end() != new_end) {
279  it->second.erase(new_end, it->second.end());
280  return true;
281  }
282  }
283  return false;
284 }
285 
286 void StartRPC()
287 {
288  LogPrint(BCLog::RPC, "Starting RPC\n");
289  g_rpc_running = true;
290  g_rpcSignals.Started();
291 }
292 
294 {
295  LogPrint(BCLog::RPC, "Interrupting RPC\n");
296  // Interrupt e.g. running longpolls
297  g_rpc_running = false;
298 }
299 
300 void StopRPC()
301 {
302  LogPrint(BCLog::RPC, "Stopping RPC\n");
303  deadlineTimers.clear();
305  g_rpcSignals.Stopped();
306 }
307 
309 {
310  return g_rpc_running;
311 }
312 
313 void SetRPCWarmupStatus(const std::string& newStatus)
314 {
315  LOCK(cs_rpcWarmup);
316  rpcWarmupStatus = newStatus;
317 }
318 
320 {
321  LOCK(cs_rpcWarmup);
322  assert(fRPCInWarmup);
323  fRPCInWarmup = false;
324 }
325 
326 bool RPCIsInWarmup(std::string *outStatus)
327 {
328  LOCK(cs_rpcWarmup);
329  if (outStatus)
330  *outStatus = rpcWarmupStatus;
331  return fRPCInWarmup;
332 }
333 
334 void JSONRPCRequest::parse(const UniValue& valRequest)
335 {
336  // Parse request
337  if (!valRequest.isObject())
338  throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
339  const UniValue& request = valRequest.get_obj();
340 
341  // Parse id now so errors from here on will have the id
342  id = find_value(request, "id");
343 
344  // Parse method
345  UniValue valMethod = find_value(request, "method");
346  if (valMethod.isNull())
347  throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
348  if (!valMethod.isStr())
349  throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
350  strMethod = valMethod.get_str();
351  if (fLogIPs)
352  LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod),
353  this->authUser, this->peerAddr);
354  else
355  LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
356 
357  // Parse params
358  UniValue valParams = find_value(request, "params");
359  if (valParams.isArray() || valParams.isObject())
360  params = valParams;
361  else if (valParams.isNull())
362  params = UniValue(UniValue::VARR);
363  else
364  throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
365 }
366 
367 bool IsDeprecatedRPCEnabled(const std::string& method)
368 {
369  const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");
370 
371  return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();
372 }
373 
374 static UniValue JSONRPCExecOne(JSONRPCRequest jreq, const UniValue& req)
375 {
376  UniValue rpc_result(UniValue::VOBJ);
377 
378  try {
379  jreq.parse(req);
380 
381  UniValue result = tableRPC.execute(jreq);
382  rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
383  }
384  catch (const UniValue& objError)
385  {
386  rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
387  }
388  catch (const std::exception& e)
389  {
390  rpc_result = JSONRPCReplyObj(NullUniValue,
391  JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
392  }
393 
394  return rpc_result;
395 }
396 
397 std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq)
398 {
400  for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
401  ret.push_back(JSONRPCExecOne(jreq, vReq[reqIdx]));
402 
403  return ret.write() + "\n";
404 }
405 
410 static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
411 {
412  JSONRPCRequest out = in;
414  // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
415  // there is an unknown one.
416  const std::vector<std::string>& keys = in.params.getKeys();
417  const std::vector<UniValue>& values = in.params.getValues();
418  std::unordered_map<std::string, const UniValue*> argsIn;
419  for (size_t i=0; i<keys.size(); ++i) {
420  argsIn[keys[i]] = &values[i];
421  }
422  // Process expected parameters.
423  int hole = 0;
424  for (const std::string &argNamePattern: argNames) {
425  std::vector<std::string> vargNames;
426  boost::algorithm::split(vargNames, argNamePattern, boost::algorithm::is_any_of("|"));
427  auto fr = argsIn.end();
428  for (const std::string & argName : vargNames) {
429  fr = argsIn.find(argName);
430  if (fr != argsIn.end()) {
431  break;
432  }
433  }
434  if (fr != argsIn.end()) {
435  for (int i = 0; i < hole; ++i) {
436  // Fill hole between specified parameters with JSON nulls,
437  // but not at the end (for backwards compatibility with calls
438  // that act based on number of specified parameters).
439  out.params.push_back(UniValue());
440  }
441  hole = 0;
442  out.params.push_back(*fr->second);
443  argsIn.erase(fr);
444  } else {
445  hole += 1;
446  }
447  }
448  // If there are still arguments in the argsIn map, this is an error.
449  if (!argsIn.empty()) {
450  throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first);
451  }
452  // Return request with named arguments transformed to positional arguments
453  return out;
454 }
455 
457 {
458  // Return immediately if in warmup
459  {
460  LOCK(cs_rpcWarmup);
461  if (fRPCInWarmup)
462  throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
463  }
464 
465  // Find method
466  auto it = mapCommands.find(request.strMethod);
467  if (it != mapCommands.end()) {
468  UniValue result;
469  for (const auto& command : it->second) {
470  if (ExecuteCommand(*command, request, result, &command == &it->second.back())) {
471  return result;
472  }
473  }
474  }
475  throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
476 }
477 
478 static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler)
479 {
480  try
481  {
482  RPCCommandExecution execution(request.strMethod);
483  // Execute, convert arguments to array if necessary
484  if (request.params.isObject()) {
485  return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);
486  } else {
487  return command.actor(request, result, last_handler);
488  }
489  }
490  catch (const std::exception& e)
491  {
492  throw JSONRPCError(RPC_MISC_ERROR, e.what());
493  }
494 }
495 
496 std::vector<std::string> CRPCTable::listCommands() const
497 {
498  std::vector<std::string> commandList;
499  for (const auto& i : mapCommands) commandList.emplace_back(i.first);
500  return commandList;
501 }
502 
504 {
505  if (!timerInterface)
506  timerInterface = iface;
507 }
508 
510 {
511  timerInterface = iface;
512 }
513 
515 {
516  if (timerInterface == iface)
517  timerInterface = nullptr;
518 }
519 
520 void RPCRunLater(const std::string& name, std::function<void()> func, int64_t nSeconds)
521 {
522  if (!timerInterface)
523  throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
524  deadlineTimers.erase(name);
525  LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
526  deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)));
527 }
528 
530 {
531  int flag = 0;
532  if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
533  flag |= SERIALIZE_TRANSACTION_NO_WITNESS;
534  return flag;
535 }
536 
std::string SanitizeString(const std::string &str, int rule)
Remove unsafe chars.
bool isObject() const
Definition: univalue.h:85
std::string Capitalize(std::string str)
Capitalizes the first character of the given string.
RPC timer "driver".
Definition: server.h:72
std::string help(const std::string &name, const JSONRPCRequest &helpreq) const
Definition: server.cpp:80
std::string category
Definition: server.h:125
const std::vector< UniValue > & getValues() const
Bitcoin RPC command dispatcher.
Definition: server.h:135
bool IsRPCRunning()
Query whether RPC is running.
Definition: server.cpp:308
void SetRPCWarmupStatus(const std::string &newStatus)
Set the RPC warmup status.
Definition: server.cpp:313
Actor actor
Definition: server.h:127
#define strprintf
Definition: tinyformat.h:1066
void MilliSleep(int64_t n)
Definition: time.cpp:61
void OnStopped(std::function< void()> slot)
Definition: server.cpp:75
bool removeCommand(const std::string &name, const CRPCCommand *pcmd)
Definition: server.cpp:273
void InterruptRPC()
Definition: server.cpp:293
void DeleteAuthCookie()
Delete RPC authentication cookie from disk.
Definition: protocol.cpp:124
const std::string & get_str() const
bool isNum() const
Definition: univalue.h:83
bool isStr() const
Definition: univalue.h:82
const std::vector< std::string > & getKeys() const
void RPCRunLater(const std::string &name, std::function< void()> func, int64_t nSeconds)
Run func nSeconds from now.
Definition: server.cpp:520
bool appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:264
Client still warming up.
Definition: protocol.h:58
std::string method
Definition: server.cpp:37
std::vector< std::string > argNames
Definition: server.h:128
Invalid, missing or duplicate parameter.
Definition: protocol.h:52
void RPCUnsetTimerInterface(RPCTimerInterface *iface)
Unset factory function for timers.
Definition: server.cpp:514
const UniValue & find_value(const UniValue &obj, const std::string &name)
Definition: univalue.cpp:234
UniValue execute(const JSONRPCRequest &request) const
Execute a method.
Definition: server.cpp:456
std::string strMethod
Definition: server.h:34
void SetRPCWarmupFinished()
Definition: server.cpp:319
std::string name
Definition: server.h:126
CRPCTable tableRPC
Definition: server.cpp:537
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
Mutex mutex
Definition: server.cpp:43
UniValue params
Definition: server.h:35
#define LOCK(cs)
Definition: sync.h:182
const char * name
Definition: rest.cpp:38
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:113
std::string JSONRPCExecBatch(const JSONRPCRequest &jreq, const UniValue &vReq)
Definition: server.cpp:397
UniValue id
Definition: server.h:33
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
General application defined errors.
Definition: protocol.h:48
RPCCommandExecution(const std::string &method)
Definition: server.cpp:52
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
int get_int() const
void StartRPC()
Definition: server.cpp:286
UniValue help(const JSONRPCRequest &jsonRequest)
Definition: server.cpp:134
bool IsDeprecatedRPCEnabled(const std::string &method)
Definition: server.cpp:367
bool isNull() const
Definition: univalue.h:78
void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
Set the factory function for timer, but only, if unset.
Definition: server.cpp:503
virtual RPCTimerBase * NewTimer(std::function< void()> &func, int64_t millis)=0
Factory function for timers.
int64_t GetTimeMicros()
Definition: time.cpp:48
bool fHelp
Definition: server.h:36
void parse(const UniValue &valRequest)
Definition: server.cpp:334
void StopRPC()
Definition: server.cpp:300
int64_t GetStartupTime()
Server/client environment: argument handling, config file parsing, thread wrappers, startup time.
Definition: system.cpp:1203
int RPCSerializationFlags()
Definition: server.cpp:529
const UniValue & get_obj() const
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:496
bool fLogIPs
Definition: logging.cpp:35
void RPCSetTimerInterface(RPCTimerInterface *iface)
Set the factory function for timers.
Definition: server.cpp:509
std::list< RPCCommandExecutionInfo >::iterator it
Definition: server.cpp:51
ArgsManager gArgs
Definition: system.cpp:74
bool RPCIsInWarmup(std::string *outStatus)
Definition: server.cpp:326
const UniValue NullUniValue
Definition: univalue.cpp:13
#define GUARDED_BY(x)
Definition: threadsafety.h:38
void StartShutdown()
Definition: shutdown.cpp:12
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:108
Standard JSON-RPC 2.0 errors.
Definition: protocol.h:37
virtual const char * Name()=0
Implementation name.
UniValue JSONRPCError(int code, const std::string &message)
Definition: protocol.cpp:51
void OnStarted(std::function< void()> slot)
Definition: server.cpp:70
int64_t GetTime()
GetTimeMicros() and GetTimeMillis() both return the system time, but in different units...
Definition: time.cpp:20
size_t size() const
Definition: univalue.h:69
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
Definition: system.cpp:453
UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, const UniValue &id)
Definition: protocol.cpp:33
intptr_t unique_id
Definition: server.h:129
std::vector< std::string > listCommands() const
Returns a list of registered commands.
Definition: server.cpp:496
bool isArray() const
Definition: univalue.h:84
CRPCTable()
Definition: server.cpp:252
UniValue stop(const JSONRPCRequest &jsonRequest)
Definition: server.cpp:158