Bitcoin Core  22.99.0
P2P Digital Currency
rest.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2021 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 <blockfilter.h>
7 #include <chain.h>
8 #include <chainparams.h>
9 #include <core_io.h>
10 #include <httpserver.h>
11 #include <index/blockfilterindex.h>
12 #include <index/txindex.h>
13 #include <node/blockstorage.h>
14 #include <node/context.h>
15 #include <primitives/block.h>
16 #include <primitives/transaction.h>
17 #include <rpc/blockchain.h>
18 #include <rpc/protocol.h>
19 #include <rpc/server.h>
20 #include <rpc/server_util.h>
21 #include <streams.h>
22 #include <sync.h>
23 #include <txmempool.h>
24 #include <util/check.h>
25 #include <util/system.h>
26 #include <validation.h>
27 #include <version.h>
28 
29 #include <any>
30 
31 #include <boost/algorithm/string.hpp>
32 
33 #include <univalue.h>
34 
37 using node::NodeContext;
39 
40 static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
41 static constexpr unsigned int MAX_REST_HEADERS_RESULTS = 2000;
42 
43 enum class RetFormat {
44  UNDEF,
45  BINARY,
46  HEX,
47  JSON,
48 };
49 
50 static const struct {
52  const char* name;
53 } rf_names[] = {
54  {RetFormat::UNDEF, ""},
55  {RetFormat::BINARY, "bin"},
56  {RetFormat::HEX, "hex"},
57  {RetFormat::JSON, "json"},
58 };
59 
60 struct CCoin {
61  uint32_t nHeight;
63 
64  CCoin() : nHeight(0) {}
65  explicit CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}
66 
68  {
69  uint32_t nTxVerDummy = 0;
70  READWRITE(nTxVerDummy, obj.nHeight, obj.out);
71  }
72 };
73 
74 static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string message)
75 {
76  req->WriteHeader("Content-Type", "text/plain");
77  req->WriteReply(status, message + "\r\n");
78  return false;
79 }
80 
88 static NodeContext* GetNodeContext(const std::any& context, HTTPRequest* req)
89 {
90  auto node_context = util::AnyPtr<NodeContext>(context);
91  if (!node_context) {
93  strprintf("%s:%d (%s)\n"
94  "Internal bug detected: Node context not found!\n"
95  "You may report this issue here: %s\n",
96  __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT));
97  return nullptr;
98  }
99  return node_context;
100 }
101 
109 static CTxMemPool* GetMemPool(const std::any& context, HTTPRequest* req)
110 {
111  auto node_context = util::AnyPtr<NodeContext>(context);
112  if (!node_context || !node_context->mempool) {
113  RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found");
114  return nullptr;
115  }
116  return node_context->mempool.get();
117 }
118 
126 static ChainstateManager* GetChainman(const std::any& context, HTTPRequest* req)
127 {
128  auto node_context = util::AnyPtr<NodeContext>(context);
129  if (!node_context || !node_context->chainman) {
131  strprintf("%s:%d (%s)\n"
132  "Internal bug detected: Chainman disabled or instance not found!\n"
133  "You may report this issue here: %s\n",
134  __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT));
135  return nullptr;
136  }
137  return node_context->chainman.get();
138 }
139 
140 static RetFormat ParseDataFormat(std::string& param, const std::string& strReq)
141 {
142  const std::string::size_type pos = strReq.rfind('.');
143  if (pos == std::string::npos)
144  {
145  param = strReq;
146  return rf_names[0].rf;
147  }
148 
149  param = strReq.substr(0, pos);
150  const std::string suff(strReq, pos + 1);
151 
152  for (const auto& rf_name : rf_names) {
153  if (suff == rf_name.name)
154  return rf_name.rf;
155  }
156 
157  /* If no suffix is found, return original string. */
158  param = strReq;
159  return rf_names[0].rf;
160 }
161 
162 static std::string AvailableDataFormatsString()
163 {
164  std::string formats;
165  for (const auto& rf_name : rf_names) {
166  if (strlen(rf_name.name) > 0) {
167  formats.append(".");
168  formats.append(rf_name.name);
169  formats.append(", ");
170  }
171  }
172 
173  if (formats.length() > 0)
174  return formats.substr(0, formats.length() - 2);
175 
176  return formats;
177 }
178 
179 static bool CheckWarmup(HTTPRequest* req)
180 {
181  std::string statusmessage;
182  if (RPCIsInWarmup(&statusmessage))
183  return RESTERR(req, HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: " + statusmessage);
184  return true;
185 }
186 
187 static bool rest_headers(const std::any& context,
188  HTTPRequest* req,
189  const std::string& strURIPart)
190 {
191  if (!CheckWarmup(req))
192  return false;
193  std::string param;
194  const RetFormat rf = ParseDataFormat(param, strURIPart);
195  std::vector<std::string> path;
196  boost::split(path, param, boost::is_any_of("/"));
197 
198  if (path.size() != 2)
199  return RESTERR(req, HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
200 
201  const auto parsed_count{ToIntegral<size_t>(path[0])};
202  if (!parsed_count.has_value() || *parsed_count < 1 || *parsed_count > MAX_REST_HEADERS_RESULTS) {
203  return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Header count is invalid or out of acceptable range (1-%u): %s", MAX_REST_HEADERS_RESULTS, path[0]));
204  }
205 
206  std::string hashStr = path[1];
207  uint256 hash;
208  if (!ParseHashStr(hashStr, hash))
209  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
210 
211  const CBlockIndex* tip = nullptr;
212  std::vector<const CBlockIndex*> headers;
213  headers.reserve(*parsed_count);
214  {
215  ChainstateManager* maybe_chainman = GetChainman(context, req);
216  if (!maybe_chainman) return false;
217  ChainstateManager& chainman = *maybe_chainman;
218  LOCK(cs_main);
219  CChain& active_chain = chainman.ActiveChain();
220  tip = active_chain.Tip();
221  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
222  while (pindex != nullptr && active_chain.Contains(pindex)) {
223  headers.push_back(pindex);
224  if (headers.size() == *parsed_count) {
225  break;
226  }
227  pindex = active_chain.Next(pindex);
228  }
229  }
230 
231  switch (rf) {
232  case RetFormat::BINARY: {
234  for (const CBlockIndex *pindex : headers) {
235  ssHeader << pindex->GetBlockHeader();
236  }
237 
238  std::string binaryHeader = ssHeader.str();
239  req->WriteHeader("Content-Type", "application/octet-stream");
240  req->WriteReply(HTTP_OK, binaryHeader);
241  return true;
242  }
243 
244  case RetFormat::HEX: {
246  for (const CBlockIndex *pindex : headers) {
247  ssHeader << pindex->GetBlockHeader();
248  }
249 
250  std::string strHex = HexStr(ssHeader) + "\n";
251  req->WriteHeader("Content-Type", "text/plain");
252  req->WriteReply(HTTP_OK, strHex);
253  return true;
254  }
255  case RetFormat::JSON: {
256  UniValue jsonHeaders(UniValue::VARR);
257  for (const CBlockIndex *pindex : headers) {
258  jsonHeaders.push_back(blockheaderToJSON(tip, pindex));
259  }
260  std::string strJSON = jsonHeaders.write() + "\n";
261  req->WriteHeader("Content-Type", "application/json");
262  req->WriteReply(HTTP_OK, strJSON);
263  return true;
264  }
265  default: {
266  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
267  }
268  }
269 }
270 
271 static bool rest_block(const std::any& context,
272  HTTPRequest* req,
273  const std::string& strURIPart,
274  TxVerbosity tx_verbosity)
275 {
276  if (!CheckWarmup(req))
277  return false;
278  std::string hashStr;
279  const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
280 
281  uint256 hash;
282  if (!ParseHashStr(hashStr, hash))
283  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
284 
285  CBlock block;
286  CBlockIndex* pblockindex = nullptr;
287  CBlockIndex* tip = nullptr;
288  {
289  ChainstateManager* maybe_chainman = GetChainman(context, req);
290  if (!maybe_chainman) return false;
291  ChainstateManager& chainman = *maybe_chainman;
292  LOCK(cs_main);
293  tip = chainman.ActiveChain().Tip();
294  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
295  if (!pblockindex) {
296  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
297  }
298 
299  if (IsBlockPruned(pblockindex))
300  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
301 
302  if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
303  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
304  }
305 
306  switch (rf) {
307  case RetFormat::BINARY: {
309  ssBlock << block;
310  std::string binaryBlock = ssBlock.str();
311  req->WriteHeader("Content-Type", "application/octet-stream");
312  req->WriteReply(HTTP_OK, binaryBlock);
313  return true;
314  }
315 
316  case RetFormat::HEX: {
318  ssBlock << block;
319  std::string strHex = HexStr(ssBlock) + "\n";
320  req->WriteHeader("Content-Type", "text/plain");
321  req->WriteReply(HTTP_OK, strHex);
322  return true;
323  }
324 
325  case RetFormat::JSON: {
326  UniValue objBlock = blockToJSON(block, tip, pblockindex, tx_verbosity);
327  std::string strJSON = objBlock.write() + "\n";
328  req->WriteHeader("Content-Type", "application/json");
329  req->WriteReply(HTTP_OK, strJSON);
330  return true;
331  }
332 
333  default: {
334  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
335  }
336  }
337 }
338 
339 static bool rest_block_extended(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
340 {
341  return rest_block(context, req, strURIPart, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
342 }
343 
344 static bool rest_block_notxdetails(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
345 {
346  return rest_block(context, req, strURIPart, TxVerbosity::SHOW_TXID);
347 }
348 
349 static bool rest_filter_header(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
350 {
351  if (!CheckWarmup(req)) return false;
352 
353  std::string param;
354  const RetFormat rf = ParseDataFormat(param, strURIPart);
355 
356  std::vector<std::string> uri_parts;
357  boost::split(uri_parts, param, boost::is_any_of("/"));
358  if (uri_parts.size() != 3) {
359  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<count>/<blockhash>");
360  }
361 
362  uint256 block_hash;
363  if (!ParseHashStr(uri_parts[2], block_hash)) {
364  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + uri_parts[2]);
365  }
366 
367  BlockFilterType filtertype;
368  if (!BlockFilterTypeByName(uri_parts[0], filtertype)) {
369  return RESTERR(req, HTTP_BAD_REQUEST, "Unknown filtertype " + uri_parts[0]);
370  }
371 
372  BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
373  if (!index) {
374  return RESTERR(req, HTTP_BAD_REQUEST, "Index is not enabled for filtertype " + uri_parts[0]);
375  }
376 
377  const auto parsed_count{ToIntegral<size_t>(uri_parts[1])};
378  if (!parsed_count.has_value() || *parsed_count < 1 || *parsed_count > MAX_REST_HEADERS_RESULTS) {
379  return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Header count is invalid or out of acceptable range (1-%u): %s", MAX_REST_HEADERS_RESULTS, uri_parts[1]));
380  }
381 
382  std::vector<const CBlockIndex*> headers;
383  headers.reserve(*parsed_count);
384  {
385  ChainstateManager* maybe_chainman = GetChainman(context, req);
386  if (!maybe_chainman) return false;
387  ChainstateManager& chainman = *maybe_chainman;
388  LOCK(cs_main);
389  CChain& active_chain = chainman.ActiveChain();
390  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block_hash);
391  while (pindex != nullptr && active_chain.Contains(pindex)) {
392  headers.push_back(pindex);
393  if (headers.size() == *parsed_count)
394  break;
395  pindex = active_chain.Next(pindex);
396  }
397  }
398 
399  bool index_ready = index->BlockUntilSyncedToCurrentChain();
400 
401  std::vector<uint256> filter_headers;
402  filter_headers.reserve(*parsed_count);
403  for (const CBlockIndex* pindex : headers) {
404  uint256 filter_header;
405  if (!index->LookupFilterHeader(pindex, filter_header)) {
406  std::string errmsg = "Filter not found.";
407 
408  if (!index_ready) {
409  errmsg += " Block filters are still in the process of being indexed.";
410  } else {
411  errmsg += " This error is unexpected and indicates index corruption.";
412  }
413 
414  return RESTERR(req, HTTP_NOT_FOUND, errmsg);
415  }
416  filter_headers.push_back(filter_header);
417  }
418 
419  switch (rf) {
420  case RetFormat::BINARY: {
422  for (const uint256& header : filter_headers) {
423  ssHeader << header;
424  }
425 
426  std::string binaryHeader = ssHeader.str();
427  req->WriteHeader("Content-Type", "application/octet-stream");
428  req->WriteReply(HTTP_OK, binaryHeader);
429  return true;
430  }
431  case RetFormat::HEX: {
433  for (const uint256& header : filter_headers) {
434  ssHeader << header;
435  }
436 
437  std::string strHex = HexStr(ssHeader) + "\n";
438  req->WriteHeader("Content-Type", "text/plain");
439  req->WriteReply(HTTP_OK, strHex);
440  return true;
441  }
442  case RetFormat::JSON: {
443  UniValue jsonHeaders(UniValue::VARR);
444  for (const uint256& header : filter_headers) {
445  jsonHeaders.push_back(header.GetHex());
446  }
447 
448  std::string strJSON = jsonHeaders.write() + "\n";
449  req->WriteHeader("Content-Type", "application/json");
450  req->WriteReply(HTTP_OK, strJSON);
451  return true;
452  }
453  default: {
454  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
455  }
456  }
457 }
458 
459 static bool rest_block_filter(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
460 {
461  if (!CheckWarmup(req)) return false;
462 
463  std::string param;
464  const RetFormat rf = ParseDataFormat(param, strURIPart);
465 
466  // request is sent over URI scheme /rest/blockfilter/filtertype/blockhash
467  std::vector<std::string> uri_parts;
468  boost::split(uri_parts, param, boost::is_any_of("/"));
469  if (uri_parts.size() != 2) {
470  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
471  }
472 
473  uint256 block_hash;
474  if (!ParseHashStr(uri_parts[1], block_hash)) {
475  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + uri_parts[1]);
476  }
477 
478  BlockFilterType filtertype;
479  if (!BlockFilterTypeByName(uri_parts[0], filtertype)) {
480  return RESTERR(req, HTTP_BAD_REQUEST, "Unknown filtertype " + uri_parts[0]);
481  }
482 
483  BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
484  if (!index) {
485  return RESTERR(req, HTTP_BAD_REQUEST, "Index is not enabled for filtertype " + uri_parts[0]);
486  }
487 
488  const CBlockIndex* block_index;
489  bool block_was_connected;
490  {
491  ChainstateManager* maybe_chainman = GetChainman(context, req);
492  if (!maybe_chainman) return false;
493  ChainstateManager& chainman = *maybe_chainman;
494  LOCK(cs_main);
495  block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
496  if (!block_index) {
497  return RESTERR(req, HTTP_NOT_FOUND, uri_parts[1] + " not found");
498  }
499  block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
500  }
501 
502  bool index_ready = index->BlockUntilSyncedToCurrentChain();
503 
504  BlockFilter filter;
505  if (!index->LookupFilter(block_index, filter)) {
506  std::string errmsg = "Filter not found.";
507 
508  if (!block_was_connected) {
509  errmsg += " Block was not connected to active chain.";
510  } else if (!index_ready) {
511  errmsg += " Block filters are still in the process of being indexed.";
512  } else {
513  errmsg += " This error is unexpected and indicates index corruption.";
514  }
515 
516  return RESTERR(req, HTTP_NOT_FOUND, errmsg);
517  }
518 
519  switch (rf) {
520  case RetFormat::BINARY: {
522  ssResp << filter;
523 
524  std::string binaryResp = ssResp.str();
525  req->WriteHeader("Content-Type", "application/octet-stream");
526  req->WriteReply(HTTP_OK, binaryResp);
527  return true;
528  }
529  case RetFormat::HEX: {
531  ssResp << filter;
532 
533  std::string strHex = HexStr(ssResp) + "\n";
534  req->WriteHeader("Content-Type", "text/plain");
535  req->WriteReply(HTTP_OK, strHex);
536  return true;
537  }
538  case RetFormat::JSON: {
540  ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
541  std::string strJSON = ret.write() + "\n";
542  req->WriteHeader("Content-Type", "application/json");
543  req->WriteReply(HTTP_OK, strJSON);
544  return true;
545  }
546  default: {
547  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
548  }
549  }
550 }
551 
552 // A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
554 
555 static bool rest_chaininfo(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
556 {
557  if (!CheckWarmup(req))
558  return false;
559  std::string param;
560  const RetFormat rf = ParseDataFormat(param, strURIPart);
561 
562  switch (rf) {
563  case RetFormat::JSON: {
564  JSONRPCRequest jsonRequest;
565  jsonRequest.context = context;
566  jsonRequest.params = UniValue(UniValue::VARR);
567  UniValue chainInfoObject = getblockchaininfo().HandleRequest(jsonRequest);
568  std::string strJSON = chainInfoObject.write() + "\n";
569  req->WriteHeader("Content-Type", "application/json");
570  req->WriteReply(HTTP_OK, strJSON);
571  return true;
572  }
573  default: {
574  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
575  }
576  }
577 }
578 
579 static bool rest_mempool_info(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
580 {
581  if (!CheckWarmup(req))
582  return false;
583  const CTxMemPool* mempool = GetMemPool(context, req);
584  if (!mempool) return false;
585  std::string param;
586  const RetFormat rf = ParseDataFormat(param, strURIPart);
587 
588  switch (rf) {
589  case RetFormat::JSON: {
590  UniValue mempoolInfoObject = MempoolInfoToJSON(*mempool);
591 
592  std::string strJSON = mempoolInfoObject.write() + "\n";
593  req->WriteHeader("Content-Type", "application/json");
594  req->WriteReply(HTTP_OK, strJSON);
595  return true;
596  }
597  default: {
598  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
599  }
600  }
601 }
602 
603 static bool rest_mempool_contents(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
604 {
605  if (!CheckWarmup(req)) return false;
606  const CTxMemPool* mempool = GetMemPool(context, req);
607  if (!mempool) return false;
608  std::string param;
609  const RetFormat rf = ParseDataFormat(param, strURIPart);
610 
611  switch (rf) {
612  case RetFormat::JSON: {
613  UniValue mempoolObject = MempoolToJSON(*mempool, true);
614 
615  std::string strJSON = mempoolObject.write() + "\n";
616  req->WriteHeader("Content-Type", "application/json");
617  req->WriteReply(HTTP_OK, strJSON);
618  return true;
619  }
620  default: {
621  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
622  }
623  }
624 }
625 
626 static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
627 {
628  if (!CheckWarmup(req))
629  return false;
630  std::string hashStr;
631  const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
632 
633  uint256 hash;
634  if (!ParseHashStr(hashStr, hash))
635  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
636 
637  if (g_txindex) {
638  g_txindex->BlockUntilSyncedToCurrentChain();
639  }
640 
641  const NodeContext* const node = GetNodeContext(context, req);
642  if (!node) return false;
643  uint256 hashBlock = uint256();
644  const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, node->mempool.get(), hash, Params().GetConsensus(), hashBlock);
645  if (!tx) {
646  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
647  }
648 
649  switch (rf) {
650  case RetFormat::BINARY: {
652  ssTx << tx;
653 
654  std::string binaryTx = ssTx.str();
655  req->WriteHeader("Content-Type", "application/octet-stream");
656  req->WriteReply(HTTP_OK, binaryTx);
657  return true;
658  }
659 
660  case RetFormat::HEX: {
662  ssTx << tx;
663 
664  std::string strHex = HexStr(ssTx) + "\n";
665  req->WriteHeader("Content-Type", "text/plain");
666  req->WriteReply(HTTP_OK, strHex);
667  return true;
668  }
669 
670  case RetFormat::JSON: {
671  UniValue objTx(UniValue::VOBJ);
672  TxToUniv(*tx, hashBlock, objTx);
673  std::string strJSON = objTx.write() + "\n";
674  req->WriteHeader("Content-Type", "application/json");
675  req->WriteReply(HTTP_OK, strJSON);
676  return true;
677  }
678 
679  default: {
680  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
681  }
682  }
683 }
684 
685 static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
686 {
687  if (!CheckWarmup(req))
688  return false;
689  std::string param;
690  const RetFormat rf = ParseDataFormat(param, strURIPart);
691 
692  std::vector<std::string> uriParts;
693  if (param.length() > 1)
694  {
695  std::string strUriParams = param.substr(1);
696  boost::split(uriParts, strUriParams, boost::is_any_of("/"));
697  }
698 
699  // throw exception in case of an empty request
700  std::string strRequestMutable = req->ReadBody();
701  if (strRequestMutable.length() == 0 && uriParts.size() == 0)
702  return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
703 
704  bool fInputParsed = false;
705  bool fCheckMemPool = false;
706  std::vector<COutPoint> vOutPoints;
707 
708  // parse/deserialize input
709  // input-format = output-format, rest/getutxos/bin requires binary input, gives binary output, ...
710 
711  if (uriParts.size() > 0)
712  {
713  //inputs is sent over URI scheme (/rest/getutxos/checkmempool/txid1-n/txid2-n/...)
714  if (uriParts[0] == "checkmempool") fCheckMemPool = true;
715 
716  for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
717  {
718  uint256 txid;
719  int32_t nOutput;
720  std::string strTxid = uriParts[i].substr(0, uriParts[i].find('-'));
721  std::string strOutput = uriParts[i].substr(uriParts[i].find('-')+1);
722 
723  if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
724  return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
725 
726  txid.SetHex(strTxid);
727  vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));
728  }
729 
730  if (vOutPoints.size() > 0)
731  fInputParsed = true;
732  else
733  return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
734  }
735 
736  switch (rf) {
737  case RetFormat::HEX: {
738  // convert hex to bin, continue then with bin part
739  std::vector<unsigned char> strRequestV = ParseHex(strRequestMutable);
740  strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
741  [[fallthrough]];
742  }
743 
744  case RetFormat::BINARY: {
745  try {
746  //deserialize only if user sent a request
747  if (strRequestMutable.size() > 0)
748  {
749  if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
750  return RESTERR(req, HTTP_BAD_REQUEST, "Combination of URI scheme inputs and raw post data is not allowed");
751 
753  oss << strRequestMutable;
754  oss >> fCheckMemPool;
755  oss >> vOutPoints;
756  }
757  } catch (const std::ios_base::failure&) {
758  // abort in case of unreadable binary data
759  return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
760  }
761  break;
762  }
763 
764  case RetFormat::JSON: {
765  if (!fInputParsed)
766  return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
767  break;
768  }
769  default: {
770  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
771  }
772  }
773 
774  // limit max outpoints
775  if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
776  return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
777 
778  // check spentness and form a bitmap (as well as a JSON capable human-readable string representation)
779  std::vector<unsigned char> bitmap;
780  std::vector<CCoin> outs;
781  std::string bitmapStringRepresentation;
782  std::vector<bool> hits;
783  bitmap.resize((vOutPoints.size() + 7) / 8);
784  ChainstateManager* maybe_chainman = GetChainman(context, req);
785  if (!maybe_chainman) return false;
786  ChainstateManager& chainman = *maybe_chainman;
787  {
788  auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView& view, const CTxMemPool& mempool) {
789  for (const COutPoint& vOutPoint : vOutPoints) {
790  Coin coin;
791  bool hit = !mempool.isSpent(vOutPoint) && view.GetCoin(vOutPoint, coin);
792  hits.push_back(hit);
793  if (hit) outs.emplace_back(std::move(coin));
794  }
795  };
796 
797  if (fCheckMemPool) {
798  const CTxMemPool* mempool = GetMemPool(context, req);
799  if (!mempool) return false;
800  // use db+mempool as cache backend in case user likes to query mempool
801  LOCK2(cs_main, mempool->cs);
802  CCoinsViewCache& viewChain = chainman.ActiveChainstate().CoinsTip();
803  CCoinsViewMemPool viewMempool(&viewChain, *mempool);
804  process_utxos(viewMempool, *mempool);
805  } else {
806  LOCK(cs_main); // no need to lock mempool!
807  process_utxos(chainman.ActiveChainstate().CoinsTip(), CTxMemPool());
808  }
809 
810  for (size_t i = 0; i < hits.size(); ++i) {
811  const bool hit = hits[i];
812  bitmapStringRepresentation.append(hit ? "1" : "0"); // form a binary string representation (human-readable for json output)
813  bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
814  }
815  }
816 
817  switch (rf) {
818  case RetFormat::BINARY: {
819  // serialize data
820  // use exact same output as mentioned in Bip64
821  CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
822  ssGetUTXOResponse << chainman.ActiveChain().Height() << chainman.ActiveChain().Tip()->GetBlockHash() << bitmap << outs;
823  std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
824 
825  req->WriteHeader("Content-Type", "application/octet-stream");
826  req->WriteReply(HTTP_OK, ssGetUTXOResponseString);
827  return true;
828  }
829 
830  case RetFormat::HEX: {
831  CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
832  ssGetUTXOResponse << chainman.ActiveChain().Height() << chainman.ActiveChain().Tip()->GetBlockHash() << bitmap << outs;
833  std::string strHex = HexStr(ssGetUTXOResponse) + "\n";
834 
835  req->WriteHeader("Content-Type", "text/plain");
836  req->WriteReply(HTTP_OK, strHex);
837  return true;
838  }
839 
840  case RetFormat::JSON: {
841  UniValue objGetUTXOResponse(UniValue::VOBJ);
842 
843  // pack in some essentials
844  // use more or less the same output as mentioned in Bip64
845  objGetUTXOResponse.pushKV("chainHeight", chainman.ActiveChain().Height());
846  objGetUTXOResponse.pushKV("chaintipHash", chainman.ActiveChain().Tip()->GetBlockHash().GetHex());
847  objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation);
848 
849  UniValue utxos(UniValue::VARR);
850  for (const CCoin& coin : outs) {
851  UniValue utxo(UniValue::VOBJ);
852  utxo.pushKV("height", (int32_t)coin.nHeight);
853  utxo.pushKV("value", ValueFromAmount(coin.out.nValue));
854 
855  // include the script in a json output
857  ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true);
858  utxo.pushKV("scriptPubKey", o);
859  utxos.push_back(utxo);
860  }
861  objGetUTXOResponse.pushKV("utxos", utxos);
862 
863  // return json string
864  std::string strJSON = objGetUTXOResponse.write() + "\n";
865  req->WriteHeader("Content-Type", "application/json");
866  req->WriteReply(HTTP_OK, strJSON);
867  return true;
868  }
869  default: {
870  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
871  }
872  }
873 }
874 
875 static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req,
876  const std::string& str_uri_part)
877 {
878  if (!CheckWarmup(req)) return false;
879  std::string height_str;
880  const RetFormat rf = ParseDataFormat(height_str, str_uri_part);
881 
882  int32_t blockheight = -1; // Initialization done only to prevent valgrind false positive, see https://github.com/bitcoin/bitcoin/pull/18785
883  if (!ParseInt32(height_str, &blockheight) || blockheight < 0) {
884  return RESTERR(req, HTTP_BAD_REQUEST, "Invalid height: " + SanitizeString(height_str));
885  }
886 
887  CBlockIndex* pblockindex = nullptr;
888  {
889  ChainstateManager* maybe_chainman = GetChainman(context, req);
890  if (!maybe_chainman) return false;
891  ChainstateManager& chainman = *maybe_chainman;
892  LOCK(cs_main);
893  const CChain& active_chain = chainman.ActiveChain();
894  if (blockheight > active_chain.Height()) {
895  return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range");
896  }
897  pblockindex = active_chain[blockheight];
898  }
899  switch (rf) {
900  case RetFormat::BINARY: {
902  ss_blockhash << pblockindex->GetBlockHash();
903  req->WriteHeader("Content-Type", "application/octet-stream");
904  req->WriteReply(HTTP_OK, ss_blockhash.str());
905  return true;
906  }
907  case RetFormat::HEX: {
908  req->WriteHeader("Content-Type", "text/plain");
909  req->WriteReply(HTTP_OK, pblockindex->GetBlockHash().GetHex() + "\n");
910  return true;
911  }
912  case RetFormat::JSON: {
913  req->WriteHeader("Content-Type", "application/json");
915  resp.pushKV("blockhash", pblockindex->GetBlockHash().GetHex());
916  req->WriteReply(HTTP_OK, resp.write() + "\n");
917  return true;
918  }
919  default: {
920  return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
921  }
922  }
923 }
924 
925 static const struct {
926  const char* prefix;
927  bool (*handler)(const std::any& context, HTTPRequest* req, const std::string& strReq);
928 } uri_prefixes[] = {
929  {"/rest/tx/", rest_tx},
930  {"/rest/block/notxdetails/", rest_block_notxdetails},
931  {"/rest/block/", rest_block_extended},
932  {"/rest/blockfilter/", rest_block_filter},
933  {"/rest/blockfilterheaders/", rest_filter_header},
934  {"/rest/chaininfo", rest_chaininfo},
935  {"/rest/mempool/info", rest_mempool_info},
936  {"/rest/mempool/contents", rest_mempool_contents},
937  {"/rest/headers/", rest_headers},
938  {"/rest/getutxos", rest_getutxos},
939  {"/rest/blockhashbyheight/", rest_blockhash_by_height},
940 };
941 
942 void StartREST(const std::any& context)
943 {
944  for (const auto& up : uri_prefixes) {
945  auto handler = [context, up](HTTPRequest* req, const std::string& prefix) { return up.handler(context, req, prefix); };
946  RegisterHTTPHandler(up.prefix, false, handler);
947  }
948 }
949 
951 {
952 }
953 
954 void StopREST()
955 {
956  for (const auto& up : uri_prefixes) {
957  UnregisterHTTPHandler(up.prefix, false);
958  }
959 }
AvailableDataFormatsString
static std::string AvailableDataFormatsString()
Definition: rest.cpp:162
block.h
ParseHashStr
bool ParseHashStr(const std::string &strHex, uint256 &result)
Parse a hex string into 256 bits.
Definition: core_read.cpp:240
LOCK2
#define LOCK2(cs1, cs2)
Definition: sync.h:227
rest_chaininfo
static bool rest_chaininfo(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:555
ParseDataFormat
static RetFormat ParseDataFormat(std::string &param, const std::string &strReq)
Definition: rest.cpp:140
HTTP_SERVICE_UNAVAILABLE
@ HTTP_SERVICE_UNAVAILABLE
Definition: protocol.h:19
ParseHex
std::vector< unsigned char > ParseHex(const char *psz)
Definition: strencodings.cpp:84
UniValue::VOBJ
@ VOBJ
Definition: univalue.h:19
node::BlockManager::LookupBlockIndex
CBlockIndex * LookupBlockIndex(const uint256 &hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Definition: blockstorage.cpp:35
check.h
g_txindex
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
Definition: txindex.cpp:16
UnregisterHTTPHandler
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
Definition: httpserver.cpp:648
RetFormat
RetFormat
Definition: rest.cpp:43
PACKAGE_BUGREPORT
#define PACKAGE_BUGREPORT
Definition: bitcoin-config.h:351
JSONRPCRequest::context
std::any context
Definition: request.h:38
CCoin::CCoin
CCoin(Coin &&in)
Definition: rest.cpp:65
ScriptPubKeyToUniv
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool include_hex, bool include_address=true)
Definition: core_write.cpp:151
streams.h
RPCHelpMan
Definition: util.h:346
sync.h
handler
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
Definition: rest.cpp:927
blockfilterindex.h
transaction.h
BlockFilter::GetEncodedFilter
const std::vector< unsigned char > & GetEncodedFilter() const
Definition: blockfilter.h:134
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:429
StartREST
void StartREST(const std::any &context)
Start HTTP REST subsystem.
Definition: rest.cpp:942
IsHex
bool IsHex(const std::string &str)
Definition: strencodings.cpp:61
HTTP_BAD_REQUEST
@ HTTP_BAD_REQUEST
Definition: protocol.h:13
MempoolInfoToJSON
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
Definition: blockchain.cpp:1812
BlockFilterTypeByName
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
Definition: blockfilter.cpp:154
node::NodeContext
NodeContext struct containing references to chain state and connection state.
Definition: context.h:40
BlockFilterIndex
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
Definition: blockfilterindex.h:24
CheckWarmup
static bool CheckWarmup(HTTPRequest *req)
Definition: rest.cpp:179
protocol.h
server_util.h
RetFormat::UNDEF
@ UNDEF
chainparams.h
UniValue::write
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
Definition: univalue_write.cpp:28
ChainstateManager::ActiveChainstate
CChainState & ActiveChainstate() const
The most-work chain.
Definition: validation.cpp:5025
CTransactionRef
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:406
HTTPRequest::WriteHeader
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
Definition: httpserver.cpp:554
node::ReadBlockFromDisk
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos, const Consensus::Params &consensusParams)
Functions for disk access for blocks.
Definition: blockstorage.cpp:745
CChain::Tip
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:447
context.h
version.h
rest_getutxos
static bool rest_getutxos(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:685
core_io.h
UniValue::pushKV
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
ValueFromAmount
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:22
validation.h
node::IsBlockPruned
bool IsBlockPruned(const CBlockIndex *pblockindex)
Definition: blockstorage.cpp:430
UniValue
Definition: univalue.h:17
RetFormat::BINARY
@ BINARY
ChainstateManager::ActiveChain
CChain & ActiveChain() const
Definition: validation.h:926
RetFormat::JSON
@ JSON
txmempool.h
txindex.h
CCoinsView
Abstract view on the open txout dataset.
Definition: coins.h:157
prefix
const char * prefix
Definition: rest.cpp:926
rest_tx
static bool rest_tx(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:626
rest_block
static bool rest_block(const std::any &context, HTTPRequest *req, const std::string &strURIPart, TxVerbosity tx_verbosity)
Definition: rest.cpp:271
blockheaderToJSON
UniValue blockheaderToJSON(const CBlockIndex *tip, const CBlockIndex *blockindex)
Block header to JSON.
Definition: blockchain.cpp:140
CCoin::out
CTxOut out
Definition: rest.cpp:62
rest_mempool_contents
static bool rest_mempool_contents(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:603
CTxMemPool::cs
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:517
blockfilter.h
TxVerbosity::SHOW_TXID
@ SHOW_TXID
Only TXID for each block's transaction.
HTTPRequest
In-flight HTTP request.
Definition: httpserver.h:56
CTxOut
An output of a transaction.
Definition: transaction.h:148
Coin
A UTXO entry.
Definition: coins.h:30
RPCHelpMan::HandleRequest
UniValue HandleRequest(const JSONRPCRequest &request) const
Definition: util.cpp:564
BLOCK_VALID_SCRIPTS
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
Definition: chain.h:121
rest_headers
static bool rest_headers(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:187
HTTPRequest::ReadBody
std::string ReadBody()
Read request body.
Definition: httpserver.cpp:534
univalue.h
rest_block_notxdetails
static bool rest_block_notxdetails(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:344
base_blob::GetHex
std::string GetHex() const
Definition: uint256.cpp:20
GetMemPool
static CTxMemPool * GetMemPool(const std::any &context, HTTPRequest *req)
Get the node context mempool.
Definition: rest.cpp:109
context
WalletContext context
Definition: notifications.cpp:37
getblockchaininfo
RPCHelpMan getblockchaininfo()
Definition: blockchain.cpp:1526
TxVerbosity::SHOW_DETAILS_AND_PREVOUT
@ SHOW_DETAILS_AND_PREVOUT
The same as previous option with information about prevouts if available.
uint256
256-bit opaque blob.
Definition: uint256.h:126
READWRITE
#define READWRITE(...)
Definition: serialize.h:140
StopREST
void StopREST()
Stop HTTP REST subsystem.
Definition: rest.cpp:954
rest_block_extended
static bool rest_block_extended(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:339
chain.h
rest_blockhash_by_height
static bool rest_blockhash_by_height(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
Definition: rest.cpp:875
RESTERR
static bool RESTERR(HTTPRequest *req, enum HTTPStatusCode status, std::string message)
Definition: rest.cpp:74
rest_mempool_info
static bool rest_mempool_info(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:579
CBlockIndex::GetBlockHash
uint256 GetBlockHash() const
Definition: chain.h:264
CCoin::SERIALIZE_METHODS
SERIALIZE_METHODS(CCoin, obj)
Definition: rest.cpp:67
CChain::Height
int Height() const
Return the maximal height in the chain.
Definition: chain.h:476
rf
RetFormat rf
Definition: rest.cpp:51
JSONRPCRequest::params
UniValue params
Definition: request.h:33
ChainstateManager
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:792
name
const char * name
Definition: rest.cpp:52
system.h
CBlock
Definition: block.h:62
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
MempoolToJSON
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
Definition: blockchain.cpp:536
blockToJSON
UniValue blockToJSON(const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, TxVerbosity verbosity)
Block description to JSON.
Definition: blockchain.cpp:169
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:299
SanitizeString
std::string SanitizeString(const std::string &str, int rule)
Remove unsafe chars.
Definition: strencodings.cpp:27
CChain
An in-memory indexed chain of blocks.
Definition: chain.h:430
HTTP_OK
@ HTTP_OK
Definition: protocol.h:12
uri_prefixes
static const struct @10 uri_prefixes[]
CCoinsViewCache
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:213
CChainState::CoinsTip
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:562
GetBlockFilterIndex
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
Definition: blockfilterindex.cpp:454
LOCK
#define LOCK(cs)
Definition: sync.h:226
MAX_GETUTXOS_OUTPOINTS
static const size_t MAX_GETUTXOS_OUTPOINTS
Definition: rest.cpp:40
blockstorage.h
std
Definition: setup_common.h:33
rest_filter_header
static bool rest_filter_header(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:349
RPCSerializationFlags
int RPCSerializationFlags()
Definition: server.cpp:540
CCoin::nHeight
uint32_t nHeight
Definition: rest.cpp:61
RetFormat::HEX
@ HEX
HTTP_NOT_FOUND
@ HTTP_NOT_FOUND
Definition: protocol.h:16
CCoinsViewMemPool
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:892
UniValue::push_back
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
BlockFilterIndex::LookupFilter
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
Definition: blockfilterindex.cpp:377
Params
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:561
CChain::Contains
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:461
MAX_REST_HEADERS_RESULTS
static constexpr unsigned int MAX_REST_HEADERS_RESULTS
Definition: rest.cpp:41
node
Definition: init.h:22
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:184
BlockFilterType
BlockFilterType
Definition: blockfilter.h:88
GetNodeContext
static NodeContext * GetNodeContext(const std::any &context, HTTPRequest *req)
Get the node context.
Definition: rest.cpp:88
rest_block_filter
static bool rest_block_filter(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
Definition: rest.cpp:459
SER_NETWORK
@ SER_NETWORK
Definition: serialize.h:131
JSONRPCRequest
Definition: request.h:28
TxToUniv
void TxToUniv(const CTransaction &tx, const uint256 &hashBlock, UniValue &entry, bool include_hex=true, int serialize_flags=0, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
Definition: core_write.cpp:168
COutPoint
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:26
blockchain.h
httpserver.h
node::GetTransaction
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const uint256 &hash, const Consensus::Params &consensusParams, uint256 &hashBlock)
Return transaction with a given hash.
Definition: transaction.cpp:125
GetChainman
static ChainstateManager * GetChainman(const std::any &context, HTTPRequest *req)
Get the node context chainstatemanager.
Definition: rest.cpp:126
rf_names
static const struct @9 rf_names[]
RPCIsInWarmup
bool RPCIsInWarmup(std::string *outStatus)
Definition: server.cpp:344
CBlockIndex::IsValid
bool IsValid(enum BlockStatus nUpTo=BLOCK_VALID_TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition: chain.h:313
UniValue::VARR
@ VARR
Definition: univalue.h:19
server.h
cs_main
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: validation.cpp:138
CBlockIndex
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:151
CDataStream::str
std::string str() const
Definition: streams.h:223
HexStr
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: strencodings.cpp:511
RegisterHTTPHandler
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Definition: httpserver.cpp:642
HTTPRequest::WriteReply
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
Definition: httpserver.cpp:566
CCoin
Definition: rest.cpp:60
base_blob::SetHex
void SetHex(const char *psz)
Definition: uint256.cpp:30
BlockFilterIndex::LookupFilterHeader
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out)
Get a single filter header by block.
Definition: blockfilterindex.cpp:387
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:467
InterruptREST
void InterruptREST()
Interrupt RPC REST subsystem.
Definition: rest.cpp:950
CCoin::CCoin
CCoin()
Definition: rest.cpp:64
ChainstateManager::m_blockman
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:862
TxVerbosity
TxVerbosity
Verbose level for block's transaction.
Definition: core_io.h:26
PROTOCOL_VERSION
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12
HTTP_INTERNAL_SERVER_ERROR
@ HTTP_INTERNAL_SERVER_ERROR
Definition: protocol.h:18
BlockFilter
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:110