Bitcoin ABC  0.29.6
P2P Digital Currency
httprpc.cpp
Go to the documentation of this file.
1 // Copyright (c) 2015-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <httprpc.h>
6 
7 #include <chainparams.h>
8 #include <common/args.h>
9 #include <config.h>
10 #include <crypto/hmac_sha256.h>
11 #include <logging.h>
12 #include <rpc/protocol.h>
13 #include <util/strencodings.h>
14 #include <util/translation.h>
15 #include <walletinitinterface.h>
16 
17 #include <boost/algorithm/string.hpp> // boost::trim
18 
19 #include <algorithm>
20 #include <cstdio>
21 #include <functional>
22 #include <iterator>
23 #include <map>
24 #include <memory>
25 #include <set>
26 #include <string>
27 
29 static const char *WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
30 
32 static const int64_t RPC_AUTH_BRUTE_FORCE_DELAY = 250;
33 
38 class HTTPRPCTimer : public RPCTimerBase {
39 public:
40  HTTPRPCTimer(struct event_base *eventBase, std::function<void()> &func,
41  int64_t millis)
42  : ev(eventBase, false, func) {
43  struct timeval tv;
44  tv.tv_sec = millis / 1000;
45  tv.tv_usec = (millis % 1000) * 1000;
46  ev.trigger(&tv);
47  }
48 
49 private:
51 };
52 
54 public:
55  explicit HTTPRPCTimerInterface(struct event_base *_base) : base(_base) {}
56 
57  const char *Name() override { return "HTTP"; }
58 
59  RPCTimerBase *NewTimer(std::function<void()> &func,
60  int64_t millis) override {
61  return new HTTPRPCTimer(base, func, millis);
62  }
63 
64 private:
65  struct event_base *base;
66 };
67 
68 /* Pre-base64-encoded authentication token */
69 static std::string strRPCUserColonPass;
70 /* Pre-base64-encoded authentication token */
71 static std::string strRPCCORSDomain;
72 /* Stored RPC timer interface (for unregistration) */
73 static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
74 /* RPC Auth Whitelist */
75 static std::map<std::string, std::set<std::string>> g_rpc_whitelist;
76 static bool g_rpc_whitelist_default = false;
77 
78 static void JSONErrorReply(HTTPRequest *req, const UniValue &objError,
79  const UniValue &id) {
80  // Send error reply from json-rpc error object.
81  int nStatus = HTTP_INTERNAL_SERVER_ERROR;
82  int code = objError.find_value("code").getInt<int>();
83 
84  if (code == RPC_INVALID_REQUEST) {
85  nStatus = HTTP_BAD_REQUEST;
86  } else if (code == RPC_METHOD_NOT_FOUND) {
87  nStatus = HTTP_NOT_FOUND;
88  }
89 
90  std::string strReply = JSONRPCReply(NullUniValue, objError, id);
91 
92  req->WriteHeader("Content-Type", "application/json");
93  req->WriteReply(nStatus, strReply);
94 }
95 
96 /*
97  * This function checks username and password against -rpcauth entries from
98  * config file.
99  */
100 static bool multiUserAuthorized(std::string strUserPass) {
101  if (strUserPass.find(':') == std::string::npos) {
102  return false;
103  }
104  std::string strUser = strUserPass.substr(0, strUserPass.find(':'));
105  std::string strPass = strUserPass.substr(strUserPass.find(':') + 1);
106 
107  for (const std::string &strRPCAuth : gArgs.GetArgs("-rpcauth")) {
108  // Search for multi-user login/pass "rpcauth" from config
109  std::vector<std::string> vFields;
110  boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
111  if (vFields.size() != 3) {
112  // Incorrect formatting in config file
113  continue;
114  }
115 
116  std::string strName = vFields[0];
117  if (!TimingResistantEqual(strName, strUser)) {
118  continue;
119  }
120 
121  std::string strSalt = vFields[1];
122  std::string strHash = vFields[2];
123 
124  static const unsigned int KEY_SIZE = 32;
125  uint8_t out[KEY_SIZE];
126 
127  CHMAC_SHA256(reinterpret_cast<const uint8_t *>(strSalt.data()),
128  strSalt.size())
129  .Write(reinterpret_cast<const uint8_t *>(strPass.data()),
130  strPass.size())
131  .Finalize(out);
132  std::vector<uint8_t> hexvec(out, out + KEY_SIZE);
133  std::string strHashFromPass = HexStr(hexvec);
134 
135  if (TimingResistantEqual(strHashFromPass, strHash)) {
136  return true;
137  }
138  }
139  return false;
140 }
141 
142 static bool RPCAuthorized(const std::string &strAuth,
143  std::string &strAuthUsernameOut) {
144  // Belt-and-suspenders measure if InitRPCAuthentication was not called.
145  if (strRPCUserColonPass.empty()) {
146  return false;
147  }
148 
149  if (strAuth.substr(0, 6) != "Basic ") {
150  return false;
151  }
152 
153  std::string strUserPass64 = strAuth.substr(6);
154  boost::trim(strUserPass64);
155  std::string strUserPass = DecodeBase64(strUserPass64);
156 
157  if (strUserPass.find(':') != std::string::npos) {
158  strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));
159  }
160 
161  // Check if authorized under single-user field
162  if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
163  return true;
164  }
165  return multiUserAuthorized(strUserPass);
166 }
167 
168 static bool checkCORS(HTTPRequest *req) {
169  // https://www.w3.org/TR/cors/#resource-requests
170 
171  // 1. If the Origin header is not present terminate this set of steps.
172  // The request is outside the scope of this specification.
173  std::pair<bool, std::string> origin = req->GetHeader("origin");
174  if (!origin.first) {
175  return false;
176  }
177 
178  // 2. If the value of the Origin header is not a case-sensitive match for
179  // any of the values in list of origins do not set any additional headers
180  // and terminate this set of steps.
181  // Note: Always matching is acceptable since the list of origins can be
182  // unbounded.
183  if (origin.second != strRPCCORSDomain) {
184  return false;
185  }
186 
187  if (req->GetRequestMethod() == HTTPRequest::OPTIONS) {
188  // 6.2 Preflight Request
189  // In response to a preflight request the resource indicates which
190  // methods and headers (other than simple methods and simple
191  // headers) it is willing to handle and whether it supports
192  // credentials.
193  // Resources must use the following set of steps to determine which
194  // additional headers to use in the response:
195 
196  // 3. Let method be the value as result of parsing the
197  // Access-Control-Request-Method header.
198  // If there is no Access-Control-Request-Method header or if parsing
199  // failed, do not set any additional headers and terminate this set
200  // of steps. The request is outside the scope of this specification.
201  std::pair<bool, std::string> method =
202  req->GetHeader("access-control-request-method");
203  if (!method.first) {
204  return false;
205  }
206 
207  // 4. Let header field-names be the values as result of parsing
208  // the Access-Control-Request-Headers headers.
209  // If there are no Access-Control-Request-Headers headers let header
210  // field-names be the empty list.
211  // If parsing failed do not set any additional headers and terminate
212  // this set of steps. The request is outside the scope of this
213  // specification.
214  std::pair<bool, std::string> header_field_names =
215  req->GetHeader("access-control-request-headers");
216 
217  // 5. If method is not a case-sensitive match for any of the
218  // values in list of methods do not set any additional headers
219  // and terminate this set of steps.
220  // Note: Always matching is acceptable since the list of methods
221  // can be unbounded.
222  if (method.second != "POST") {
223  return false;
224  }
225 
226  // 6. If any of the header field-names is not a ASCII case-
227  // insensitive match for any of the values in list of headers do not
228  // set any additional headers and terminate this set of steps.
229  // Note: Always matching is acceptable since the list of headers can
230  // be unbounded.
231  const std::string &list_of_headers = "authorization,content-type";
232 
233  // 7. If the resource supports credentials add a single
234  // Access-Control-Allow-Origin header, with the value of the Origin
235  // header as value, and add a single
236  // Access-Control-Allow-Credentials header with the case-sensitive
237  // string "true" as value.
238  req->WriteHeader("Access-Control-Allow-Origin", origin.second);
239  req->WriteHeader("Access-Control-Allow-Credentials", "true");
240 
241  // 8. Optionally add a single Access-Control-Max-Age header with as
242  // value the amount of seconds the user agent is allowed to cache
243  // the result of the request.
244 
245  // 9. If method is a simple method this step may be skipped.
246  // Add one or more Access-Control-Allow-Methods headers consisting
247  // of (a subset of) the list of methods.
248  // If a method is a simple method it does not need to be listed, but
249  // this is not prohibited.
250  // Note: Since the list of methods can be unbounded, simply
251  // returning the method indicated by
252  // Access-Control-Request-Method (if supported) can be enough.
253  req->WriteHeader("Access-Control-Allow-Methods", method.second);
254 
255  // 10. If each of the header field-names is a simple header and none
256  // is Content-Type, this step may be skipped.
257  // Add one or more Access-Control-Allow-Headers headers consisting
258  // of (a subset of) the list of headers.
259  req->WriteHeader("Access-Control-Allow-Headers",
260  header_field_names.first ? header_field_names.second
261  : list_of_headers);
262  req->WriteReply(HTTP_OK);
263  return true;
264  }
265 
266  // 6.1 Simple Cross-Origin Request, Actual Request, and Redirects
267  // In response to a simple cross-origin request or actual request the
268  // resource indicates whether or not to share the response.
269  // If the resource has been relocated, it indicates whether to share its
270  // new URL.
271  // Resources must use the following set of steps to determine which
272  // additional headers to use in the response:
273 
274  // 3. If the resource supports credentials add a single
275  // Access-Control-Allow-Origin header, with the value of the Origin
276  // header as value, and add a single Access-Control-Allow-Credentials
277  // header with the case-sensitive string "true" as value.
278  req->WriteHeader("Access-Control-Allow-Origin", origin.second);
279  req->WriteHeader("Access-Control-Allow-Credentials", "true");
280 
281  // 4. If the list of exposed headers is not empty add one or more
282  // Access-Control-Expose-Headers headers, with as values the header
283  // field names given in the list of exposed headers.
284  req->WriteHeader("Access-Control-Expose-Headers", "WWW-Authenticate");
285 
286  return false;
287 }
288 
290  // First, check and/or set CORS headers
291  if (checkCORS(req)) {
292  return true;
293  }
294 
295  // JSONRPC handles only POST
296  if (req->GetRequestMethod() != HTTPRequest::POST) {
298  "JSONRPC server handles only POST requests");
299  return false;
300  }
301  // Check authorization
302  std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
303  if (!authHeader.first) {
304  req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
306  return false;
307  }
308 
309  JSONRPCRequest jreq;
310  jreq.context = context;
311  jreq.peerAddr = req->GetPeer().ToString();
312  if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
313  LogPrintf("ThreadRPCServer incorrect password attempt from %s\n",
314  jreq.peerAddr);
315 
322  std::chrono::milliseconds{RPC_AUTH_BRUTE_FORCE_DELAY});
323 
324  req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
326  return false;
327  }
328 
329  try {
330  // Parse request
331  UniValue valRequest;
332  if (!valRequest.read(req->ReadBody())) {
333  throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
334  }
335 
336  // Set the URI
337  jreq.URI = req->GetURI();
338 
339  std::string strReply;
340  bool user_has_whitelist = g_rpc_whitelist.count(jreq.authUser);
341  if (!user_has_whitelist && g_rpc_whitelist_default) {
342  LogPrintf("RPC User %s not allowed to call any methods\n",
343  jreq.authUser);
345  return false;
346 
347  // singleton request
348  } else if (valRequest.isObject()) {
349  jreq.parse(valRequest);
350  if (user_has_whitelist &&
351  !g_rpc_whitelist[jreq.authUser].count(jreq.strMethod)) {
352  LogPrintf("RPC User %s not allowed to call method %s\n",
353  jreq.authUser, jreq.strMethod);
355  return false;
356  }
357  UniValue result = rpcServer.ExecuteCommand(config, jreq);
358 
359  // Send reply
360  strReply = JSONRPCReply(result, NullUniValue, jreq.id);
361 
362  // array of requests
363  } else if (valRequest.isArray()) {
364  if (user_has_whitelist) {
365  for (unsigned int reqIdx = 0; reqIdx < valRequest.size();
366  reqIdx++) {
367  if (!valRequest[reqIdx].isObject()) {
369  "Invalid Request object");
370  } else {
371  const UniValue &request = valRequest[reqIdx].get_obj();
372  // Parse method
373  std::string strMethod =
374  request.find_value("method").get_str();
375  if (!g_rpc_whitelist[jreq.authUser].count(strMethod)) {
376  LogPrintf(
377  "RPC User %s not allowed to call method %s\n",
378  jreq.authUser, strMethod);
380  return false;
381  }
382  }
383  }
384  }
385  strReply = JSONRPCExecBatch(config, rpcServer, jreq,
386  valRequest.get_array());
387  } else {
388  throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
389  }
390 
391  req->WriteHeader("Content-Type", "application/json");
392  req->WriteReply(HTTP_OK, strReply);
393  } catch (const UniValue &objError) {
394  JSONErrorReply(req, objError, jreq.id);
395  return false;
396  } catch (const std::exception &e) {
397  JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
398  return false;
399  }
400  return true;
401 }
402 
403 static bool InitRPCAuthentication() {
404  if (gArgs.GetArg("-rpcpassword", "") == "") {
405  LogPrintf("Using random cookie authentication.\n");
407  return false;
408  }
409  } else {
410  LogPrintf("Config options rpcuser and rpcpassword will soon be "
411  "deprecated. Locally-run instances may remove rpcuser to use "
412  "cookie-based auth, or may be replaced with rpcauth. Please "
413  "see share/rpcauth for rpcauth auth generation.\n");
414  strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" +
415  gArgs.GetArg("-rpcpassword", "");
416  }
417 
418  strRPCCORSDomain = gArgs.GetArg("-rpccorsdomain", "");
419 
420  if (gArgs.GetArg("-rpcauth", "") != "") {
421  LogPrintf("Using rpcauth authentication.\n");
422  }
423 
424  g_rpc_whitelist_default = gArgs.GetBoolArg("-rpcwhitelistdefault",
425  gArgs.IsArgSet("-rpcwhitelist"));
426  for (const std::string &strRPCWhitelist : gArgs.GetArgs("-rpcwhitelist")) {
427  auto pos = strRPCWhitelist.find(':');
428  std::string strUser = strRPCWhitelist.substr(0, pos);
429  bool intersect = g_rpc_whitelist.count(strUser);
430  std::set<std::string> &whitelist = g_rpc_whitelist[strUser];
431  if (pos != std::string::npos) {
432  std::string strWhitelist = strRPCWhitelist.substr(pos + 1);
433  std::set<std::string> new_whitelist;
434  boost::split(new_whitelist, strWhitelist, boost::is_any_of(", "));
435  if (intersect) {
436  std::set<std::string> tmp_whitelist;
437  std::set_intersection(
438  new_whitelist.begin(), new_whitelist.end(),
439  whitelist.begin(), whitelist.end(),
440  std::inserter(tmp_whitelist, tmp_whitelist.end()));
441  new_whitelist = std::move(tmp_whitelist);
442  }
443  whitelist = std::move(new_whitelist);
444  }
445  }
446 
447  return true;
448 }
449 
450 bool StartHTTPRPC(HTTPRPCRequestProcessor &httpRPCRequestProcessor) {
451  LogPrint(BCLog::RPC, "Starting HTTP RPC server\n");
452  if (!InitRPCAuthentication()) {
453  return false;
454  }
455 
456  const std::function<bool(Config &, HTTPRequest *, const std::string &)>
457  &rpcFunction =
459  &httpRPCRequestProcessor, std::placeholders::_2);
460  RegisterHTTPHandler("/", true, rpcFunction);
462  RegisterHTTPHandler("/wallet/", false, rpcFunction);
463  }
464  struct event_base *eventBase = EventBase();
465  assert(eventBase);
466  httpRPCTimerInterface = std::make_unique<HTTPRPCTimerInterface>(eventBase);
468  return true;
469 }
470 
472  LogPrint(BCLog::RPC, "Interrupting HTTP RPC server\n");
473 }
474 
475 void StopHTTPRPC() {
476  LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
477  UnregisterHTTPHandler("/", true);
479  UnregisterHTTPHandler("/wallet/", false);
480  }
481  if (httpRPCTimerInterface) {
483  httpRPCTimerInterface.reset();
484  }
485 }
ArgsManager gArgs
Definition: args.cpp:38
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
Definition: args.cpp:371
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:381
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:494
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:556
A hasher class for HMAC-SHA-256.
Definition: hmac_sha256.h:14
CHMAC_SHA256 & Write(const uint8_t *data, size_t len)
Definition: hmac_sha256.h:23
void Finalize(uint8_t hash[OUTPUT_SIZE])
Definition: hmac_sha256.cpp:30
std::string ToString() const
Definition: config.h:19
Event class.
Definition: httpserver.h:139
void trigger(struct timeval *tv)
Trigger the event.
Definition: httpserver.cpp:539
bool ProcessHTTPRequest(HTTPRequest *request)
Definition: httprpc.cpp:289
const std::any & context
Definition: httprpc.h:23
RPCServer & rpcServer
Definition: httprpc.h:18
static bool DelegateHTTPRequest(HTTPRPCRequestProcessor *requestProcessor, HTTPRequest *request)
Definition: httprpc.h:29
Simple one-shot callback timer to be used by the RPC mechanism to e.g.
Definition: httprpc.cpp:38
HTTPRPCTimer(struct event_base *eventBase, std::function< void()> &func, int64_t millis)
Definition: httprpc.cpp:40
HTTPEvent ev
Definition: httprpc.cpp:50
const char * Name() override
Implementation name.
Definition: httprpc.cpp:57
RPCTimerBase * NewTimer(std::function< void()> &func, int64_t millis) override
Factory function for timers.
Definition: httprpc.cpp:59
struct event_base * base
Definition: httprpc.cpp:65
HTTPRPCTimerInterface(struct event_base *_base)
Definition: httprpc.cpp:55
In-flight HTTP request.
Definition: httpserver.h:74
std::pair< bool, std::string > GetHeader(const std::string &hdr) const
Get the request header specified by hdr, or an empty string.
Definition: httpserver.cpp:560
std::string GetURI() const
Get requested URI.
Definition: httpserver.cpp:651
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
Definition: httpserver.cpp:607
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
Definition: httpserver.cpp:595
RequestMethod GetRequestMethod() const
Get request method.
Definition: httpserver.cpp:655
std::string ReadBody()
Read request body.
Definition: httpserver.cpp:571
CService GetPeer() const
Get CService (address:ip) for the origin of the http request.
Definition: httpserver.cpp:638
std::string strMethod
Definition: request.h:33
std::string peerAddr
Definition: request.h:38
UniValue id
Definition: request.h:32
void parse(const UniValue &valRequest)
Definition: request.cpp:164
std::string URI
Definition: request.h:36
std::string authUser
Definition: request.h:37
std::any context
Definition: request.h:39
UniValue ExecuteCommand(const Config &config, const JSONRPCRequest &request) const
Attempts to execute an RPC command from the given request.
Definition: server.cpp:71
Opaque base class for timers returned by NewTimerFunc.
Definition: server.h:92
RPC timer "driver".
Definition: server.h:100
const std::string & get_str() const
bool isArray() const
Definition: univalue.h:110
const UniValue & find_value(std::string_view key) const
Definition: univalue.cpp:229
const UniValue & get_obj() const
size_t size() const
Definition: univalue.h:92
bool read(std::string_view raw)
Int getInt() const
Definition: univalue.h:157
const UniValue & get_array() const
bool isObject() const
Definition: univalue.h:111
virtual bool HasWalletSupport() const =0
Is the wallet component enabled.
const WalletInitInterface & g_wallet_init_interface
Definition: dummywallet.cpp:40
static bool checkCORS(HTTPRequest *req)
Definition: httprpc.cpp:168
static const char * WWW_AUTH_HEADER_DATA
WWW-Authenticate to present with 401 Unauthorized response.
Definition: httprpc.cpp:29
void InterruptHTTPRPC()
Interrupt HTTP RPC subsystem.
Definition: httprpc.cpp:471
void StopHTTPRPC()
Stop HTTP RPC subsystem.
Definition: httprpc.cpp:475
static std::unique_ptr< HTTPRPCTimerInterface > httpRPCTimerInterface
Definition: httprpc.cpp:73
static std::string strRPCCORSDomain
Definition: httprpc.cpp:71
static bool multiUserAuthorized(std::string strUserPass)
Definition: httprpc.cpp:100
static bool g_rpc_whitelist_default
Definition: httprpc.cpp:76
static bool RPCAuthorized(const std::string &strAuth, std::string &strAuthUsernameOut)
Definition: httprpc.cpp:142
static std::string strRPCUserColonPass
Definition: httprpc.cpp:69
static bool InitRPCAuthentication()
Definition: httprpc.cpp:403
static std::map< std::string, std::set< std::string > > g_rpc_whitelist
Definition: httprpc.cpp:75
bool StartHTTPRPC(HTTPRPCRequestProcessor &httpRPCRequestProcessor)
Start HTTP RPC subsystem.
Definition: httprpc.cpp:450
static const int64_t RPC_AUTH_BRUTE_FORCE_DELAY
RPC auth failure delay to make brute-forcing expensive.
Definition: httprpc.cpp:32
static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, const UniValue &id)
Definition: httprpc.cpp:78
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
Definition: httpserver.cpp:679
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Definition: httpserver.cpp:672
struct event_base * EventBase()
Return evhttp event base.
Definition: httpserver.cpp:517
static struct event_base * eventBase
HTTP module state.
Definition: httpserver.cpp:135
#define LogPrint(category,...)
Definition: logging.h:211
#define LogPrintf(...)
Definition: logging.h:207
@ RPC
Definition: logging.h:47
std::string JSONRPCReply(const UniValue &result, const UniValue &error, const UniValue &id)
Definition: request.cpp:52
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
bool GenerateAuthCookie(std::string *cookie_out)
Generate a new RPC authentication cookie and write it to disk.
Definition: request.cpp:82
@ HTTP_BAD_REQUEST
Definition: protocol.h:12
@ HTTP_BAD_METHOD
Definition: protocol.h:16
@ HTTP_OK
Definition: protocol.h:11
@ HTTP_UNAUTHORIZED
Definition: protocol.h:13
@ HTTP_NOT_FOUND
Definition: protocol.h:15
@ HTTP_FORBIDDEN
Definition: protocol.h:14
@ HTTP_INTERNAL_SERVER_ERROR
Definition: protocol.h:17
@ RPC_PARSE_ERROR
Definition: protocol.h:34
@ RPC_METHOD_NOT_FOUND
Definition: protocol.h:29
@ RPC_INVALID_REQUEST
Standard JSON-RPC 2.0 errors.
Definition: protocol.h:26
void RPCUnsetTimerInterface(RPCTimerInterface *iface)
Unset factory function for timers.
Definition: server.cpp:658
std::string JSONRPCExecBatch(const Config &config, RPCServer &rpcServer, const JSONRPCRequest &jreq, const UniValue &vReq)
Definition: server.cpp:435
void RPCSetTimerInterface(RPCTimerInterface *iface)
Set the factory function for timers.
Definition: server.cpp:654
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::vector< uint8_t > DecodeBase64(const char *p, bool *pf_invalid)
bool TimingResistantEqual(const T &a, const T &b)
Timing-attack-resistant comparison.
Definition: strencodings.h:186
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:23
const UniValue NullUniValue
Definition: univalue.cpp:16
assert(!tx.IsCoinBase())