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