72 uint32_t nTxVerDummy = 0;
73 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
94 auto node_context = util::AnyPtr<NodeContext>(context);
111 auto node_context = util::AnyPtr<NodeContext>(context);
112 if (!node_context || !node_context->mempool) {
116 return node_context->mempool.get();
128 auto node_context = util::AnyPtr<NodeContext>(context);
129 if (!node_context || !node_context->chainman) {
133 return node_context->chainman.get();
140 param = strReq.substr(0, strReq.rfind(
'?'));
141 const std::string::size_type pos_format{param.rfind(
'.')};
144 if (pos_format == std::string::npos) {
149 const std::string suffix(param, pos_format + 1);
150 for (
const auto& rf_name :
rf_names) {
151 if (suffix == rf_name.name) {
152 param.erase(pos_format);
164 for (
const auto& rf_name :
rf_names) {
165 if (strlen(rf_name.name) > 0) {
167 formats.append(rf_name.name);
168 formats.append(
", ");
172 if (formats.length() > 0)
173 return formats.substr(0, formats.length() - 2);
180 std::string statusmessage;
188 const std::string& uri_part)
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) {
211 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
214 const auto parsed_count{ToIntegral<size_t>(raw_count)};
225 std::vector<const CBlockIndex*>
headers;
226 headers.reserve(*parsed_count);
228 if (!maybe_chainman)
return false;
233 tip = active_chain.
Tip();
235 while (pindex !=
nullptr && active_chain.
Contains(*pindex)) {
237 if (
headers.size() == *parsed_count) {
240 pindex = active_chain.
Next(*pindex);
248 ssHeader << pindex->GetBlockHeader();
253 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
261 ssHeader << pindex->GetBlockHeader();
264 std::string strHex =
HexStr(ssHeader) +
"\n";
275 std::string strJSON = jsonHeaders.
write() +
"\n";
277 req->
WriteHeader(
"Content-Type",
"application/json");
297 coin.
out.Serialize(stream);
316 prevout.
pushKV(
"scriptPubKey", std::move(script_pub_key));
318 tx_prevouts.
push_back(std::move(prevout));
320 result.
push_back(std::move(tx_prevouts));
331 std::vector<std::string> path =
SplitString(param,
'/');
334 if (path.size() == 1) {
366 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
374 const std::string strHex{
HexStr(ssSpentResponse) +
"\n"};
384 std::string strJSON = result.
write() +
"\n";
386 req->
WriteHeader(
"Content-Type",
"application/json");
405 const std::string& uri_part,
406 std::optional<TxVerbosity> tx_verbosity,
407 std::optional<std::pair<size_t, size_t>> block_part = std::nullopt)
423 if (!maybe_chainman)
return false;
433 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
443 switch (block_data.error()) {
455 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
461 const std::string strHex{
HexStr(*block_data) +
"\n"};
473 std::string strJSON = objBlock.
write() +
"\n";
475 req->
WriteHeader(
"Content-Type",
"application/json");
501 if (
const auto opt_offset{ToIntegral<size_t>(req->
GetQueryParameter(
"offset").value_or(
""))}) {
502 if (
const auto opt_size{ToIntegral<size_t>(req->
GetQueryParameter(
"size").value_or(
""))}) {
505 {{*opt_offset, *opt_size}});
512 }
catch (
const std::runtime_error& e) {
524 std::vector<std::string> uri_parts =
SplitString(param,
'/');
525 std::string raw_count;
526 std::string raw_blockhash;
527 if (uri_parts.size() == 3) {
529 raw_blockhash = uri_parts[2];
530 raw_count = uri_parts[1];
531 }
else if (uri_parts.size() == 2) {
533 raw_blockhash = uri_parts[1];
536 }
catch (
const std::runtime_error& e) {
540 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
543 const auto parsed_count{ToIntegral<size_t>(raw_count)};
563 std::vector<const CBlockIndex*>
headers;
564 headers.reserve(*parsed_count);
567 if (!maybe_chainman)
return false;
572 while (pindex !=
nullptr && active_chain.
Contains(*pindex)) {
574 if (
headers.size() == *parsed_count)
576 pindex = active_chain.
Next(*pindex);
580 bool index_ready = index->BlockUntilSyncedToCurrentChain();
582 std::vector<uint256> filter_headers;
583 filter_headers.reserve(*parsed_count);
587 std::string errmsg =
"Filter not found.";
590 errmsg +=
" Block filters are still in the process of being indexed.";
592 errmsg +=
" This error is unexpected and indicates index corruption.";
597 filter_headers.push_back(filter_header);
603 for (
const uint256& header : filter_headers) {
609 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
615 for (
const uint256& header : filter_headers) {
619 std::string strHex =
HexStr(ssHeader) +
"\n";
627 for (
const uint256& header : filter_headers) {
631 std::string strJSON = jsonHeaders.
write() +
"\n";
633 req->
WriteHeader(
"Content-Type",
"application/json");
651 std::vector<std::string> uri_parts =
SplitString(param,
'/');
652 if (uri_parts.size() != 2) {
653 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
672 bool block_was_connected;
675 if (!maybe_chainman)
return false;
685 bool index_ready = index->BlockUntilSyncedToCurrentChain();
689 std::string errmsg =
"Filter not found.";
691 if (!block_was_connected) {
692 errmsg +=
" Block was not connected to active chain.";
693 }
else if (!index_ready) {
694 errmsg +=
" Block filters are still in the process of being indexed.";
696 errmsg +=
" This error is unexpected and indicates index corruption.";
708 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
716 std::string strHex =
HexStr(ssResp) +
"\n";
725 std::string strJSON =
ret.write() +
"\n";
727 req->
WriteHeader(
"Content-Type",
"application/json");
753 std::string strJSON = chainInfoObject.
write() +
"\n";
755 req->
WriteHeader(
"Content-Type",
"application/json");
772 std::string hash_str;
774 const bool current_tip{hash_str.empty()};
789 if (!chainman)
return false;
798 req->
WriteHeader(
"Content-Type",
"application/json");
816 if (param !=
"contents" && param !=
"info") {
821 if (!mempool)
return false;
825 std::string str_json;
826 if (param ==
"contents") {
827 std::string raw_verbose;
830 }
catch (
const std::runtime_error& e) {
833 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
834 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
836 std::string raw_mempool_sequence;
838 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
839 }
catch (
const std::runtime_error& e) {
842 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
843 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
845 const bool verbose{raw_verbose ==
"true"};
846 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
847 if (verbose && mempool_sequence) {
848 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
856 req->
WriteHeader(
"Content-Type",
"application/json");
879 g_txindex->BlockUntilSyncedToCurrentChain();
883 if (!
node)
return false;
895 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
904 std::string strHex =
HexStr(ssTx) +
"\n";
914 std::string strJSON = objTx.
write() +
"\n";
916 req->
WriteHeader(
"Content-Type",
"application/json");
934 std::vector<std::string> uriParts;
935 if (param.length() > 1)
937 std::string strUriParams = param.substr(1);
942 std::string strRequestMutable = req->
ReadBody();
943 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
946 bool fInputParsed =
false;
947 bool fCheckMemPool =
false;
948 std::vector<COutPoint> vOutPoints;
953 if (uriParts.size() > 0)
956 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
958 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
960 const auto txid_out{util::Split<std::string_view>(uriParts[i],
'-')};
961 if (txid_out.size() != 2) {
965 auto output{ToIntegral<uint32_t>(txid_out.at(1))};
967 if (!txid || !output) {
971 vOutPoints.emplace_back(*txid, *output);
974 if (vOutPoints.size() > 0)
983 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
984 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
991 if (strRequestMutable.size() > 0)
997 oss << strRequestMutable;
998 oss >> fCheckMemPool;
1001 }
catch (
const std::ios_base::failure&) {
1023 std::vector<unsigned char> bitmap;
1024 std::vector<CCoin> outs;
1025 std::string bitmapStringRepresentation;
1026 std::vector<bool> hits;
1027 bitmap.resize(
CeilDiv(vOutPoints.size(), 8u));
1029 if (!maybe_chainman)
return false;
1035 for (
const COutPoint& vOutPoint : vOutPoints) {
1036 auto coin = !mempool || !mempool->isSpent(vOutPoint) ? view.GetCoin(vOutPoint) : std::nullopt;
1037 hits.push_back(coin.has_value());
1038 if (coin) outs.emplace_back(std::move(*coin));
1044 if (fCheckMemPool) {
1046 if (!mempool)
return false;
1051 process_utxos(viewMempool, mempool);
1057 for (
size_t i = 0; i < hits.size(); ++i) {
1058 const bool hit = hits[i];
1059 bitmapStringRepresentation.append(hit ?
"1" :
"0");
1060 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
1069 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1072 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1079 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1080 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
1093 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
1094 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.
GetHex());
1095 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
1098 for (
const CCoin& coin : outs) {
1100 utxo.
pushKV(
"height", coin.nHeight);
1106 utxo.
pushKV(
"scriptPubKey", std::move(o));
1109 objGetUTXOResponse.
pushKV(
"utxos", std::move(utxos));
1112 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
1114 req->
WriteHeader(
"Content-Type",
"application/json");
1125 const std::string& str_uri_part)
1128 std::string height_str;
1131 const auto blockheight{ToIntegral<int32_t>(height_str)};
1132 if (!blockheight || *blockheight < 0) {
1139 if (!maybe_chainman)
return false;
1143 if (*blockheight > active_chain.
Height()) {
1146 pblockindex = active_chain[*blockheight];
1154 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1166 req->
WriteHeader(
"Content-Type",
"application/json");
1178static 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.
void WriteHeader(std::string &&hdr, std::string &&value)
std::optional< std::string > GetQueryParameter(std::string_view key) const
std::string ReadBody() const
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
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
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.