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