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