6 #if defined(HAVE_CONFIG_H)
67 uint32_t nTxVerDummy = 0;
68 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
88 auto node_context = util::AnyPtr<NodeContext>(context);
92 "Internal bug detected: Node context not found!\n"
93 "You may report this issue here: %s\n",
109 auto node_context = util::AnyPtr<NodeContext>(context);
110 if (!node_context || !node_context->mempool) {
114 return node_context->mempool.get();
126 auto node_context = util::AnyPtr<NodeContext>(context);
127 if (!node_context || !node_context->chainman) {
130 "Internal bug detected: Chainman disabled or instance not found!\n"
131 "You may report this issue here: %s\n",
135 return node_context->chainman.get();
142 param = strReq.substr(0, strReq.rfind(
'?'));
143 const std::string::size_type pos_format{param.rfind(
'.')};
146 if (pos_format == std::string::npos) {
151 const std::string suffix(param, pos_format + 1);
152 for (
const auto& rf_name :
rf_names) {
153 if (suffix == rf_name.name) {
154 param.erase(pos_format);
166 for (
const auto& rf_name :
rf_names) {
167 if (strlen(rf_name.name) > 0) {
169 formats.append(rf_name.name);
170 formats.append(
", ");
174 if (formats.length() > 0)
175 return formats.substr(0, formats.length() - 2);
182 std::string statusmessage;
190 const std::string& strURIPart)
196 std::vector<std::string> path =
SplitString(param,
'/');
198 std::string raw_count;
200 if (path.size() == 2) {
204 }
else if (path.size() == 1) {
209 }
catch (
const std::runtime_error& e) {
213 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
216 const auto parsed_count{ToIntegral<size_t>(raw_count)};
226 std::vector<const CBlockIndex*> headers;
227 headers.reserve(*parsed_count);
230 if (!maybe_chainman)
return false;
234 tip = active_chain.
Tip();
236 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
237 headers.push_back(pindex);
238 if (headers.size() == *parsed_count) {
241 pindex = active_chain.
Next(pindex);
249 ssHeader << pindex->GetBlockHeader();
252 std::string binaryHeader = ssHeader.
str();
253 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
261 ssHeader << pindex->GetBlockHeader();
264 std::string strHex =
HexStr(ssHeader) +
"\n";
274 std::string strJSON = jsonHeaders.
write() +
"\n";
275 req->
WriteHeader(
"Content-Type",
"application/json");
287 const std::string& strURIPart,
303 if (!maybe_chainman)
return false;
312 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
318 std::vector<uint8_t> block_data{};
325 const std::string binaryBlock{block_data.begin(), block_data.end()};
326 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
332 const std::string strHex{
HexStr(block_data) +
"\n"};
343 std::string strJSON = objBlock.
write() +
"\n";
344 req->
WriteHeader(
"Content-Type",
"application/json");
372 std::vector<std::string> uri_parts =
SplitString(param,
'/');
373 std::string raw_count;
374 std::string raw_blockhash;
375 if (uri_parts.size() == 3) {
377 raw_blockhash = uri_parts[2];
378 raw_count = uri_parts[1];
379 }
else if (uri_parts.size() == 2) {
381 raw_blockhash = uri_parts[1];
384 }
catch (
const std::runtime_error& e) {
388 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
391 const auto parsed_count{ToIntegral<size_t>(raw_count)};
411 std::vector<const CBlockIndex*> headers;
412 headers.reserve(*parsed_count);
415 if (!maybe_chainman)
return false;
420 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
421 headers.push_back(pindex);
422 if (headers.size() == *parsed_count)
424 pindex = active_chain.
Next(pindex);
428 bool index_ready = index->BlockUntilSyncedToCurrentChain();
430 std::vector<uint256> filter_headers;
431 filter_headers.reserve(*parsed_count);
435 std::string errmsg =
"Filter not found.";
438 errmsg +=
" Block filters are still in the process of being indexed.";
440 errmsg +=
" This error is unexpected and indicates index corruption.";
445 filter_headers.push_back(filter_header);
451 for (
const uint256& header : filter_headers) {
455 std::string binaryHeader = ssHeader.
str();
456 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
462 for (
const uint256& header : filter_headers) {
466 std::string strHex =
HexStr(ssHeader) +
"\n";
473 for (
const uint256& header : filter_headers) {
477 std::string strJSON = jsonHeaders.
write() +
"\n";
478 req->
WriteHeader(
"Content-Type",
"application/json");
496 std::vector<std::string> uri_parts =
SplitString(param,
'/');
497 if (uri_parts.size() != 2) {
498 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
517 bool block_was_connected;
520 if (!maybe_chainman)
return false;
530 bool index_ready = index->BlockUntilSyncedToCurrentChain();
534 std::string errmsg =
"Filter not found.";
536 if (!block_was_connected) {
537 errmsg +=
" Block was not connected to active chain.";
538 }
else if (!index_ready) {
539 errmsg +=
" Block filters are still in the process of being indexed.";
541 errmsg +=
" This error is unexpected and indicates index corruption.";
552 std::string binaryResp = ssResp.str();
553 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
561 std::string strHex =
HexStr(ssResp) +
"\n";
569 std::string strJSON =
ret.write() +
"\n";
570 req->
WriteHeader(
"Content-Type",
"application/json");
596 std::string strJSON = chainInfoObject.
write() +
"\n";
597 req->
WriteHeader(
"Content-Type",
"application/json");
614 std::string hash_str;
623 if (!hash_str.empty()) {
630 if (!chainman)
return false;
638 req->
WriteHeader(
"Content-Type",
"application/json");
656 if (param !=
"contents" && param !=
"info") {
661 if (!mempool)
return false;
665 std::string str_json;
666 if (param ==
"contents") {
667 std::string raw_verbose;
670 }
catch (
const std::runtime_error& e) {
673 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
674 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
676 std::string raw_mempool_sequence;
678 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
679 }
catch (
const std::runtime_error& e) {
682 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
683 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
685 const bool verbose{raw_verbose ==
"true"};
686 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
687 if (verbose && mempool_sequence) {
688 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
695 req->
WriteHeader(
"Content-Type",
"application/json");
717 g_txindex->BlockUntilSyncedToCurrentChain();
721 if (!
node)
return false;
733 std::string binaryTx = ssTx.
str();
734 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
743 std::string strHex =
HexStr(ssTx) +
"\n";
752 std::string strJSON = objTx.
write() +
"\n";
753 req->
WriteHeader(
"Content-Type",
"application/json");
771 std::vector<std::string> uriParts;
772 if (param.length() > 1)
774 std::string strUriParams = param.substr(1);
779 std::string strRequestMutable = req->
ReadBody();
780 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
783 bool fInputParsed =
false;
784 bool fCheckMemPool =
false;
785 std::vector<COutPoint> vOutPoints;
790 if (uriParts.size() > 0)
793 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
795 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
798 std::string strTxid = uriParts[i].substr(0, uriParts[i].find(
'-'));
799 std::string strOutput = uriParts[i].substr(uriParts[i].find(
'-')+1);
804 vOutPoints.emplace_back(
TxidFromString(strTxid), (uint32_t)nOutput);
807 if (vOutPoints.size() > 0)
816 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
817 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
824 if (strRequestMutable.size() > 0)
830 oss << strRequestMutable;
831 oss >> fCheckMemPool;
834 }
catch (
const std::ios_base::failure&) {
856 std::vector<unsigned char> bitmap;
857 std::vector<CCoin> outs;
858 std::string bitmapStringRepresentation;
859 std::vector<bool> hits;
860 bitmap.resize((vOutPoints.size() + 7) / 8);
862 if (!maybe_chainman)
return false;
868 for (
const COutPoint& vOutPoint : vOutPoints) {
870 bool hit = (!mempool || !mempool->isSpent(vOutPoint)) && view.GetCoin(vOutPoint, coin);
872 if (hit) outs.emplace_back(std::move(coin));
880 if (!mempool)
return false;
885 process_utxos(viewMempool, mempool);
891 for (
size_t i = 0; i < hits.size(); ++i) {
892 const bool hit = hits[i];
893 bitmapStringRepresentation.append(hit ?
"1" :
"0");
894 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
903 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
904 std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
906 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
913 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
914 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
926 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
927 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.
GetHex());
928 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
931 for (
const CCoin& coin : outs) {
933 utxo.
pushKV(
"height", (int32_t)coin.nHeight);
939 utxo.
pushKV(
"scriptPubKey", o);
942 objGetUTXOResponse.
pushKV(
"utxos", utxos);
945 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
946 req->
WriteHeader(
"Content-Type",
"application/json");
957 const std::string& str_uri_part)
960 std::string height_str;
963 int32_t blockheight = -1;
964 if (!
ParseInt32(height_str, &blockheight) || blockheight < 0) {
971 if (!maybe_chainman)
return false;
975 if (blockheight > active_chain.
Height()) {
978 pblockindex = active_chain[blockheight];
984 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
994 req->
WriteHeader(
"Content-Type",
"application/json");
1006 static const struct {
#define PACKAGE_BUGREPORT
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.
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok. Implies all parents are either at least VALID_SCRIPTS, or are ASSUMED_VALID.
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.
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
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())
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.
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)
std::string GetHex() const
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadRawBlockFromDisk(std::vector< uint8_t > &block, const FlatFilePos &pos) const
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
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)
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.
static constexpr TransactionSerParams TX_WITH_WITNESS
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_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
bool RPCIsInWarmup(std::string *outStatus)
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(...)
Txid TxidFromString(std::string_view str)
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.