Bitcoin ABC 0.33.3
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 <common/args.h>
8#include <config.h>
10#include <logging.h>
11#include <rpc/protocol.h>
12#include <util/strencodings.h>
13#include <util/string.h>
14#include <walletinitinterface.h>
15
16#include <algorithm>
17#include <cstdio>
18#include <functional>
19#include <iterator>
20#include <map>
21#include <memory>
22#include <set>
23#include <string>
24#include <vector>
25
28
30static const char *WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
31
33static const int64_t RPC_AUTH_BRUTE_FORCE_DELAY = 250;
34
39class HTTPRPCTimer : public RPCTimerBase {
40public:
41 HTTPRPCTimer(struct event_base *eventBase, std::function<void()> &func,
42 int64_t millis)
43 : ev(eventBase, false, func) {
44 struct timeval tv;
45 tv.tv_sec = millis / 1000;
46 tv.tv_usec = (millis % 1000) * 1000;
47 ev.trigger(&tv);
48 }
49
50private:
52};
53
55public:
56 explicit HTTPRPCTimerInterface(struct event_base *_base) : base(_base) {}
57
58 const char *Name() override { return "HTTP"; }
59
60 RPCTimerBase *NewTimer(std::function<void()> &func,
61 int64_t millis) override {
62 return new HTTPRPCTimer(base, func, millis);
63 }
64
65private:
66 struct event_base *base;
67};
68
69/* Pre-base64-encoded authentication token */
70static std::string strRPCUserColonPass;
71/* Pre-base64-encoded authentication token */
72static std::string strRPCCORSDomain;
73/* Stored RPC timer interface (for unregistration) */
74static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
75/* List of -rpcauth values */
76static std::vector<std::vector<std::string>> g_rpcauth;
77/* RPC Auth Whitelist */
78static std::map<std::string, std::set<std::string>> g_rpc_whitelist;
79static bool g_rpc_whitelist_default = false;
80
81static void JSONErrorReply(HTTPRequest *req, const UniValue &objError,
82 const UniValue &id) {
83 // Send error reply from json-rpc error object.
84 int nStatus = HTTP_INTERNAL_SERVER_ERROR;
85 int code = objError.find_value("code").getInt<int>();
86
87 if (code == RPC_INVALID_REQUEST) {
88 nStatus = HTTP_BAD_REQUEST;
89 } else if (code == RPC_METHOD_NOT_FOUND) {
90 nStatus = HTTP_NOT_FOUND;
91 }
92
93 std::string strReply = JSONRPCReply(NullUniValue, objError, id);
94
95 req->WriteHeader("Content-Type", "application/json");
96 req->WriteReply(nStatus, strReply);
97}
98
99/*
100 * This function checks username and password against -rpcauth entries from
101 * config file.
102 */
103static bool multiUserAuthorized(std::string strUserPass) {
104 if (strUserPass.find(':') == std::string::npos) {
105 return false;
106 }
107 std::string strUser = strUserPass.substr(0, strUserPass.find(':'));
108 std::string strPass = strUserPass.substr(strUserPass.find(':') + 1);
109
110 for (const auto &vFields : g_rpcauth) {
111 std::string strName = vFields[0];
112 if (!TimingResistantEqual(strName, strUser)) {
113 continue;
114 }
115
116 std::string strSalt = vFields[1];
117 std::string strHash = vFields[2];
118
119 static const unsigned int KEY_SIZE = 32;
120 uint8_t out[KEY_SIZE];
121
122 CHMAC_SHA256(reinterpret_cast<const uint8_t *>(strSalt.data()),
123 strSalt.size())
124 .Write(reinterpret_cast<const uint8_t *>(strPass.data()),
125 strPass.size())
126 .Finalize(out);
127 std::vector<uint8_t> hexvec(out, out + KEY_SIZE);
128 std::string strHashFromPass = HexStr(hexvec);
129
130 if (TimingResistantEqual(strHashFromPass, strHash)) {
131 return true;
132 }
133 }
134 return false;
135}
136
137static bool RPCAuthorized(const std::string &strAuth,
138 std::string &strAuthUsernameOut) {
139 // Belt-and-suspenders measure if InitRPCAuthentication was not called.
140 if (strRPCUserColonPass.empty()) {
141 return false;
142 }
143
144 if (strAuth.substr(0, 6) != "Basic ") {
145 return false;
146 }
147
148 std::string_view strUserPass64 =
149 TrimStringView(std::string_view{strAuth}.substr(6));
150 auto userpass_data = DecodeBase64(strUserPass64);
151 std::string strUserPass;
152 if (!userpass_data) {
153 return false;
154 }
155 strUserPass.assign(userpass_data->begin(), userpass_data->end());
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
168static 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
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().ToStringAddrPort();
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
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 for (const std::string &rpcauth : gArgs.GetArgs("-rpcauth")) {
423 std::vector<std::string> fields{SplitString(rpcauth, ':')};
424 const std::vector<std::string> salt_hmac{
425 SplitString(fields.back(), '$')};
426 if (fields.size() == 2 && salt_hmac.size() == 2) {
427 fields.pop_back();
428 fields.insert(fields.end(), salt_hmac.begin(), salt_hmac.end());
429 g_rpcauth.push_back(fields);
430 } else {
431 LogPrintf("Invalid -rpcauth argument.\n");
432 return false;
433 }
434 }
435 }
436
437 g_rpc_whitelist_default = gArgs.GetBoolArg("-rpcwhitelistdefault",
438 gArgs.IsArgSet("-rpcwhitelist"));
439 for (const std::string &strRPCWhitelist : gArgs.GetArgs("-rpcwhitelist")) {
440 auto pos = strRPCWhitelist.find(':');
441 std::string strUser = strRPCWhitelist.substr(0, pos);
442 bool intersect = g_rpc_whitelist.count(strUser);
443 std::set<std::string> &whitelist = g_rpc_whitelist[strUser];
444 if (pos != std::string::npos) {
445 std::string strWhitelist = strRPCWhitelist.substr(pos + 1);
446 std::vector<std::string> whitelist_split =
447 SplitString(strWhitelist, ", ");
448 std::set<std::string> new_whitelist{
449 std::make_move_iterator(whitelist_split.begin()),
450 std::make_move_iterator(whitelist_split.end())};
451 if (intersect) {
452 std::set<std::string> tmp_whitelist;
453 std::set_intersection(
454 new_whitelist.begin(), new_whitelist.end(),
455 whitelist.begin(), whitelist.end(),
456 std::inserter(tmp_whitelist, tmp_whitelist.end()));
457 new_whitelist = std::move(tmp_whitelist);
458 }
459 whitelist = std::move(new_whitelist);
460 }
461 }
462
463 return true;
464}
465
466bool StartHTTPRPC(HTTPRPCRequestProcessor &httpRPCRequestProcessor) {
467 LogPrint(BCLog::RPC, "Starting HTTP RPC server\n");
468 if (!InitRPCAuthentication()) {
469 return false;
470 }
471
472 const std::function<bool(Config &, HTTPRequest *, const std::string &)>
473 &rpcFunction =
475 &httpRPCRequestProcessor, std::placeholders::_2);
476 RegisterHTTPHandler("/", true, rpcFunction);
478 RegisterHTTPHandler("/wallet/", false, rpcFunction);
479 }
480 struct event_base *eventBase = EventBase();
482 httpRPCTimerInterface = std::make_unique<HTTPRPCTimerInterface>(eventBase);
484 return true;
485}
486
488 LogPrint(BCLog::RPC, "Interrupting HTTP RPC server\n");
489}
490
492 LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
493 UnregisterHTTPHandler("/", true);
495 UnregisterHTTPHandler("/wallet/", false);
496 }
499 httpRPCTimerInterface.reset();
500 }
501}
ArgsManager gArgs
Definition: args.cpp:39
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
Definition: args.cpp:361
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:371
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:462
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:524
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 ToStringAddrPort() const
Definition: config.h:19
Event class.
Definition: httpserver.h:136
void trigger(struct timeval *tv)
Trigger the event.
Definition: httpserver.cpp:633
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:39
HTTPRPCTimer(struct event_base *eventBase, std::function< void()> &func, int64_t millis)
Definition: httprpc.cpp:41
HTTPEvent ev
Definition: httprpc.cpp:51
const char * Name() override
Implementation name.
Definition: httprpc.cpp:58
RPCTimerBase * NewTimer(std::function< void()> &func, int64_t millis) override
Factory function for timers.
Definition: httprpc.cpp:60
struct event_base * base
Definition: httprpc.cpp:66
HTTPRPCTimerInterface(struct event_base *_base)
Definition: httprpc.cpp:56
In-flight HTTP request.
Definition: httpserver.h:71
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:654
std::string GetURI() const
Get requested URI.
Definition: httpserver.cpp:745
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
Definition: httpserver.cpp:701
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
Definition: httpserver.cpp:689
RequestMethod GetRequestMethod() const
Get request method.
Definition: httpserver.cpp:749
std::string ReadBody()
Read request body.
Definition: httpserver.cpp:665
CService GetPeer() const
Get CService (address:ip) for the origin of the http request.
Definition: httpserver.cpp:732
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:73
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
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:30
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:30
void InterruptHTTPRPC()
Interrupt HTTP RPC subsystem.
Definition: httprpc.cpp:487
void StopHTTPRPC()
Stop HTTP RPC subsystem.
Definition: httprpc.cpp:491
static std::unique_ptr< HTTPRPCTimerInterface > httpRPCTimerInterface
Definition: httprpc.cpp:74
static std::string strRPCCORSDomain
Definition: httprpc.cpp:72
static bool multiUserAuthorized(std::string strUserPass)
Definition: httprpc.cpp:103
static bool g_rpc_whitelist_default
Definition: httprpc.cpp:79
static bool RPCAuthorized(const std::string &strAuth, std::string &strAuthUsernameOut)
Definition: httprpc.cpp:137
static std::vector< std::vector< std::string > > g_rpcauth
Definition: httprpc.cpp:76
static std::string strRPCUserColonPass
Definition: httprpc.cpp:70
static bool InitRPCAuthentication()
Definition: httprpc.cpp:403
static std::map< std::string, std::set< std::string > > g_rpc_whitelist
Definition: httprpc.cpp:78
bool StartHTTPRPC(HTTPRPCRequestProcessor &httpRPCRequestProcessor)
Start HTTP RPC subsystem.
Definition: httprpc.cpp:466
static const int64_t RPC_AUTH_BRUTE_FORCE_DELAY
RPC auth failure delay to make brute-forcing expensive.
Definition: httprpc.cpp:33
static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, const UniValue &id)
Definition: httprpc.cpp:81
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
Definition: httpserver.cpp:773
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Definition: httpserver.cpp:766
static struct event_base * eventBase
HTTP module state.
Definition: httpserver.cpp:139
struct event_base * EventBase()
Return evhttp event base.
Definition: httpserver.cpp:611
#define LogPrint(category,...)
Definition: logging.h:452
#define LogPrintf(...)
Definition: logging.h:424
@ RPC
Definition: logging.h:76
std::vector< std::string > SplitString(std::string_view str, char sep)
Definition: string.h:59
std::string_view TrimStringView(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:70
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:662
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:658
bool TimingResistantEqual(const T &a, const T &b)
Timing-attack-resistant comparison.
Definition: strencodings.h:233
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:21
const UniValue NullUniValue
Definition: univalue.cpp:16
std::optional< std::vector< uint8_t > > DecodeBase64(std::string_view str)
assert(!tx.IsCoinBase())