62 uint32_t nTxVerDummy = 0;
63 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
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",
104 auto node_context = util::AnyPtr<NodeContext>(
context);
105 if (!node_context || !node_context->mempool) {
109 return node_context->mempool.get();
121 auto node_context = util::AnyPtr<NodeContext>(
context);
122 if (!node_context || !node_context->chainman) {
125 "Internal bug detected: Chainman disabled or instance not found!\n"
126 "You may report this issue here: %s\n",
130 return node_context->chainman.get();
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;
185 const std::string& strURIPart)
191 std::vector<std::string> path =
SplitString(param,
'/');
193 std::string raw_count;
195 if (path.size() == 2) {
199 }
else if (path.size() == 1) {
204 }
catch (
const std::runtime_error& e) {
208 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
211 const auto parsed_count{ToIntegral<size_t>(raw_count)};
221 std::vector<const CBlockIndex*> headers;
222 headers.reserve(*parsed_count);
225 if (!maybe_chainman)
return false;
229 tip = active_chain.
Tip();
231 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
232 headers.push_back(pindex);
233 if (headers.size() == *parsed_count) {
236 pindex = active_chain.
Next(pindex);
244 ssHeader << pindex->GetBlockHeader();
247 std::string binaryHeader = ssHeader.
str();
248 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
256 ssHeader << pindex->GetBlockHeader();
259 std::string strHex =
HexStr(ssHeader) +
"\n";
269 std::string strJSON = jsonHeaders.
write() +
"\n";
270 req->
WriteHeader(
"Content-Type",
"application/json");
282 const std::string& strURIPart,
298 if (!maybe_chainman)
return false;
308 if (chainman.
m_blockman.IsBlockPruned(pblockindex))
321 std::string binaryBlock = ssBlock.
str();
322 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
330 std::string strHex =
HexStr(ssBlock) +
"\n";
338 std::string strJSON = objBlock.
write() +
"\n";
339 req->
WriteHeader(
"Content-Type",
"application/json");
367 std::vector<std::string> uri_parts =
SplitString(param,
'/');
368 std::string raw_count;
369 std::string raw_blockhash;
370 if (uri_parts.size() == 3) {
372 raw_blockhash = uri_parts[2];
373 raw_count = uri_parts[1];
374 }
else if (uri_parts.size() == 2) {
376 raw_blockhash = uri_parts[1];
379 }
catch (
const std::runtime_error& e) {
383 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
386 const auto parsed_count{ToIntegral<size_t>(raw_count)};
406 std::vector<const CBlockIndex*> headers;
407 headers.reserve(*parsed_count);
410 if (!maybe_chainman)
return false;
415 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
416 headers.push_back(pindex);
417 if (headers.size() == *parsed_count)
419 pindex = active_chain.
Next(pindex);
423 bool index_ready = index->BlockUntilSyncedToCurrentChain();
425 std::vector<uint256> filter_headers;
426 filter_headers.reserve(*parsed_count);
430 std::string errmsg =
"Filter not found.";
433 errmsg +=
" Block filters are still in the process of being indexed.";
435 errmsg +=
" This error is unexpected and indicates index corruption.";
440 filter_headers.push_back(filter_header);
446 for (
const uint256& header : filter_headers) {
450 std::string binaryHeader = ssHeader.
str();
451 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
457 for (
const uint256& header : filter_headers) {
461 std::string strHex =
HexStr(ssHeader) +
"\n";
468 for (
const uint256& header : filter_headers) {
472 std::string strJSON = jsonHeaders.
write() +
"\n";
473 req->
WriteHeader(
"Content-Type",
"application/json");
491 std::vector<std::string> uri_parts =
SplitString(param,
'/');
492 if (uri_parts.size() != 2) {
493 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
512 bool block_was_connected;
515 if (!maybe_chainman)
return false;
525 bool index_ready = index->BlockUntilSyncedToCurrentChain();
529 std::string errmsg =
"Filter not found.";
531 if (!block_was_connected) {
532 errmsg +=
" Block was not connected to active chain.";
533 }
else if (!index_ready) {
534 errmsg +=
" Block filters are still in the process of being indexed.";
536 errmsg +=
" This error is unexpected and indicates index corruption.";
547 std::string binaryResp = ssResp.str();
548 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
556 std::string strHex =
HexStr(ssResp) +
"\n";
564 std::string strJSON =
ret.write() +
"\n";
565 req->
WriteHeader(
"Content-Type",
"application/json");
591 std::string strJSON = chainInfoObject.
write() +
"\n";
592 req->
WriteHeader(
"Content-Type",
"application/json");
609 std::string hash_str;
618 if (!hash_str.empty()) {
625 if (!chainman)
return false;
633 req->
WriteHeader(
"Content-Type",
"application/json");
651 if (param !=
"contents" && param !=
"info") {
656 if (!mempool)
return false;
660 std::string str_json;
661 if (param ==
"contents") {
662 std::string raw_verbose;
665 }
catch (
const std::runtime_error& e) {
668 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
669 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
671 std::string raw_mempool_sequence;
673 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
674 }
catch (
const std::runtime_error& e) {
677 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
678 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
680 const bool verbose{raw_verbose ==
"true"};
681 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
682 if (verbose && mempool_sequence) {
683 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
690 req->
WriteHeader(
"Content-Type",
"application/json");
712 g_txindex->BlockUntilSyncedToCurrentChain();
716 if (!
node)
return false;
728 std::string binaryTx = ssTx.
str();
729 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
738 std::string strHex =
HexStr(ssTx) +
"\n";
747 std::string strJSON = objTx.
write() +
"\n";
748 req->
WriteHeader(
"Content-Type",
"application/json");
766 std::vector<std::string> uriParts;
767 if (param.length() > 1)
769 std::string strUriParams = param.substr(1);
774 std::string strRequestMutable = req->
ReadBody();
775 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
778 bool fInputParsed =
false;
779 bool fCheckMemPool =
false;
780 std::vector<COutPoint> vOutPoints;
785 if (uriParts.size() > 0)
788 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
790 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
794 std::string strTxid = uriParts[i].substr(0, uriParts[i].find(
'-'));
795 std::string strOutput = uriParts[i].substr(uriParts[i].find(
'-')+1);
801 vOutPoints.push_back(
COutPoint(txid, (uint32_t)nOutput));
804 if (vOutPoints.size() > 0)
813 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
814 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
821 if (strRequestMutable.size() > 0)
827 oss << strRequestMutable;
828 oss >> fCheckMemPool;
831 }
catch (
const std::ios_base::failure&) {
853 std::vector<unsigned char> bitmap;
854 std::vector<CCoin> outs;
855 std::string bitmapStringRepresentation;
856 std::vector<bool> hits;
857 bitmap.resize((vOutPoints.size() + 7) / 8);
859 if (!maybe_chainman)
return false;
865 for (
const COutPoint& vOutPoint : vOutPoints) {
867 bool hit = (!mempool || !mempool->isSpent(vOutPoint)) && view.GetCoin(vOutPoint, coin);
869 if (hit) outs.emplace_back(std::move(coin));
877 if (!mempool)
return false;
882 process_utxos(viewMempool, mempool);
885 process_utxos(chainman.ActiveChainstate().CoinsTip(),
nullptr);
888 for (
size_t i = 0; i < hits.size(); ++i) {
889 const bool hit = hits[i];
890 bitmapStringRepresentation.append(hit ?
"1" :
"0");
891 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
900 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
901 std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
903 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
910 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
911 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
923 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
924 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.
GetHex());
925 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
928 for (
const CCoin& coin : outs) {
930 utxo.
pushKV(
"height", (int32_t)coin.nHeight);
936 utxo.
pushKV(
"scriptPubKey", o);
939 objGetUTXOResponse.
pushKV(
"utxos", utxos);
942 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
943 req->
WriteHeader(
"Content-Type",
"application/json");
954 const std::string& str_uri_part)
957 std::string height_str;
960 int32_t blockheight = -1;
961 if (!
ParseInt32(height_str, &blockheight) || blockheight < 0) {
968 if (!maybe_chainman)
return false;
972 if (blockheight > active_chain.
Height()) {
975 pblockindex = active_chain[blockheight];
981 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
991 req->
WriteHeader(
"Content-Type",
"application/json");
1003 static const struct {
#define PACKAGE_BUGREPORT
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, TxVerbosity verbosity)
Block description to JSON.
UniValue blockheaderToJSON(const CBlockIndex *tip, const CBlockIndex *blockindex)
Block header 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.
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
Complete block filter struct as defined in BIP 157.
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
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,...
uint256 GetBlockHash() const
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.
An in-memory indexed chain of blocks.
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...
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
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.
An outpoint - a combination of a transaction hash and an index n into its vout.
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...
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
CBlockIndex * ActiveTip() 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 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)
void SetHex(const char *psz)
std::string GetHex() const
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ParseHashStr(const std::string &strHex, uint256 &result)
Parse a hex string into 256 bits.
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 ScriptToUniv(const CScript &script, UniValue &out, bool include_hex=true, bool include_address=false, const SigningProvider *provider=nullptr)
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, int serialize_flags=0, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
UniValue ValueFromAmount(const CAmount amount)
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
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.
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const uint256 &hash, uint256 &hashBlock, const BlockManager &blockman)
Return transaction with a given hash.
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr unsigned int MAX_REST_HEADERS_RESULTS
static bool rest_blockhash_by_height(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
static ChainstateManager * GetChainman(const std::any &context, HTTPRequest *req)
Get the node context chainstatemanager.
static bool rest_block_filter(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool rest_getutxos(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool rest_headers(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool rest_tx(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
void StartREST(const std::any &context)
Start HTTP REST subsystem.
static bool rest_block_notxdetails(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
static const struct @10 uri_prefixes[]
void StopREST()
Stop HTTP REST subsystem.
RPCHelpMan getdeploymentinfo()
RPCHelpMan getblockchaininfo()
static CTxMemPool * GetMemPool(const std::any &context, HTTPRequest *req)
Get the node context mempool.
static bool rest_chaininfo(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
void InterruptREST()
Interrupt RPC REST subsystem.
static bool rest_deploymentinfo(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
static bool RESTERR(HTTPRequest *req, enum HTTPStatusCode status, std::string message)
static bool rest_mempool(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
static const struct @9 rf_names[]
static bool CheckWarmup(HTTPRequest *req)
static bool rest_block_extended(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static NodeContext * GetNodeContext(const std::any &context, HTTPRequest *req)
Get the node context.
static bool rest_filter_header(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
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 bool rest_block(const std::any &context, HTTPRequest *req, const std::string &strURIPart, TxVerbosity tx_verbosity)
static const size_t MAX_GETUTXOS_OUTPOINTS
static std::string AvailableDataFormatsString()
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
HTTPStatusCode
HTTP status codes.
@ HTTP_SERVICE_UNAVAILABLE
@ HTTP_INTERNAL_SERVER_ERROR
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
bool RPCIsInWarmup(std::string *outStatus)
int RPCSerializationFlags()
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
std::vector< std::string > SplitString(std::string_view str, char sep)
SERIALIZE_METHODS(CCoin, obj)
NodeContext struct containing references to chain state and connection state.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
#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.
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
bool IsHex(std::string_view str)
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.
static const int PROTOCOL_VERSION
network protocol versioning