88 uint32_t nTxVerDummy = 0;
89 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
110 auto node_context = util::AnyPtr<NodeContext>(context);
127 auto node_context = util::AnyPtr<NodeContext>(context);
128 if (!node_context || !node_context->mempool) {
132 return node_context->mempool.get();
144 auto node_context = util::AnyPtr<NodeContext>(context);
145 if (!node_context || !node_context->chainman) {
149 return node_context->chainman.get();
156 param = strReq.substr(0, strReq.rfind(
'?'));
157 const std::string::size_type pos_format{param.rfind(
'.')};
160 if (pos_format == std::string::npos) {
165 const std::string suffix(param, pos_format + 1);
166 for (
const auto& rf_name :
rf_names) {
167 if (suffix == rf_name.name) {
168 param.erase(pos_format);
180 for (
const auto& rf_name :
rf_names) {
181 if (strlen(rf_name.name) > 0) {
183 formats.append(rf_name.name);
184 formats.append(
", ");
188 if (formats.length() > 0)
189 return formats.substr(0, formats.length() - 2);
196 std::string statusmessage;
204 const std::string& uri_part)
210 std::vector<std::string> path =
SplitString(param,
'/');
212 std::string raw_count;
214 if (path.size() == 2) {
218 }
else if (path.size() == 1) {
223 }
catch (
const std::runtime_error& e) {
227 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
230 const auto parsed_count{ToIntegral<size_t>(raw_count)};
241 std::vector<const CBlockIndex*>
headers;
242 headers.reserve(*parsed_count);
244 if (!maybe_chainman)
return false;
249 tip = active_chain.
Tip();
251 while (pindex !=
nullptr && active_chain.
Contains(*pindex)) {
253 if (
headers.size() == *parsed_count) {
256 pindex = active_chain.
Next(*pindex);
264 ssHeader << pindex->GetBlockHeader();
269 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
277 ssHeader << pindex->GetBlockHeader();
280 std::string strHex =
HexStr(ssHeader) +
"\n";
291 std::string strJSON = jsonHeaders.
write() +
"\n";
293 req->
WriteHeader(
"Content-Type",
"application/json");
313 coin.
out.Serialize(stream);
334 prevout.
pushKV(
"scriptPubKey", std::move(script_pub_key));
336 tx_prevouts.
push_back(std::move(prevout));
338 result.
push_back(std::move(tx_prevouts));
349 std::vector<std::string> path =
SplitString(param,
'/');
352 if (path.size() == 1) {
384 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
392 const std::string strHex{
HexStr(ssSpentResponse) +
"\n"};
402 std::string strJSON = result.
write() +
"\n";
404 req->
WriteHeader(
"Content-Type",
"application/json");
423 const std::string& uri_part,
424 std::optional<TxVerbosity> tx_verbosity,
425 std::optional<std::pair<size_t, size_t>> block_part = std::nullopt)
441 if (!maybe_chainman)
return false;
451 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
461 switch (block_data.error()) {
473 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
479 const std::string strHex{
HexStr(*block_data) +
"\n"};
491 std::string strJSON = objBlock.
write() +
"\n";
493 req->
WriteHeader(
"Content-Type",
"application/json");
519 if (
const auto opt_offset{ToIntegral<size_t>(req->
GetQueryParameter(
"offset").value_or(
""))}) {
520 if (
const auto opt_size{ToIntegral<size_t>(req->
GetQueryParameter(
"size").value_or(
""))}) {
523 {{*opt_offset, *opt_size}});
530 }
catch (
const std::runtime_error& e) {
542 std::vector<std::string> uri_parts =
SplitString(param,
'/');
543 std::string raw_count;
544 std::string raw_blockhash;
545 if (uri_parts.size() == 3) {
547 raw_blockhash = uri_parts[2];
548 raw_count = uri_parts[1];
549 }
else if (uri_parts.size() == 2) {
551 raw_blockhash = uri_parts[1];
554 }
catch (
const std::runtime_error& e) {
558 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
561 const auto parsed_count{ToIntegral<size_t>(raw_count)};
581 std::vector<const CBlockIndex*>
headers;
582 headers.reserve(*parsed_count);
585 if (!maybe_chainman)
return false;
590 while (pindex !=
nullptr && active_chain.
Contains(*pindex)) {
592 if (
headers.size() == *parsed_count)
594 pindex = active_chain.
Next(*pindex);
598 bool index_ready = index->BlockUntilSyncedToCurrentChain();
600 std::vector<uint256> filter_headers;
601 filter_headers.reserve(*parsed_count);
605 std::string errmsg =
"Filter not found.";
608 errmsg +=
" Block filters are still in the process of being indexed.";
610 errmsg +=
" This error is unexpected and indicates index corruption.";
615 filter_headers.push_back(filter_header);
621 for (
const uint256& header : filter_headers) {
627 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
633 for (
const uint256& header : filter_headers) {
637 std::string strHex =
HexStr(ssHeader) +
"\n";
645 for (
const uint256& header : filter_headers) {
649 std::string strJSON = jsonHeaders.
write() +
"\n";
651 req->
WriteHeader(
"Content-Type",
"application/json");
669 std::vector<std::string> uri_parts =
SplitString(param,
'/');
670 if (uri_parts.size() != 2) {
671 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
690 bool block_was_connected;
693 if (!maybe_chainman)
return false;
703 bool index_ready = index->BlockUntilSyncedToCurrentChain();
707 std::string errmsg =
"Filter not found.";
709 if (!block_was_connected) {
710 errmsg +=
" Block was not connected to active chain.";
711 }
else if (!index_ready) {
712 errmsg +=
" Block filters are still in the process of being indexed.";
714 errmsg +=
" This error is unexpected and indicates index corruption.";
726 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
734 std::string strHex =
HexStr(ssResp) +
"\n";
743 std::string strJSON =
ret.write() +
"\n";
745 req->
WriteHeader(
"Content-Type",
"application/json");
771 std::string strJSON = chainInfoObject.
write() +
"\n";
773 req->
WriteHeader(
"Content-Type",
"application/json");
790 std::string hash_str;
792 const bool current_tip{hash_str.empty()};
807 if (!chainman)
return false;
816 req->
WriteHeader(
"Content-Type",
"application/json");
834 if (param !=
"contents" && param !=
"info") {
839 if (!mempool)
return false;
843 std::string str_json;
844 if (param ==
"contents") {
845 std::string raw_verbose;
848 }
catch (
const std::runtime_error& e) {
851 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
852 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
854 std::string raw_mempool_sequence;
856 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
857 }
catch (
const std::runtime_error& e) {
860 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
861 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
863 const bool verbose{raw_verbose ==
"true"};
864 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
865 if (verbose && mempool_sequence) {
866 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
874 req->
WriteHeader(
"Content-Type",
"application/json");
897 g_txindex->BlockUntilSyncedToCurrentChain();
901 if (!
node)
return false;
913 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
922 std::string strHex =
HexStr(ssTx) +
"\n";
932 std::string strJSON = objTx.
write() +
"\n";
934 req->
WriteHeader(
"Content-Type",
"application/json");
952 std::vector<std::string> uriParts;
953 if (param.length() > 1)
955 std::string strUriParams = param.substr(1);
960 std::string strRequestMutable = req->
ReadBody();
961 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
964 bool fInputParsed =
false;
965 bool fCheckMemPool =
false;
966 std::vector<COutPoint> vOutPoints;
971 if (uriParts.size() > 0)
974 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
976 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
978 const auto txid_out{util::Split<std::string_view>(uriParts[i],
'-')};
979 if (txid_out.size() != 2) {
983 auto output{ToIntegral<uint32_t>(txid_out.at(1))};
985 if (!txid || !output) {
989 vOutPoints.emplace_back(*txid, *output);
992 if (vOutPoints.size() > 0)
1001 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
1002 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
1009 if (strRequestMutable.size() > 0)
1015 oss << strRequestMutable;
1016 oss >> fCheckMemPool;
1019 }
catch (
const std::ios_base::failure&) {
1041 std::vector<unsigned char> bitmap;
1042 std::vector<CCoin> outs;
1043 std::string bitmapStringRepresentation;
1044 std::vector<bool> hits;
1045 bitmap.resize(
CeilDiv(vOutPoints.size(), 8u));
1047 if (!maybe_chainman)
return false;
1053 for (
const COutPoint& vOutPoint : vOutPoints) {
1054 auto coin = !mempool || !mempool->isSpent(vOutPoint) ? view.GetCoin(vOutPoint) : std::nullopt;
1055 hits.push_back(coin.has_value());
1056 if (coin) outs.emplace_back(std::move(*coin));
1062 if (fCheckMemPool) {
1064 if (!mempool)
return false;
1069 process_utxos(viewMempool, mempool);
1075 for (
size_t i = 0; i < hits.size(); ++i) {
1076 const bool hit = hits[i];
1077 bitmapStringRepresentation.append(hit ?
"1" :
"0");
1078 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
1087 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1090 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1097 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1098 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
1111 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
1112 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.
GetHex());
1113 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
1116 for (
const CCoin& coin : outs) {
1118 utxo.
pushKV(
"height", coin.nHeight);
1124 utxo.
pushKV(
"scriptPubKey", std::move(o));
1127 objGetUTXOResponse.
pushKV(
"utxos", std::move(utxos));
1130 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
1132 req->
WriteHeader(
"Content-Type",
"application/json");
1143 const std::string& str_uri_part)
1146 std::string height_str;
1149 const auto blockheight{ToIntegral<int32_t>(height_str)};
1150 if (!blockheight || *blockheight < 0) {
1157 if (!maybe_chainman)
return false;
1161 if (*blockheight > active_chain.
Height()) {
1164 pblockindex = active_chain[*blockheight];
1172 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1184 req->
WriteHeader(
"Content-Type",
"application/json");
1196static 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
uint32_t nHeight
at which height this containing transaction was included in the active block chain
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.