Bitcoin Core  0.20.99
P2P Digital Currency
rest.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-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 <chain.h>
7 #include <chainparams.h>
8 #include <core_io.h>
9 #include <httpserver.h>
10 #include <index/txindex.h>
11 #include <node/context.h>
12 #include <primitives/block.h>
13 #include <primitives/transaction.h>
14 #include <rpc/blockchain.h>
15 #include <rpc/protocol.h>
16 #include <rpc/server.h>
17 #include <streams.h>
18 #include <sync.h>
19 #include <txmempool.h>
20 #include <util/check.h>
21 #include <util/ref.h>
22 #include <util/strencodings.h>
23 #include <validation.h>
24 #include <version.h>
25 
26 #include <boost/algorithm/string.hpp>
27 
28 #include <univalue.h>
29 
30 static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
31 
32 enum class RetFormat {
33  UNDEF,
34  BINARY,
35  HEX,
36  JSON,
37 };
38 
39 static const struct {
41  const char* name;
42 } rf_names[] = {
43  {RetFormat::UNDEF, ""},
44  {RetFormat::BINARY, "bin"},
45  {RetFormat::HEX, "hex"},
46  {RetFormat::JSON, "json"},
47 };
48 
49 struct CCoin {
50  uint32_t nHeight;
52 
53  CCoin() : nHeight(0) {}
54  explicit CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}
55 
57  {
58  uint32_t nTxVerDummy = 0;
59  READWRITE(nTxVerDummy, obj.nHeight, obj.out);
60  }
61 };
62 
63 static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string message)
64 {
65  req->WriteHeader("Content-Type", "text/plain");
66  req->WriteReply(status, message + "\r\n");
67  return false;
68 }
69 
77 static NodeContext* GetNodeContext(const util::Ref& context, HTTPRequest* req)
78 {
79  NodeContext* node = context.Has<NodeContext>() ? &context.Get<NodeContext>() : nullptr;
80  if (!node) {
82  strprintf("%s:%d (%s)\n"
83  "Internal bug detected: Node context not found!\n"
84  "You may report this issue here: %s\n",
85  __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT));
86  return nullptr;
87  }
88  return node;
89 }
90 
98 static CTxMemPool* GetMemPool(const util::Ref& context, HTTPRequest* req)
99 {
100  NodeContext* node = context.Has<NodeContext>() ? &context.Get<NodeContext>() : nullptr;
101  if (!node || !node->mempool) {
102  RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found");
103  return nullptr;
104  }
105  return node->mempool.get();
106 }
107 
108 static RetFormat ParseDataFormat(std::string& param, const std::string& strReq)
109 {
110  const std::string::size_type pos = strReq.rfind('.');
111  if (pos == std::string::npos)
112  {
113  param = strReq;
114  return rf_names[0].rf;
115  }
116 
117  param = strReq.substr(0, pos);
118  const std::string suff(strReq, pos + 1);
119 
120  for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
121  if (suff == rf_names[i].name)
122  return rf_names[i].rf;
123 
124  /* If no suffix is found, return original string. */
125  param = strReq;
126  return rf_names[0].rf;
127 }
128 
129 static std::string AvailableDataFormatsString()
130 {
131  std::string formats;
132  for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
133  if (strlen(rf_names[i].name) > 0) {
134  formats.append(".");
135  formats.append(rf_names[i].name);
136  formats.append(", ");
137  }
138 
139  if (formats.length() > 0)
140  return formats.substr(0, formats.length() - 2);
141 
142  return formats;
143 }
144 
145 static bool CheckWarmup(HTTPRequest* req)
146 {
147  std::string statusmessage;
148  if (RPCIsInWarmup(&statusmessage))
149  return RESTERR(req, HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: " + statusmessage);
150  return true;
151 }
152 
153 static bool rest_headers(const util::Ref& context,
154  HTTPRequest* req,
155  const std::string& strURIPart)
156 {
157  if (!CheckWarmup(req))
158  return false;
159  std::string param;
160  const RetFormat rf = ParseDataFormat(param, strURIPart);
161  std::vector<std::string> path;
162  boost::split(path, param, boost::is_any_of("/"));
163 
164  if (path.size() != 2)
165  return RESTERR(req, HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
166 
167  long count = strtol(path[0].c_str(), nullptr, 10);
168  if (count < 1 || count > 2000)
169  return RESTERR(req, HTTP_BAD_REQUEST, "Header count out of range: " + path[0]);
170 
171  std::string hashStr = path[1];
172  uint256 hash;
173  if (!ParseHashStr(hashStr, hash))
174  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
175 
176  const CBlockIndex* tip = nullptr;
177  std::vector<const CBlockIndex *> headers;
178  headers.reserve(count);
179  {
180  LOCK(cs_main);
181  tip = ::ChainActive().Tip();
182  const CBlockIndex* pindex = LookupBlockIndex(hash);
183  while (pindex != nullptr && ::ChainActive().Contains(pindex)) {
184  headers.push_back(pindex);
185  if (headers.size() == (unsigned long)count)
186  break;
187  pindex = ::ChainActive().Next(pindex);
188  }
189  }
190 
191  switch (rf) {
192  case RetFormat::BINARY: {
194  for (const CBlockIndex *pindex : headers) {
195  ssHeader << pindex->GetBlockHeader();
196  }
197 
198  std::string binaryHeader = ssHeader.str();
199  req->WriteHeader("Content-Type", "application/octet-stream");
200  req->WriteReply(HTTP_OK, binaryHeader);
201  return true;
202  }
203 
204  case RetFormat::HEX: {
206  for (const CBlockIndex *pindex : headers) {
207  ssHeader << pindex->GetBlockHeader();
208  }
209 
210  std::string strHex = HexStr(ssHeader) + "\n";
211  req->WriteHeader("Content-Type", "text/plain");
212  req->WriteReply(HTTP_OK, strHex);
213  return true;
214  }
215  case RetFormat::JSON: {
216  UniValue jsonHeaders(UniValue::VARR);
217  for (const CBlockIndex *pindex : headers) {
218  jsonHeaders.push_back(blockheaderToJSON(tip, pindex));
219  }
220  std::string strJSON = jsonHeaders.write() + "\n";
221  req->WriteHeader("Content-Type", "application/json");
222  req->WriteReply(HTTP_OK, strJSON);
223  return true;
224  }
225  default: {
226  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: .bin, .hex, .json)");
227  }
228  }
229 }
230 
231 static bool rest_block(HTTPRequest* req,
232  const std::string& strURIPart,
233  bool showTxDetails)
234 {
235  if (!CheckWarmup(req))
236  return false;
237  std::string hashStr;
238  const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
239 
240  uint256 hash;
241  if (!ParseHashStr(hashStr, hash))
242  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
243 
244  CBlock block;
245  CBlockIndex* pblockindex = nullptr;
246  CBlockIndex* tip = nullptr;
247  {
248  LOCK(cs_main);
249  tip = ::ChainActive().Tip();
250  pblockindex = LookupBlockIndex(hash);
251  if (!pblockindex) {
252  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
253  }
254 
255  if (IsBlockPruned(pblockindex))
256  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
257 
258  if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
259  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
260  }
261 
262  switch (rf) {
263  case RetFormat::BINARY: {
265  ssBlock << block;
266  std::string binaryBlock = ssBlock.str();
267  req->WriteHeader("Content-Type", "application/octet-stream");
268  req->WriteReply(HTTP_OK, binaryBlock);
269  return true;
270  }
271 
272  case RetFormat::HEX: {
274  ssBlock << block;
275  std::string strHex = HexStr(ssBlock) + "\n";
276  req->WriteHeader("Content-Type", "text/plain");
277  req->WriteReply(HTTP_OK, strHex);
278  return true;
279  }
280 
281  case RetFormat::JSON: {
282  UniValue objBlock = blockToJSON(block, tip, pblockindex, showTxDetails);
283  std::string strJSON = objBlock.write() + "\n";
284  req->WriteHeader("Content-Type", "application/json");
285  req->WriteReply(HTTP_OK, strJSON);
286  return true;
287  }
288 
289  default: {
290  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
291  }
292  }
293 }
294 
295 static bool rest_block_extended(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
296 {
297  return rest_block(req, strURIPart, true);
298 }
299 
300 static bool rest_block_notxdetails(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
301 {
302  return rest_block(req, strURIPart, false);
303 }
304 
305 // A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
307 
308 static bool rest_chaininfo(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
309 {
310  if (!CheckWarmup(req))
311  return false;
312  std::string param;
313  const RetFormat rf = ParseDataFormat(param, strURIPart);
314 
315  switch (rf) {
316  case RetFormat::JSON: {
317  JSONRPCRequest jsonRequest(context);
318  jsonRequest.params = UniValue(UniValue::VARR);
319  UniValue chainInfoObject = getblockchaininfo().HandleRequest(jsonRequest);
320  std::string strJSON = chainInfoObject.write() + "\n";
321  req->WriteHeader("Content-Type", "application/json");
322  req->WriteReply(HTTP_OK, strJSON);
323  return true;
324  }
325  default: {
326  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
327  }
328  }
329 }
330 
331 static bool rest_mempool_info(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
332 {
333  if (!CheckWarmup(req))
334  return false;
335  const CTxMemPool* mempool = GetMemPool(context, req);
336  if (!mempool) return false;
337  std::string param;
338  const RetFormat rf = ParseDataFormat(param, strURIPart);
339 
340  switch (rf) {
341  case RetFormat::JSON: {
342  UniValue mempoolInfoObject = MempoolInfoToJSON(*mempool);
343 
344  std::string strJSON = mempoolInfoObject.write() + "\n";
345  req->WriteHeader("Content-Type", "application/json");
346  req->WriteReply(HTTP_OK, strJSON);
347  return true;
348  }
349  default: {
350  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
351  }
352  }
353 }
354 
355 static bool rest_mempool_contents(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
356 {
357  if (!CheckWarmup(req)) return false;
358  const CTxMemPool* mempool = GetMemPool(context, req);
359  if (!mempool) return false;
360  std::string param;
361  const RetFormat rf = ParseDataFormat(param, strURIPart);
362 
363  switch (rf) {
364  case RetFormat::JSON: {
365  UniValue mempoolObject = MempoolToJSON(*mempool, true);
366 
367  std::string strJSON = mempoolObject.write() + "\n";
368  req->WriteHeader("Content-Type", "application/json");
369  req->WriteReply(HTTP_OK, strJSON);
370  return true;
371  }
372  default: {
373  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
374  }
375  }
376 }
377 
378 static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
379 {
380  if (!CheckWarmup(req))
381  return false;
382  std::string hashStr;
383  const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
384 
385  uint256 hash;
386  if (!ParseHashStr(hashStr, hash))
387  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
388 
389  if (g_txindex) {
390  g_txindex->BlockUntilSyncedToCurrentChain();
391  }
392 
393  const NodeContext* const node = GetNodeContext(context, req);
394  if (!node) return false;
395  uint256 hashBlock = uint256();
396  const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, node->mempool.get(), hash, Params().GetConsensus(), hashBlock);
397  if (!tx) {
398  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
399  }
400 
401  switch (rf) {
402  case RetFormat::BINARY: {
404  ssTx << tx;
405 
406  std::string binaryTx = ssTx.str();
407  req->WriteHeader("Content-Type", "application/octet-stream");
408  req->WriteReply(HTTP_OK, binaryTx);
409  return true;
410  }
411 
412  case RetFormat::HEX: {
414  ssTx << tx;
415 
416  std::string strHex = HexStr(ssTx) + "\n";
417  req->WriteHeader("Content-Type", "text/plain");
418  req->WriteReply(HTTP_OK, strHex);
419  return true;
420  }
421 
422  case RetFormat::JSON: {
423  UniValue objTx(UniValue::VOBJ);
424  TxToUniv(*tx, hashBlock, objTx);
425  std::string strJSON = objTx.write() + "\n";
426  req->WriteHeader("Content-Type", "application/json");
427  req->WriteReply(HTTP_OK, strJSON);
428  return true;
429  }
430 
431  default: {
432  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
433  }
434  }
435 }
436 
437 static bool rest_getutxos(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart)
438 {
439  if (!CheckWarmup(req))
440  return false;
441  std::string param;
442  const RetFormat rf = ParseDataFormat(param, strURIPart);
443 
444  std::vector<std::string> uriParts;
445  if (param.length() > 1)
446  {
447  std::string strUriParams = param.substr(1);
448  boost::split(uriParts, strUriParams, boost::is_any_of("/"));
449  }
450 
451  // throw exception in case of an empty request
452  std::string strRequestMutable = req->ReadBody();
453  if (strRequestMutable.length() == 0 && uriParts.size() == 0)
454  return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
455 
456  bool fInputParsed = false;
457  bool fCheckMemPool = false;
458  std::vector<COutPoint> vOutPoints;
459 
460  // parse/deserialize input
461  // input-format = output-format, rest/getutxos/bin requires binary input, gives binary output, ...
462 
463  if (uriParts.size() > 0)
464  {
465  //inputs is sent over URI scheme (/rest/getutxos/checkmempool/txid1-n/txid2-n/...)
466  if (uriParts[0] == "checkmempool") fCheckMemPool = true;
467 
468  for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
469  {
470  uint256 txid;
471  int32_t nOutput;
472  std::string strTxid = uriParts[i].substr(0, uriParts[i].find('-'));
473  std::string strOutput = uriParts[i].substr(uriParts[i].find('-')+1);
474 
475  if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
476  return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
477 
478  txid.SetHex(strTxid);
479  vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));
480  }
481 
482  if (vOutPoints.size() > 0)
483  fInputParsed = true;
484  else
485  return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
486  }
487 
488  switch (rf) {
489  case RetFormat::HEX: {
490  // convert hex to bin, continue then with bin part
491  std::vector<unsigned char> strRequestV = ParseHex(strRequestMutable);
492  strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
493  }
494 
495  case RetFormat::BINARY: {
496  try {
497  //deserialize only if user sent a request
498  if (strRequestMutable.size() > 0)
499  {
500  if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
501  return RESTERR(req, HTTP_BAD_REQUEST, "Combination of URI scheme inputs and raw post data is not allowed");
502 
504  oss << strRequestMutable;
505  oss >> fCheckMemPool;
506  oss >> vOutPoints;
507  }
508  } catch (const std::ios_base::failure&) {
509  // abort in case of unreadable binary data
510  return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
511  }
512  break;
513  }
514 
515  case RetFormat::JSON: {
516  if (!fInputParsed)
517  return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
518  break;
519  }
520  default: {
521  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
522  }
523  }
524 
525  // limit max outpoints
526  if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
527  return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
528 
529  // check spentness and form a bitmap (as well as a JSON capable human-readable string representation)
530  std::vector<unsigned char> bitmap;
531  std::vector<CCoin> outs;
532  std::string bitmapStringRepresentation;
533  std::vector<bool> hits;
534  bitmap.resize((vOutPoints.size() + 7) / 8);
535  {
536  auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView& view, const CTxMemPool& mempool) {
537  for (const COutPoint& vOutPoint : vOutPoints) {
538  Coin coin;
539  bool hit = !mempool.isSpent(vOutPoint) && view.GetCoin(vOutPoint, coin);
540  hits.push_back(hit);
541  if (hit) outs.emplace_back(std::move(coin));
542  }
543  };
544 
545  if (fCheckMemPool) {
546  const CTxMemPool* mempool = GetMemPool(context, req);
547  if (!mempool) return false;
548  // use db+mempool as cache backend in case user likes to query mempool
549  LOCK2(cs_main, mempool->cs);
551  CCoinsViewMemPool viewMempool(&viewChain, *mempool);
552  process_utxos(viewMempool, *mempool);
553  } else {
554  LOCK(cs_main); // no need to lock mempool!
555  process_utxos(::ChainstateActive().CoinsTip(), CTxMemPool());
556  }
557 
558  for (size_t i = 0; i < hits.size(); ++i) {
559  const bool hit = hits[i];
560  bitmapStringRepresentation.append(hit ? "1" : "0"); // form a binary string representation (human-readable for json output)
561  bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
562  }
563  }
564 
565  switch (rf) {
566  case RetFormat::BINARY: {
567  // serialize data
568  // use exact same output as mentioned in Bip64
569  CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
570  ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs;
571  std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
572 
573  req->WriteHeader("Content-Type", "application/octet-stream");
574  req->WriteReply(HTTP_OK, ssGetUTXOResponseString);
575  return true;
576  }
577 
578  case RetFormat::HEX: {
579  CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
580  ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs;
581  std::string strHex = HexStr(ssGetUTXOResponse) + "\n";
582 
583  req->WriteHeader("Content-Type", "text/plain");
584  req->WriteReply(HTTP_OK, strHex);
585  return true;
586  }
587 
588  case RetFormat::JSON: {
589  UniValue objGetUTXOResponse(UniValue::VOBJ);
590 
591  // pack in some essentials
592  // use more or less the same output as mentioned in Bip64
593  objGetUTXOResponse.pushKV("chainHeight", ::ChainActive().Height());
594  objGetUTXOResponse.pushKV("chaintipHash", ::ChainActive().Tip()->GetBlockHash().GetHex());
595  objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation);
596 
597  UniValue utxos(UniValue::VARR);
598  for (const CCoin& coin : outs) {
599  UniValue utxo(UniValue::VOBJ);
600  utxo.pushKV("height", (int32_t)coin.nHeight);
601  utxo.pushKV("value", ValueFromAmount(coin.out.nValue));
602 
603  // include the script in a json output
605  ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true);
606  utxo.pushKV("scriptPubKey", o);
607  utxos.push_back(utxo);
608  }
609  objGetUTXOResponse.pushKV("utxos", utxos);
610 
611  // return json string
612  std::string strJSON = objGetUTXOResponse.write() + "\n";
613  req->WriteHeader("Content-Type", "application/json");
614  req->WriteReply(HTTP_OK, strJSON);
615  return true;
616  }
617  default: {
618  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
619  }
620  }
621 }
622 
623 static bool rest_blockhash_by_height(const util::Ref& context, HTTPRequest* req,
624  const std::string& str_uri_part)
625 {
626  if (!CheckWarmup(req)) return false;
627  std::string height_str;
628  const RetFormat rf = ParseDataFormat(height_str, str_uri_part);
629 
630  int32_t blockheight = -1; // Initialization done only to prevent valgrind false positive, see https://github.com/bitcoin/bitcoin/pull/18785
631  if (!ParseInt32(height_str, &blockheight) || blockheight < 0) {
632  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid height: " + SanitizeString(height_str));
633  }
634 
635  CBlockIndex* pblockindex = nullptr;
636  {
637  LOCK(cs_main);
638  if (blockheight > ::ChainActive().Height()) {
639  return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range");
640  }
641  pblockindex = ::ChainActive()[blockheight];
642  }
643  switch (rf) {
644  case RetFormat::BINARY: {
646  ss_blockhash << pblockindex->GetBlockHash();
647  req->WriteHeader("Content-Type", "application/octet-stream");
648  req->WriteReply(HTTP_OK, ss_blockhash.str());
649  return true;
650  }
651  case RetFormat::HEX: {
652  req->WriteHeader("Content-Type", "text/plain");
653  req->WriteReply(HTTP_OK, pblockindex->GetBlockHash().GetHex() + "\n");
654  return true;
655  }
656  case RetFormat::JSON: {
657  req->WriteHeader("Content-Type", "application/json");
659  resp.pushKV("blockhash", pblockindex->GetBlockHash().GetHex());
660  req->WriteReply(HTTP_OK, resp.write() + "\n");
661  return true;
662  }
663  default: {
664  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
665  }
666  }
667 }
668 
669 static const struct {
670  const char* prefix;
671  bool (*handler)(const util::Ref& context, HTTPRequest* req, const std::string& strReq);
672 } uri_prefixes[] = {
673  {"/rest/tx/", rest_tx},
674  {"/rest/block/notxdetails/", rest_block_notxdetails},
675  {"/rest/block/", rest_block_extended},
676  {"/rest/chaininfo", rest_chaininfo},
677  {"/rest/mempool/info", rest_mempool_info},
678  {"/rest/mempool/contents", rest_mempool_contents},
679  {"/rest/headers/", rest_headers},
680  {"/rest/getutxos", rest_getutxos},
681  {"/rest/blockhashbyheight/", rest_blockhash_by_height},
682 };
683 
684 void StartREST(const util::Ref& context)
685 {
686  for (const auto& up : uri_prefixes) {
687  auto handler = [&context, up](HTTPRequest* req, const std::string& prefix) { return up.handler(context, req, prefix); };
688  RegisterHTTPHandler(up.prefix, false, handler);
689  }
690 }
691 
693 {
694 }
695 
696 void StopREST()
697 {
698  for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++)
700 }
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:395
uint32_t nHeight
Definition: rest.cpp:50
std::string SanitizeString(const std::string &str, int rule)
Remove unsafe chars.
bool(* handler)(const util::Ref &context, HTTPRequest *req, const std::string &strReq)
Definition: rest.cpp:671
static const struct @9 uri_prefixes[]
static bool rest_block_extended(const util::Ref &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:295
static bool CheckWarmup(HTTPRequest *req)
Definition: rest.cpp:145
static NodeContext * GetNodeContext(const util::Ref &context, HTTPRequest *req)
Get the node context.
Definition: rest.cpp:77
static RetFormat ParseDataFormat(std::string &param, const std::string &strReq)
Definition: rest.cpp:108
A UTXO entry.
Definition: coins.h:30
Definition: block.h:62
CChain & ChainActive()
Please prefer the identical ChainstateManager::ActiveChain.
Definition: validation.cpp:113
std::unique_ptr< CTxMemPool > mempool
Definition: context.h:38
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
static bool rest_block_notxdetails(const util::Ref &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:300
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos, const Consensus::Params &consensusParams)
Functions for disk access for blocks.
static std::string AvailableDataFormatsString()
Definition: rest.cpp:129
UniValue HandleRequest(const JSONRPCRequest &request)
Definition: util.h:340
std::string str() const
Definition: streams.h:280
const char * prefix
Definition: rest.cpp:670
#define ARRAYLEN(array)
Utilities for converting data from/to strings.
Definition: strencodings.h:20
std::vector< unsigned char > ParseHex(const char *psz)
int Height() const
Return the maximal height in the chain.
Definition: chain.h:415
UniValue ValueFromAmount(const CAmount &amount)
Definition: core_write.cpp:18
HTTPStatusCode
HTTP status codes.
Definition: protocol.h:10
UniValue blockheaderToJSON(const CBlockIndex *tip, const CBlockIndex *blockindex)
Block header to JSON.
Definition: blockchain.cpp:118
RetFormat
Definition: rest.cpp:32
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:202
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Definition: httpserver.cpp:641
SERIALIZE_METHODS(CCoin, obj)
Definition: rest.cpp:56
uint256 GetBlockHash() const
Definition: chain.h:233
static bool rest_block(HTTPRequest *req, const std::string &strURIPart, bool showTxDetails)
Definition: rest.cpp:231
#define LOCK2(cs1, cs2)
Definition: sync.h:231
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
static bool RESTERR(HTTPRequest *req, enum HTTPStatusCode status, std::string message)
Definition: rest.cpp:63
NodeContext struct containing references to chain state and connection state.
Definition: context.h:36
Abstract view on the open txout dataset.
Definition: coins.h:180
RetFormat rf
Definition: rest.cpp:40
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
Definition: httpserver.cpp:571
UniValue params
Definition: request.h:36
static bool rest_blockhash_by_height(const util::Ref &context, HTTPRequest *req, const std::string &str_uri_part)
Definition: rest.cpp:623
#define LOCK(cs)
Definition: sync.h:230
const char * name
Definition: rest.cpp:41
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
Definition: txindex.cpp:17
static bool rest_mempool_contents(const util::Ref &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:355
CBlockIndex * Next(const CBlockIndex *pindex) const
Find the successor of a block in this chain, or nullptr if the given index is not found or is the tip...
Definition: chain.h:407
bool IsHex(const std::string &str)
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: validation.cpp:129
bool ParseInt32(const std::string &str, int32_t *out)
Convert string to signed 32-bit integer with strict parse error feedback.
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
Definition: httpserver.cpp:647
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
bool Has() const
Definition: ref.h:28
static bool rest_mempool_info(const util::Ref &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:331
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
An output of a transaction.
Definition: transaction.h:128
static bool rest_getutxos(const util::Ref &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:437
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:26
static CTxMemPool * GetMemPool(const util::Ref &context, HTTPRequest *req)
Get the node context mempool.
Definition: rest.cpp:98
T & Get() const
Definition: ref.h:26
UniValue blockToJSON(const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, bool txDetails)
Block description to JSON.
Definition: blockchain.cpp:147
CCoin()
Definition: rest.cpp:53
CTxOut out
Definition: rest.cpp:51
Type-safe dynamic reference.
Definition: ref.h:21
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
static const size_t MAX_GETUTXOS_OUTPOINTS
Definition: rest.cpp:30
CBlockIndex * LookupBlockIndex(const uint256 &hash)
Definition: validation.cpp:173
256-bit opaque blob.
Definition: uint256.h:124
RPCHelpMan getblockchaininfo()
CChainState & ChainstateActive()
Please prefer the identical ChainstateManager::ActiveChainstate.
Definition: validation.cpp:106
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:488
static const struct @8 rf_names[]
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
Definition: httpserver.cpp:559
static bool rest_headers(const util::Ref &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:153
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
void StopREST()
Stop HTTP REST subsystem.
Definition: rest.cpp:696
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:137
const CChainParams & Params()
Return the currently selected parameters.
bool IsBlockPruned(const CBlockIndex *pblockindex)
Check whether the block associated with this index entry is pruned or not.
Definition: validation.h:979
int RPCSerializationFlags()
Definition: server.cpp:509
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:390
std::string GetHex() const
Definition: uint256.cpp:20
bool RPCIsInWarmup(std::string *outStatus)
Definition: server.cpp:338
Definition: rest.cpp:49
static int count
Definition: tests.c:35
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
Definition: core_write.cpp:154
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Definition: validation.h:590
std::string ReadBody()
Read request body.
Definition: httpserver.cpp:539
void TxToUniv(const CTransaction &tx, const uint256 &hashBlock, UniValue &entry, bool include_hex=true, int serialize_flags=0)
Definition: core_write.cpp:180
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
Definition: blockchain.cpp:503
In-flight HTTP request.
Definition: httpserver.h:56
bool ParseHashStr(const std::string &strHex, uint256 &result)
Parse a hex string into 256 bits.
Definition: core_read.cpp:191
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:65
void InterruptREST()
Interrupt RPC REST subsystem.
Definition: rest.cpp:692
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:236
CCoin(Coin &&in)
Definition: rest.cpp:54
#define READWRITE(...)
Definition: serialize.h:175
void SetHex(const char *psz)
Definition: uint256.cpp:30
static bool rest_chaininfo(const util::Ref &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:308
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:893
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const uint256 &hash, const Consensus::Params &consensusParams, uint256 &hashBlock)
Return transaction from the block at block_index.
static bool rest_tx(const util::Ref &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:378
#define PACKAGE_BUGREPORT
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it...
Definition: txmempool.h:576
void StartREST(const util::Ref &context)
Start HTTP REST subsystem.
Definition: rest.cpp:684