6 #if defined(HAVE_CONFIG_H) 66 uint32_t nTxVerDummy = 0;
67 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
87 auto node_context = util::AnyPtr<NodeContext>(context);
91 "Internal bug detected: Node context not found!\n" 92 "You may report this issue here: %s\n",
108 auto node_context = util::AnyPtr<NodeContext>(context);
109 if (!node_context || !node_context->mempool) {
113 return node_context->mempool.get();
125 auto node_context = util::AnyPtr<NodeContext>(context);
126 if (!node_context || !node_context->chainman) {
129 "Internal bug detected: Chainman disabled or instance not found!\n" 130 "You may report this issue here: %s\n",
134 return node_context->chainman.get();
141 param = strReq.substr(0, strReq.rfind(
'?'));
142 const std::string::size_type pos_format{param.rfind(
'.')};
145 if (pos_format == std::string::npos) {
150 const std::string suffix(param, pos_format + 1);
151 for (
const auto& rf_name :
rf_names) {
152 if (suffix == rf_name.name) {
153 param.erase(pos_format);
165 for (
const auto& rf_name :
rf_names) {
166 if (strlen(rf_name.name) > 0) {
168 formats.append(rf_name.name);
169 formats.append(
", ");
173 if (formats.length() > 0)
174 return formats.substr(0, formats.length() - 2);
181 std::string statusmessage;
189 const std::string& strURIPart)
195 std::vector<std::string> path =
SplitString(param,
'/');
197 std::string raw_count;
199 if (path.size() == 2) {
203 }
else if (path.size() == 1) {
208 }
catch (
const std::runtime_error& e) {
212 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
215 const auto parsed_count{ToIntegral<size_t>(raw_count)};
225 std::vector<const CBlockIndex*> headers;
226 headers.reserve(*parsed_count);
229 if (!maybe_chainman)
return false;
233 tip = active_chain.
Tip();
235 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
236 headers.push_back(pindex);
237 if (headers.size() == *parsed_count) {
240 pindex = active_chain.
Next(pindex);
248 ssHeader << pindex->GetBlockHeader();
251 std::string binaryHeader = ssHeader.
str();
252 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
260 ssHeader << pindex->GetBlockHeader();
263 std::string strHex =
HexStr(ssHeader) +
"\n";
273 std::string strJSON = jsonHeaders.
write() +
"\n";
274 req->
WriteHeader(
"Content-Type",
"application/json");
286 const std::string& strURIPart,
302 if (!maybe_chainman)
return false;
311 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
324 std::string binaryBlock = ssBlock.
str();
325 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
333 std::string strHex =
HexStr(ssBlock) +
"\n";
341 std::string strJSON = objBlock.
write() +
"\n";
342 req->
WriteHeader(
"Content-Type",
"application/json");
370 std::vector<std::string> uri_parts =
SplitString(param,
'/');
371 std::string raw_count;
372 std::string raw_blockhash;
373 if (uri_parts.size() == 3) {
375 raw_blockhash = uri_parts[2];
376 raw_count = uri_parts[1];
377 }
else if (uri_parts.size() == 2) {
379 raw_blockhash = uri_parts[1];
382 }
catch (
const std::runtime_error& e) {
386 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
389 const auto parsed_count{ToIntegral<size_t>(raw_count)};
409 std::vector<const CBlockIndex*> headers;
410 headers.reserve(*parsed_count);
413 if (!maybe_chainman)
return false;
418 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
419 headers.push_back(pindex);
420 if (headers.size() == *parsed_count)
422 pindex = active_chain.
Next(pindex);
426 bool index_ready = index->BlockUntilSyncedToCurrentChain();
428 std::vector<uint256> filter_headers;
429 filter_headers.reserve(*parsed_count);
433 std::string errmsg =
"Filter not found.";
436 errmsg +=
" Block filters are still in the process of being indexed.";
438 errmsg +=
" This error is unexpected and indicates index corruption.";
443 filter_headers.push_back(filter_header);
449 for (
const uint256& header : filter_headers) {
453 std::string binaryHeader = ssHeader.
str();
454 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
460 for (
const uint256& header : filter_headers) {
464 std::string strHex =
HexStr(ssHeader) +
"\n";
471 for (
const uint256& header : filter_headers) {
475 std::string strJSON = jsonHeaders.
write() +
"\n";
476 req->
WriteHeader(
"Content-Type",
"application/json");
494 std::vector<std::string> uri_parts =
SplitString(param,
'/');
495 if (uri_parts.size() != 2) {
496 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
515 bool block_was_connected;
518 if (!maybe_chainman)
return false;
528 bool index_ready = index->BlockUntilSyncedToCurrentChain();
532 std::string errmsg =
"Filter not found.";
534 if (!block_was_connected) {
535 errmsg +=
" Block was not connected to active chain.";
536 }
else if (!index_ready) {
537 errmsg +=
" Block filters are still in the process of being indexed.";
539 errmsg +=
" This error is unexpected and indicates index corruption.";
550 std::string binaryResp = ssResp.str();
551 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
559 std::string strHex =
HexStr(ssResp) +
"\n";
567 std::string strJSON =
ret.write() +
"\n";
568 req->
WriteHeader(
"Content-Type",
"application/json");
594 std::string strJSON = chainInfoObject.
write() +
"\n";
595 req->
WriteHeader(
"Content-Type",
"application/json");
612 std::string hash_str;
621 if (!hash_str.empty()) {
628 if (!chainman)
return false;
636 req->
WriteHeader(
"Content-Type",
"application/json");
654 if (param !=
"contents" && param !=
"info") {
659 if (!mempool)
return false;
663 std::string str_json;
664 if (param ==
"contents") {
665 std::string raw_verbose;
668 }
catch (
const std::runtime_error& e) {
671 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
672 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
674 std::string raw_mempool_sequence;
676 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
677 }
catch (
const std::runtime_error& e) {
680 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
681 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
683 const bool verbose{raw_verbose ==
"true"};
684 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
685 if (verbose && mempool_sequence) {
686 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
693 req->
WriteHeader(
"Content-Type",
"application/json");
715 g_txindex->BlockUntilSyncedToCurrentChain();
719 if (!
node)
return false;
731 std::string binaryTx = ssTx.
str();
732 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
741 std::string strHex =
HexStr(ssTx) +
"\n";
750 std::string strJSON = objTx.
write() +
"\n";
751 req->
WriteHeader(
"Content-Type",
"application/json");
769 std::vector<std::string> uriParts;
770 if (param.length() > 1)
772 std::string strUriParams = param.substr(1);
777 std::string strRequestMutable = req->
ReadBody();
778 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
781 bool fInputParsed =
false;
782 bool fCheckMemPool =
false;
783 std::vector<COutPoint> vOutPoints;
788 if (uriParts.size() > 0)
791 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
793 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
796 std::string strTxid = uriParts[i].substr(0, uriParts[i].find(
'-'));
797 std::string strOutput = uriParts[i].substr(uriParts[i].find(
'-')+1);
802 vOutPoints.emplace_back(
TxidFromString(strTxid), (uint32_t)nOutput);
805 if (vOutPoints.size() > 0)
814 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
815 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
822 if (strRequestMutable.size() > 0)
828 oss << strRequestMutable;
829 oss >> fCheckMemPool;
832 }
catch (
const std::ios_base::failure&) {
854 std::vector<unsigned char> bitmap;
855 std::vector<CCoin> outs;
856 std::string bitmapStringRepresentation;
857 std::vector<bool> hits;
858 bitmap.resize((vOutPoints.size() + 7) / 8);
860 if (!maybe_chainman)
return false;
866 for (
const COutPoint& vOutPoint : vOutPoints) {
868 bool hit = (!mempool || !mempool->isSpent(vOutPoint)) && view.GetCoin(vOutPoint, coin);
870 if (hit) outs.emplace_back(std::move(coin));
878 if (!mempool)
return false;
883 process_utxos(viewMempool, mempool);
889 for (
size_t i = 0; i < hits.size(); ++i) {
890 const bool hit = hits[i];
891 bitmapStringRepresentation.append(hit ?
"1" :
"0");
892 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
901 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
902 std::string ssGetUTXOResponseString = ssGetUTXOResponse.
str();
904 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
911 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
912 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
924 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
925 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.GetHex());
926 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
929 for (
const CCoin& coin : outs) {
931 utxo.
pushKV(
"height", (int32_t)coin.nHeight);
937 utxo.
pushKV(
"scriptPubKey", o);
940 objGetUTXOResponse.
pushKV(
"utxos", utxos);
943 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
944 req->
WriteHeader(
"Content-Type",
"application/json");
955 const std::string& str_uri_part)
958 std::string height_str;
961 int32_t blockheight = -1;
962 if (!
ParseInt32(height_str, &blockheight) || blockheight < 0) {
969 if (!maybe_chainman)
return false;
973 if (blockheight > active_chain.
Height()) {
976 pblockindex = active_chain[blockheight];
982 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
992 req->
WriteHeader(
"Content-Type",
"application/json");
1004 static const struct {
std::shared_ptr< const CTransaction > CTransactionRef
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
static ChainstateManager * GetChainman(const std::any &context, HTTPRequest *req)
Get the node context chainstatemanager.
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
void push_back(UniValue val)
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
static bool CheckWarmup(HTTPRequest *req)
The same as previous option with information about prevouts if available.
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
TxVerbosity
Verbose level for block's transaction.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
static bool rest_getutxos(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
An in-memory indexed chain of blocks.
static std::string AvailableDataFormatsString()
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
static bool rest_tx(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.
int Height() const
Return the maximal height in the chain.
bool IsHex(std::string_view str)
HTTPStatusCode
HTTP status codes.
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.
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
static const struct @10 uri_prefixes[]
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...
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
static bool rest_headers(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
std::vector< std::string > SplitString(std::string_view str, char sep)
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Txid TxidFromString(std::string_view str)
SERIALIZE_METHODS(CCoin, obj)
uint256 GetBlockHash() const
static bool rest_mempool(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.
NodeContext struct containing references to chain state and connection state.
static bool rest_block_extended(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool RESTERR(HTTPRequest *req, enum HTTPStatusCode status, std::string message)
static bool rest_block(const std::any &context, HTTPRequest *req, const std::string &strURIPart, TxVerbosity tx_verbosity)
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Scripts & signatures ok. Implies all parents are either at least VALID_SCRIPTS, or are ASSUMED_VALID...
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex)
Block header to JSON.
void ScriptToUniv(const CScript &script, UniValue &out, bool include_hex=true, bool include_address=false, const SigningProvider *provider=nullptr)
Abstract view on the open txout dataset.
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
Double ended buffer combining vector and stream-like interfaces.
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
Complete block filter struct as defined in BIP 157.
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
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...
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
An output of a transaction.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
An outpoint - a combination of a transaction hash and an index n into its vout.
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
static const struct @9 rf_names[]
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
bool ParseInt32(std::string_view str, int32_t *out)
Convert string to signed 32-bit integer with strict parse error feedback.
static bool rest_blockhash_by_height(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
static bool rest_block_notxdetails(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
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.
static CTxMemPool * GetMemPool(const std::any &context, HTTPRequest *req)
Get the node context mempool.
static const size_t MAX_GETUTXOS_OUTPOINTS
RPCHelpMan getblockchaininfo()
static bool rest_filter_header(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
Only TXID for each block's transaction.
RPCHelpMan getdeploymentinfo()
void StopREST()
Stop HTTP REST subsystem.
The block chain is a tree shaped structure starting with the genesis block at the root...
void pushKV(std::string key, UniValue val)
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
static NodeContext * GetNodeContext(const std::any &context, HTTPRequest *req)
Get the node context.
static bool rest_block_filter(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
std::string GetHex() const
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
UniValue ValueFromAmount(const CAmount amount)
bool RPCIsInWarmup(std::string *outStatus)
std::string ReadBody()
Read request body.
bool ParseHashStr(const std::string &strHex, uint256 &result)
Parse a hex string into 256 bits.
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
void InterruptREST()
Interrupt RPC REST subsystem.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
UniValue HandleRequest(const JSONRPCRequest &request) const
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
CCoinsView that brings transactions from a mempool into view.
static bool rest_deploymentinfo(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
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...
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity)
Block description to JSON.
#define PACKAGE_BUGREPORT
static constexpr unsigned int MAX_REST_HEADERS_RESULTS
static bool rest_chaininfo(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it...
static constexpr TransactionSerParams TX_WITH_WITNESS
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
void StartREST(const std::any &context)
Start HTTP REST subsystem.