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