63 uint32_t nTxVerDummy = 0;
64 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
69 std::string message) {
83 auto node_context = util::AnyPtr<NodeContext>(context);
87 "Internal bug detected: Node context not found!\n"
88 "You may report this issue here: %s\n",
89 __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT));
103 auto node_context = util::AnyPtr<NodeContext>(context);
104 if (!node_context || !node_context->mempool) {
108 return node_context->mempool.get();
120 auto node_context = util::AnyPtr<NodeContext>(context);
121 if (!node_context || !node_context->chainman) {
124 "Internal bug detected: Chainman disabled or instance"
126 "You may report this issue here: %s\n",
127 __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT));
130 return node_context->chainman.get();
134 const std::string &strReq) {
137 param = strReq.substr(0, strReq.rfind(
'?'));
138 const std::string::size_type pos_format{param.rfind(
'.')};
141 if (pos_format == std::string::npos) {
146 const std::string suffix(param, pos_format + 1);
147 for (
const auto &rf_name :
rf_names) {
148 if (suffix == rf_name.name) {
149 param.erase(pos_format);
161 for (
const auto &rf_name :
rf_names) {
162 if (strlen(rf_name.name) > 0) {
164 formats.append(rf_name.name);
165 formats.append(
", ");
169 if (formats.length() > 0) {
170 return formats.substr(0, formats.length() - 2);
177 std::string statusmessage;
180 "Service temporarily unavailable: " + statusmessage);
194 std::vector<std::string> path =
SplitString(param,
'/');
196 std::string raw_count;
198 if (path.size() == 2) {
202 }
else if (path.size() == 1) {
207 }
catch (
const std::runtime_error &e) {
212 "Invalid URI format. Expected "
213 "/rest/headers/<hash>.<ext>?count=<count>");
216 const auto parsed_count{ToIntegral<size_t>(raw_count)};
217 if (!parsed_count.has_value() || *parsed_count < 1 ||
222 "Header count is invalid or out of acceptable range (1-%u): %s",
232 std::vector<const CBlockIndex *> headers;
233 headers.reserve(*parsed_count);
236 if (!maybe_chainman) {
242 tip = active_chain.
Tip();
244 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
245 headers.push_back(pindex);
246 if (headers.size() == *parsed_count) {
249 pindex = active_chain.
Next(pindex);
257 ssHeader << pindex->GetBlockHeader();
260 std::string binaryHeader = ssHeader.
str();
261 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
269 ssHeader << pindex->GetBlockHeader();
272 std::string strHex =
HexStr(ssHeader) +
"\n";
282 std::string strJSON = jsonHeaders.
write() +
"\n";
283 req->
WriteHeader(
"Content-Type",
"application/json");
289 "output format not found (available: " +
314 if (!maybe_chainman) {
325 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
327 hashStr +
" not available (pruned data)");
338 std::string binaryBlock = ssBlock.str();
339 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
347 std::string strHex =
HexStr(ssBlock) +
"\n";
355 *pblockindex, tx_verbosity);
356 std::string strJSON = objBlock.
write() +
"\n";
357 req->
WriteHeader(
"Content-Type",
"application/json");
364 "output format not found (available: " +
372 const std::string &strURIPart) {
373 return rest_block(config, context, req, strURIPart,
379 const std::string &strURIPart) {
385 const std::string &strURIPart) {
393 std::vector<std::string> uri_parts =
SplitString(param,
'/');
394 std::string raw_count;
395 std::string raw_blockhash;
396 if (uri_parts.size() == 3) {
399 raw_blockhash = uri_parts[2];
400 raw_count = uri_parts[1];
401 }
else if (uri_parts.size() == 2) {
404 raw_blockhash = uri_parts[1];
407 }
catch (
const std::runtime_error &e) {
412 "Invalid URI format. Expected "
413 "/rest/blockfilterheaders/<filtertype>/"
414 "<blockhash>.<ext>?count=<count>");
417 const auto parsed_count{ToIntegral<size_t>(raw_count)};
418 if (!parsed_count.has_value() || *parsed_count < 1 ||
423 "Header count is invalid or out of acceptable range (1-%u): %s",
435 "Unknown filtertype " + uri_parts[0]);
441 "Index is not enabled for filtertype " + uri_parts[0]);
444 std::vector<const CBlockIndex *> headers;
445 headers.reserve(*parsed_count);
448 if (!maybe_chainman) {
456 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
457 headers.push_back(pindex);
458 if (headers.size() == *parsed_count) {
461 pindex = active_chain.
Next(pindex);
465 bool index_ready = index->BlockUntilSyncedToCurrentChain();
467 std::vector<uint256> filter_headers;
468 filter_headers.reserve(*parsed_count);
472 std::string errmsg =
"Filter not found.";
476 " Block filters are still in the process of being indexed.";
479 " This error is unexpected and indicates index corruption.";
484 filter_headers.push_back(filter_header);
490 for (
const uint256 &header : filter_headers) {
494 std::string binaryHeader = ssHeader.
str();
495 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
501 for (
const uint256 &header : filter_headers) {
505 std::string strHex =
HexStr(ssHeader) +
"\n";
512 for (
const uint256 &header : filter_headers) {
516 std::string strJSON = jsonHeaders.
write() +
"\n";
517 req->
WriteHeader(
"Content-Type",
"application/json");
523 "output format not found (available: " +
539 std::vector<std::string> uri_parts =
SplitString(param,
'/');
540 if (uri_parts.size() != 2) {
542 "Invalid URI format. Expected "
543 "/rest/blockfilter/<filtertype>/<blockhash>");
554 "Unknown filtertype " + uri_parts[0]);
560 "Index is not enabled for filtertype " + uri_parts[0]);
564 bool block_was_connected;
567 if (!maybe_chainman) {
579 bool index_ready = index->BlockUntilSyncedToCurrentChain();
583 std::string errmsg =
"Filter not found.";
585 if (!block_was_connected) {
586 errmsg +=
" Block was not connected to active chain.";
587 }
else if (!index_ready) {
589 " Block filters are still in the process of being indexed.";
592 " This error is unexpected and indicates index corruption.";
603 std::string binaryResp = ssResp.str();
604 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
612 std::string strHex =
HexStr(ssResp) +
"\n";
620 std::string strJSON = ret.
write() +
"\n";
621 req->
WriteHeader(
"Content-Type",
"application/json");
627 "output format not found (available: " +
649 std::string strJSON = chainInfoObject.
write() +
"\n";
650 req->
WriteHeader(
"Content-Type",
"application/json");
656 "output format not found (available: json)");
679 std::string strJSON = mempoolInfoObject.
write() +
"\n";
680 req->
WriteHeader(
"Content-Type",
"application/json");
686 "output format not found (available: json)");
693 const std::string &strURIPart) {
711 std::string strJSON = mempoolObject.
write() +
"\n";
712 req->
WriteHeader(
"Content-Type",
"application/json");
718 "output format not found (available: json)");
724 const std::string &strURIPart) {
737 g_txindex->BlockUntilSyncedToCurrentChain();
747 hashBlock,
node->chainman->m_blockman);
757 std::string binaryTx = ssTx.
str();
758 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
767 std::string strHex =
HexStr(ssTx) +
"\n";
776 std::string strJSON = objTx.
write() +
"\n";
777 req->
WriteHeader(
"Content-Type",
"application/json");
784 "output format not found (available: " +
799 std::vector<std::string> uriParts;
800 if (param.length() > 1) {
801 std::string strUriParams = param.substr(1);
806 std::string strRequestMutable = req->
ReadBody();
807 if (strRequestMutable.length() == 0 && uriParts.size() == 0) {
811 bool fInputParsed =
false;
812 bool fCheckMemPool =
false;
813 std::vector<COutPoint> vOutPoints;
819 if (uriParts.size() > 0) {
822 if (uriParts[0] ==
"checkmempool") {
823 fCheckMemPool =
true;
826 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++) {
828 util::Split<std::string_view>(uriParts[i],
'-')};
829 if (txid_out.size() != 2) {
833 auto output{ToIntegral<uint32_t>(txid_out.at(1))};
835 if (!txid || !output) {
839 vOutPoints.push_back(COutPoint(*txid, *output));
842 if (vOutPoints.size() > 0) {
852 std::vector<uint8_t> strRequestV =
ParseHex(strRequestMutable);
853 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
859 if (strRequestMutable.size() > 0) {
863 "Combination of URI scheme inputs and "
864 "raw post data is not allowed");
868 oss << strRequestMutable;
869 oss >> fCheckMemPool;
872 }
catch (
const std::ios_base::failure &) {
887 "output format not found (available: " +
896 strprintf(
"Error: max outpoints exceeded (max: %d, tried: %d)",
902 std::vector<uint8_t> bitmap;
903 std::vector<CCoin> outs;
904 std::string bitmapStringRepresentation;
905 std::vector<bool> hits;
906 bitmap.resize((vOutPoints.size() + 7) / 8);
908 if (!maybe_chainman) {
916 [&vOutPoints, &outs, &hits, &active_height, &active_hash,
919 for (
const COutPoint &vOutPoint : vOutPoints) {
920 auto coin = !mempool || !mempool->isSpent(vOutPoint)
921 ? view.GetCoin(vOutPoint)
923 hits.push_back(coin.has_value());
925 outs.emplace_back(std::move(*coin));
943 process_utxos(viewMempool, mempool);
950 for (
size_t i = 0; i < hits.size(); ++i) {
951 const bool hit = hits[i];
954 bitmapStringRepresentation.append(hit ?
"1" :
"0");
955 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
964 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
965 std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
967 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
974 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
975 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
987 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
988 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.
GetHex());
989 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
992 for (
const CCoin &coin : outs) {
994 utxo.
pushKV(
"height", int32_t(coin.nHeight));
995 utxo.
pushKV(
"value", coin.out.nValue);
1000 utxo.
pushKV(
"scriptPubKey", std::move(o));
1003 objGetUTXOResponse.
pushKV(
"utxos", std::move(utxos));
1006 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
1007 req->
WriteHeader(
"Content-Type",
"application/json");
1013 "output format not found (available: " +
1021 const std::string &str_uri_part) {
1025 std::string height_str;
1028 int32_t blockheight;
1029 if (!
ParseInt32(height_str, &blockheight) || blockheight < 0) {
1037 if (!maybe_chainman) {
1043 if (blockheight > active_chain.
Height()) {
1046 pblockindex = active_chain[blockheight];
1052 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1063 req->
WriteHeader(
"Content-Type",
"application/json");
1071 "output format not found (available: " +
1077static const struct {
1080 const std::string &strReq);
1098 const std::string &
prefix) {
1099 return up.handler(config, context, req,
prefix);
RPCHelpMan getblockchaininfo()
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex)
Block header to JSON.
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity)
Block description to JSON.
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
@ SCRIPTS
Scripts & signatures ok.
Complete block filter struct as defined in BIP 157.
const std::vector< uint8_t > & GetEncodedFilter() const
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
The block chain is a tree shaped structure starting with the genesis block at the root,...
bool IsValid(enum BlockValidity nUpTo=BlockValidity::TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
BlockHash GetBlockHash() const
An in-memory indexed chain of blocks.
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
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...
int Height() const
Return the maximal height in the chain.
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Abstract view on the open txout dataset.
CCoinsView that brings transactions from a mempool into view.
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
An output of a transaction.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Double ended buffer combining vector and stream-like interfaces.
std::optional< std::string > GetQueryParameter(const std::string &key) const
Get the query parameter value from request uri for a specified key, or std::nullopt if the key is not...
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
std::string ReadBody()
Read request body.
UniValue HandleRequest(const Config &config, const JSONRPCRequest &request) const
void push_back(UniValue val)
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
void pushKV(std::string key, UniValue val)
std::string GetHex() const
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadBlock(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
TxVerbosity
Verbose level for block's transaction.
@ SHOW_DETAILS_AND_PREVOUT
The same as previous option with information about prevouts if available.
@ SHOW_TXID
Only TXID for each block's transaction.
void TxToUniv(const CTransaction &tx, const BlockHash &hashBlock, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS, std::function< bool(const CTxOut &)> is_change_func={})
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const TxId &txid, BlockHash &hashBlock, const BlockManager &blockman)
Return transaction with a given txid.
Implement std::hash so RCUPtr can be used as a key for maps or sets.
std::vector< std::string > SplitString(std::string_view str, char sep)
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr unsigned int MAX_REST_HEADERS_RESULTS
static bool rest_filter_header(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool rest_block_filter(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool rest_blockhash_by_height(Config &config, const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
void StartREST(const std::any &context)
Start HTTP REST subsystem.
bool(* handler)(Config &config, const std::any &context, HTTPRequest *req, const std::string &strReq)
static bool rest_block(const Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart, TxVerbosity tx_verbosity)
void StopREST()
Stop HTTP REST subsystem.
static bool rest_mempool_info(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static const struct @12 rf_names[]
static bool rest_headers(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool rest_block_extended(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool rest_mempool_contents(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
void InterruptREST()
Interrupt RPC REST subsystem.
static bool RESTERR(HTTPRequest *req, enum HTTPStatusCode status, std::string message)
static bool CheckWarmup(HTTPRequest *req)
static bool rest_block_notxdetails(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static ChainstateManager * GetChainman(const std::any &context, HTTPRequest *req)
Get the node context chainstatemanager.
static bool rest_chaininfo(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool rest_tx(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static const struct @13 uri_prefixes[]
RESTResponseFormat ParseDataFormat(std::string ¶m, const std::string &strReq)
Parse a URI to get the data format and URI without data format and query string.
static CTxMemPool * GetMemPool(const std::any &context, HTTPRequest *req)
Get the node context mempool.
static bool rest_getutxos(Config &config, const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static const size_t MAX_GETUTXOS_OUTPOINTS
static std::string AvailableDataFormatsString()
static NodeContext * GetNodeContext(const std::any &context, HTTPRequest *req)
Get the node context.
HTTPStatusCode
HTTP status codes.
@ HTTP_SERVICE_UNAVAILABLE
@ HTTP_INTERNAL_SERVER_ERROR
bool RPCIsInWarmup(std::string *outStatus)
Returns the current warmup state.
A BlockHash is a unqiue identifier for a block.
static std::optional< BlockHash > FromHex(std::string_view str)
SERIALIZE_METHODS(CCoin, obj)
static std::optional< TxId > FromHex(std::string_view str)
NodeContext struct containing references to chain state and connection state.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
bool ParseInt32(std::string_view str, int32_t *out)
Convert string to signed 32-bit integer with strict parse error feedback.
template std::vector< std::byte > ParseHex(std::string_view)
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.