73 uint32_t nTxVerDummy = 0;
74 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
95 auto node_context = util::AnyPtr<NodeContext>(context);
112 auto node_context = util::AnyPtr<NodeContext>(context);
113 if (!node_context || !node_context->mempool) {
117 return node_context->mempool.get();
129 auto node_context = util::AnyPtr<NodeContext>(context);
130 if (!node_context || !node_context->chainman) {
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& uri_part)
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)};
226 std::vector<const CBlockIndex*>
headers;
227 headers.reserve(*parsed_count);
229 if (!maybe_chainman)
return false;
234 tip = active_chain.
Tip();
236 while (pindex !=
nullptr && active_chain.
Contains(*pindex)) {
238 if (
headers.size() == *parsed_count) {
241 pindex = active_chain.
Next(*pindex);
249 ssHeader << pindex->GetBlockHeader();
254 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
262 ssHeader << pindex->GetBlockHeader();
265 std::string strHex =
HexStr(ssHeader) +
"\n";
276 std::string strJSON = jsonHeaders.
write() +
"\n";
278 req->
WriteHeader(
"Content-Type",
"application/json");
298 coin.
out.Serialize(stream);
317 prevout.
pushKV(
"scriptPubKey", std::move(script_pub_key));
319 tx_prevouts.
push_back(std::move(prevout));
321 result.
push_back(std::move(tx_prevouts));
332 std::vector<std::string> path =
SplitString(param,
'/');
335 if (path.size() == 1) {
367 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
375 const std::string strHex{
HexStr(ssSpentResponse) +
"\n"};
385 std::string strJSON = result.
write() +
"\n";
387 req->
WriteHeader(
"Content-Type",
"application/json");
406 const std::string& uri_part,
407 std::optional<TxVerbosity> tx_verbosity,
408 std::optional<std::pair<size_t, size_t>> block_part = std::nullopt)
424 if (!maybe_chainman)
return false;
434 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
444 switch (block_data.error()) {
456 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
462 const std::string strHex{
HexStr(*block_data) +
"\n"};
474 std::string strJSON = objBlock.
write() +
"\n";
476 req->
WriteHeader(
"Content-Type",
"application/json");
502 if (
const auto opt_offset{ToIntegral<size_t>(req->
GetQueryParameter(
"offset").value_or(
""))}) {
503 if (
const auto opt_size{ToIntegral<size_t>(req->
GetQueryParameter(
"size").value_or(
""))}) {
506 {{*opt_offset, *opt_size}});
513 }
catch (
const std::runtime_error& e) {
525 std::vector<std::string> uri_parts =
SplitString(param,
'/');
526 std::string raw_count;
527 std::string raw_blockhash;
528 if (uri_parts.size() == 3) {
530 raw_blockhash = uri_parts[2];
531 raw_count = uri_parts[1];
532 }
else if (uri_parts.size() == 2) {
534 raw_blockhash = uri_parts[1];
537 }
catch (
const std::runtime_error& e) {
541 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
544 const auto parsed_count{ToIntegral<size_t>(raw_count)};
564 std::vector<const CBlockIndex*>
headers;
565 headers.reserve(*parsed_count);
568 if (!maybe_chainman)
return false;
573 while (pindex !=
nullptr && active_chain.
Contains(*pindex)) {
575 if (
headers.size() == *parsed_count)
577 pindex = active_chain.
Next(*pindex);
581 bool index_ready = index->BlockUntilSyncedToCurrentChain();
583 std::vector<uint256> filter_headers;
584 filter_headers.reserve(*parsed_count);
588 std::string errmsg =
"Filter not found.";
591 errmsg +=
" Block filters are still in the process of being indexed.";
593 errmsg +=
" This error is unexpected and indicates index corruption.";
598 filter_headers.push_back(filter_header);
604 for (
const uint256& header : filter_headers) {
610 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
616 for (
const uint256& header : filter_headers) {
620 std::string strHex =
HexStr(ssHeader) +
"\n";
628 for (
const uint256& header : filter_headers) {
632 std::string strJSON = jsonHeaders.
write() +
"\n";
634 req->
WriteHeader(
"Content-Type",
"application/json");
652 std::vector<std::string> uri_parts =
SplitString(param,
'/');
653 if (uri_parts.size() != 2) {
654 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
673 bool block_was_connected;
676 if (!maybe_chainman)
return false;
686 bool index_ready = index->BlockUntilSyncedToCurrentChain();
690 std::string errmsg =
"Filter not found.";
692 if (!block_was_connected) {
693 errmsg +=
" Block was not connected to active chain.";
694 }
else if (!index_ready) {
695 errmsg +=
" Block filters are still in the process of being indexed.";
697 errmsg +=
" This error is unexpected and indicates index corruption.";
709 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
717 std::string strHex =
HexStr(ssResp) +
"\n";
726 std::string strJSON =
ret.write() +
"\n";
728 req->
WriteHeader(
"Content-Type",
"application/json");
754 std::string strJSON = chainInfoObject.
write() +
"\n";
756 req->
WriteHeader(
"Content-Type",
"application/json");
773 std::string hash_str;
775 const bool current_tip{hash_str.empty()};
790 if (!chainman)
return false;
799 req->
WriteHeader(
"Content-Type",
"application/json");
817 if (param !=
"contents" && param !=
"info") {
822 if (!mempool)
return false;
826 std::string str_json;
827 if (param ==
"contents") {
828 std::string raw_verbose;
831 }
catch (
const std::runtime_error& e) {
834 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
835 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
837 std::string raw_mempool_sequence;
839 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
840 }
catch (
const std::runtime_error& e) {
843 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
844 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
846 const bool verbose{raw_verbose ==
"true"};
847 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
848 if (verbose && mempool_sequence) {
849 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
857 req->
WriteHeader(
"Content-Type",
"application/json");
880 g_txindex->BlockUntilSyncedToCurrentChain();
884 if (!
node)
return false;
896 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
905 std::string strHex =
HexStr(ssTx) +
"\n";
915 std::string strJSON = objTx.
write() +
"\n";
917 req->
WriteHeader(
"Content-Type",
"application/json");
935 std::vector<std::string> uriParts;
936 if (param.length() > 1)
938 std::string strUriParams = param.substr(1);
943 std::string strRequestMutable = req->
ReadBody();
944 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
947 bool fInputParsed =
false;
948 bool fCheckMemPool =
false;
949 std::vector<COutPoint> vOutPoints;
954 if (uriParts.size() > 0)
957 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
959 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
961 const auto txid_out{util::Split<std::string_view>(uriParts[i],
'-')};
962 if (txid_out.size() != 2) {
966 auto output{ToIntegral<uint32_t>(txid_out.at(1))};
968 if (!txid || !output) {
972 vOutPoints.emplace_back(*txid, *output);
975 if (vOutPoints.size() > 0)
984 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
985 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
992 if (strRequestMutable.size() > 0)
998 oss << strRequestMutable;
999 oss >> fCheckMemPool;
1002 }
catch (
const std::ios_base::failure&) {
1024 std::vector<unsigned char> bitmap;
1025 std::vector<CCoin> outs;
1026 std::string bitmapStringRepresentation;
1027 std::vector<bool> hits;
1028 bitmap.resize(
CeilDiv(vOutPoints.size(), 8u));
1030 if (!maybe_chainman)
return false;
1036 for (
const COutPoint& vOutPoint : vOutPoints) {
1037 auto coin = !mempool || !mempool->isSpent(vOutPoint) ? view.GetCoin(vOutPoint) : std::nullopt;
1038 hits.push_back(coin.has_value());
1039 if (coin) outs.emplace_back(std::move(*coin));
1045 if (fCheckMemPool) {
1047 if (!mempool)
return false;
1052 process_utxos(viewMempool, mempool);
1058 for (
size_t i = 0; i < hits.size(); ++i) {
1059 const bool hit = hits[i];
1060 bitmapStringRepresentation.append(hit ?
"1" :
"0");
1061 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
1070 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1073 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1080 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1081 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
1094 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
1095 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.
GetHex());
1096 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
1099 for (
const CCoin& coin : outs) {
1101 utxo.
pushKV(
"height", coin.nHeight);
1107 utxo.
pushKV(
"scriptPubKey", std::move(o));
1110 objGetUTXOResponse.
pushKV(
"utxos", std::move(utxos));
1113 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
1115 req->
WriteHeader(
"Content-Type",
"application/json");
1126 const std::string& str_uri_part)
1129 std::string height_str;
1132 const auto blockheight{ToIntegral<int32_t>(height_str)};
1133 if (!blockheight || *blockheight < 0) {
1140 if (!maybe_chainman)
return false;
1144 if (*blockheight > active_chain.
Height()) {
1147 pblockindex = active_chain[*blockheight];
1155 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1167 req->
WriteHeader(
"Content-Type",
"application/json");
1179static const struct {
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity, const uint256 pow_limit)
Block description to JSON.
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex, const uint256 pow_limit)
Block header to JSON.
bool BlockFilterTypeByName(std::string_view 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.
@ BLOCK_HAVE_DATA
full block available in blk*.dat
#define STR_INTERNAL_BUG(msg)
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,...
bool IsValid(enum BlockStatus nUpTo) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
uint256 GetBlockHash() const
int nHeight
height of the entry in the chain. The genesis block has height 0
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
Undo information for a CBlock.
std::vector< CTxUndo > vtxundo
An in-memory indexed chain of blocks.
bool Contains(const CBlockIndex &index) const
Efficiently check whether a block is present in this chain.
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
CBlockIndex * Next(const CBlockIndex &index) 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.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Pure 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 ...
An output of a transaction.
Undo information for a CTransaction.
std::vector< Coin > vprevout
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Chainstate & ActiveChainstate() const
Alternatives to CurrentChainstate() used by older code to query latest chainstate information without...
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
const Consensus::Params & GetConsensus() const
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...
CTxOut out
unspent transaction output
Double ended buffer combining vector and stream-like interfaces.
UniValue HandleRequest(const JSONRPCRequest &request) const
Minimal stream for reading from an existing byte array by std::span.
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
std::optional< std::string > GetQueryParameter(std::string_view key) const
std::string ReadBody() const
void WriteHeader(std::string &&hdr, std::string &&value)
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadBlockUndo(CBlockUndo &blockundo, const CBlockIndex &index) const
ReadRawBlockResult ReadRawBlock(const FlatFilePos &pos, std::optional< std::pair< size_t, size_t > > block_part=std::nullopt) const
static std::optional< transaction_identifier > FromHex(std::string_view hex)
static std::optional< uint256 > FromHex(std::string_view str)
void ScriptToUniv(const CScript &script, UniValue &out, bool include_hex, bool include_address, const SigningProvider *provider)
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex, const CTxUndo *txundo, TxVerbosity verbosity, std::function< bool(const CTxOut &)> is_change_func)
UniValue ValueFromAmount(const CAmount amount)
@ SHOW_DETAILS_AND_PREVOUT
The same as previous option with information about prevouts if available.
@ SHOW_TXID
Only TXID for each block's transaction.
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
std::string HexStr(const std::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.
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const Txid &hash, const BlockManager &blockman, uint256 &hashBlock)
Return transaction with a given hash.
std::vector< std::string > SplitString(std::string_view str, char sep)
constexpr auto CeilDiv(const Dividend dividend, const Divisor divisor)
Integer ceiling division (for unsigned values).
constexpr TransactionSerParams TX_WITH_WITNESS
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr unsigned int MAX_REST_HEADERS_RESULTS
static bool rest_headers(const std::any &context, HTTPRequest *req, const std::string &uri_part)
static void SerializeBlockUndo(DataStream &stream, const CBlockUndo &block_undo)
Serialize spent outputs as a list of per-transaction CTxOut lists using binary format.
static bool rest_block_extended(const std::any &context, HTTPRequest *req, const std::string &uri_part)
static bool rest_blockhash_by_height(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
static bool rest_block_part(const std::any &context, HTTPRequest *req, const std::string &uri_part)
static constexpr const char * REST_CACHE_IMMUTABLE
Response bytes never change.
static bool rest_block_filter(const std::any &context, HTTPRequest *req, const std::string &uri_part)
static bool rest_block_notxdetails(const std::any &context, HTTPRequest *req, const std::string &uri_part)
void StartREST(const std::any &context)
Start HTTP REST subsystem.
static bool rest_filter_header(const std::any &context, HTTPRequest *req, const std::string &uri_part)
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
static bool rest_getutxos(const std::any &context, HTTPRequest *req, const std::string &uri_part)
static bool rest_tx(const std::any &context, HTTPRequest *req, const std::string &uri_part)
static bool rest_block(const std::any &context, HTTPRequest *req, const std::string &uri_part, std::optional< TxVerbosity > tx_verbosity, std::optional< std::pair< size_t, size_t > > block_part=std::nullopt)
This handler is used by multiple HTTP endpoints:
static const struct @10 uri_prefixes[]
void StopREST()
Stop HTTP REST subsystem.
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 constexpr const char * REST_CACHE_NO_STORE
Mutable, node-local, or error response; must not be cached.
static bool CheckWarmup(HTTPRequest *req)
static ChainstateManager * GetChainman(const std::any &context, HTTPRequest *req)
Get the node context chainstatemanager.
RPCMethod getblockchaininfo()
static void BlockUndoToJSON(const CBlockUndo &block_undo, UniValue &result)
Serialize spent outputs as a list of per-transaction CTxOut lists using JSON format.
static bool rest_chaininfo(const std::any &context, HTTPRequest *req, const std::string &uri_part)
RPCMethod getdeploymentinfo()
static bool rest_spent_txouts(const std::any &context, HTTPRequest *req, const std::string &uri_part)
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 const size_t MAX_GETUTXOS_OUTPOINTS
static std::string AvailableDataFormatsString()
static NodeContext * GetNodeContext(const std::any &context, HTTPRequest *req)
Get the node context.
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
void WriteCompactSize(SizeComputer &os, uint64_t nSize)
bool RPCIsInWarmup(std::string *outStatus)
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
@ SAFE_CHARS_URI
Chars allowed in URIs (RFC 3986)
SERIALIZE_METHODS(CCoin, obj)
uint256 powLimit
Proof of work parameters.
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.
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.