67 uint32_t nTxVerDummy = 0;
68 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
88 auto node_context = util::AnyPtr<NodeContext>(context);
105 auto node_context = util::AnyPtr<NodeContext>(context);
106 if (!node_context || !node_context->mempool) {
110 return node_context->mempool.get();
122 auto node_context = util::AnyPtr<NodeContext>(context);
123 if (!node_context || !node_context->chainman) {
127 return node_context->chainman.get();
134 param = strReq.substr(0, strReq.rfind(
'?'));
135 const std::string::size_type pos_format{param.rfind(
'.')};
138 if (pos_format == std::string::npos) {
143 const std::string suffix(param, pos_format + 1);
144 for (
const auto& rf_name :
rf_names) {
145 if (suffix == rf_name.name) {
146 param.erase(pos_format);
158 for (
const auto& rf_name :
rf_names) {
159 if (strlen(rf_name.name) > 0) {
161 formats.append(rf_name.name);
162 formats.append(
", ");
166 if (formats.length() > 0)
167 return formats.substr(0, formats.length() - 2);
174 std::string statusmessage;
182 const std::string& uri_part)
188 std::vector<std::string> path =
SplitString(param,
'/');
190 std::string raw_count;
192 if (path.size() == 2) {
196 }
else if (path.size() == 1) {
201 }
catch (
const std::runtime_error& e) {
205 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
208 const auto parsed_count{ToIntegral<size_t>(raw_count)};
219 std::vector<const CBlockIndex*>
headers;
220 headers.reserve(*parsed_count);
222 if (!maybe_chainman)
return false;
227 tip = active_chain.
Tip();
229 while (pindex !=
nullptr && active_chain.
Contains(*pindex)) {
231 if (
headers.size() == *parsed_count) {
234 pindex = active_chain.
Next(*pindex);
242 ssHeader << pindex->GetBlockHeader();
245 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
253 ssHeader << pindex->GetBlockHeader();
256 std::string strHex =
HexStr(ssHeader) +
"\n";
266 std::string strJSON = jsonHeaders.
write() +
"\n";
267 req->
WriteHeader(
"Content-Type",
"application/json");
287 coin.
out.Serialize(stream);
306 prevout.
pushKV(
"scriptPubKey", std::move(script_pub_key));
308 tx_prevouts.
push_back(std::move(prevout));
310 result.
push_back(std::move(tx_prevouts));
321 std::vector<std::string> path =
SplitString(param,
'/');
324 if (path.size() == 1) {
355 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
363 const std::string strHex{
HexStr(ssSpentResponse) +
"\n"};
372 std::string strJSON = result.
write() +
"\n";
373 req->
WriteHeader(
"Content-Type",
"application/json");
392 const std::string& uri_part,
393 std::optional<TxVerbosity> tx_verbosity,
394 std::optional<std::pair<size_t, size_t>> block_part = std::nullopt)
410 if (!maybe_chainman)
return false;
420 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
430 switch (block_data.error()) {
441 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
447 const std::string strHex{
HexStr(*block_data) +
"\n"};
458 std::string strJSON = objBlock.
write() +
"\n";
459 req->
WriteHeader(
"Content-Type",
"application/json");
485 if (
const auto opt_offset{ToIntegral<size_t>(req->
GetQueryParameter(
"offset").value_or(
""))}) {
486 if (
const auto opt_size{ToIntegral<size_t>(req->
GetQueryParameter(
"size").value_or(
""))}) {
489 {{*opt_offset, *opt_size}});
496 }
catch (
const std::runtime_error& e) {
508 std::vector<std::string> uri_parts =
SplitString(param,
'/');
509 std::string raw_count;
510 std::string raw_blockhash;
511 if (uri_parts.size() == 3) {
513 raw_blockhash = uri_parts[2];
514 raw_count = uri_parts[1];
515 }
else if (uri_parts.size() == 2) {
517 raw_blockhash = uri_parts[1];
520 }
catch (
const std::runtime_error& e) {
524 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
527 const auto parsed_count{ToIntegral<size_t>(raw_count)};
547 std::vector<const CBlockIndex*>
headers;
548 headers.reserve(*parsed_count);
551 if (!maybe_chainman)
return false;
556 while (pindex !=
nullptr && active_chain.
Contains(*pindex)) {
558 if (
headers.size() == *parsed_count)
560 pindex = active_chain.
Next(*pindex);
564 bool index_ready = index->BlockUntilSyncedToCurrentChain();
566 std::vector<uint256> filter_headers;
567 filter_headers.reserve(*parsed_count);
571 std::string errmsg =
"Filter not found.";
574 errmsg +=
" Block filters are still in the process of being indexed.";
576 errmsg +=
" This error is unexpected and indicates index corruption.";
581 filter_headers.push_back(filter_header);
587 for (
const uint256& header : filter_headers) {
591 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
597 for (
const uint256& header : filter_headers) {
601 std::string strHex =
HexStr(ssHeader) +
"\n";
608 for (
const uint256& header : filter_headers) {
612 std::string strJSON = jsonHeaders.
write() +
"\n";
613 req->
WriteHeader(
"Content-Type",
"application/json");
631 std::vector<std::string> uri_parts =
SplitString(param,
'/');
632 if (uri_parts.size() != 2) {
633 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
652 bool block_was_connected;
655 if (!maybe_chainman)
return false;
665 bool index_ready = index->BlockUntilSyncedToCurrentChain();
669 std::string errmsg =
"Filter not found.";
671 if (!block_was_connected) {
672 errmsg +=
" Block was not connected to active chain.";
673 }
else if (!index_ready) {
674 errmsg +=
" Block filters are still in the process of being indexed.";
676 errmsg +=
" This error is unexpected and indicates index corruption.";
687 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
695 std::string strHex =
HexStr(ssResp) +
"\n";
703 std::string strJSON =
ret.write() +
"\n";
704 req->
WriteHeader(
"Content-Type",
"application/json");
730 std::string strJSON = chainInfoObject.
write() +
"\n";
731 req->
WriteHeader(
"Content-Type",
"application/json");
748 std::string hash_str;
757 if (!hash_str.empty()) {
764 if (!chainman)
return false;
772 req->
WriteHeader(
"Content-Type",
"application/json");
790 if (param !=
"contents" && param !=
"info") {
795 if (!mempool)
return false;
799 std::string str_json;
800 if (param ==
"contents") {
801 std::string raw_verbose;
804 }
catch (
const std::runtime_error& e) {
807 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
808 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
810 std::string raw_mempool_sequence;
812 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
813 }
catch (
const std::runtime_error& e) {
816 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
817 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
819 const bool verbose{raw_verbose ==
"true"};
820 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
821 if (verbose && mempool_sequence) {
822 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
829 req->
WriteHeader(
"Content-Type",
"application/json");
852 g_txindex->BlockUntilSyncedToCurrentChain();
856 if (!
node)
return false;
868 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
877 std::string strHex =
HexStr(ssTx) +
"\n";
886 std::string strJSON = objTx.
write() +
"\n";
887 req->
WriteHeader(
"Content-Type",
"application/json");
905 std::vector<std::string> uriParts;
906 if (param.length() > 1)
908 std::string strUriParams = param.substr(1);
913 std::string strRequestMutable = req->
ReadBody();
914 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
917 bool fInputParsed =
false;
918 bool fCheckMemPool =
false;
919 std::vector<COutPoint> vOutPoints;
924 if (uriParts.size() > 0)
927 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
929 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
931 const auto txid_out{util::Split<std::string_view>(uriParts[i],
'-')};
932 if (txid_out.size() != 2) {
936 auto output{ToIntegral<uint32_t>(txid_out.at(1))};
938 if (!txid || !output) {
942 vOutPoints.emplace_back(*txid, *output);
945 if (vOutPoints.size() > 0)
954 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
955 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
962 if (strRequestMutable.size() > 0)
968 oss << strRequestMutable;
969 oss >> fCheckMemPool;
972 }
catch (
const std::ios_base::failure&) {
994 std::vector<unsigned char> bitmap;
995 std::vector<CCoin> outs;
996 std::string bitmapStringRepresentation;
997 std::vector<bool> hits;
998 bitmap.resize(
CeilDiv(vOutPoints.size(), 8u));
1000 if (!maybe_chainman)
return false;
1006 for (
const COutPoint& vOutPoint : vOutPoints) {
1007 auto coin = !mempool || !mempool->isSpent(vOutPoint) ? view.GetCoin(vOutPoint) : std::nullopt;
1008 hits.push_back(coin.has_value());
1009 if (coin) outs.emplace_back(std::move(*coin));
1015 if (fCheckMemPool) {
1017 if (!mempool)
return false;
1022 process_utxos(viewMempool, mempool);
1028 for (
size_t i = 0; i < hits.size(); ++i) {
1029 const bool hit = hits[i];
1030 bitmapStringRepresentation.append(hit ?
"1" :
"0");
1031 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
1040 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1042 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1049 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1050 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
1062 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
1063 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.
GetHex());
1064 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
1067 for (
const CCoin& coin : outs) {
1069 utxo.
pushKV(
"height", coin.nHeight);
1075 utxo.
pushKV(
"scriptPubKey", std::move(o));
1078 objGetUTXOResponse.
pushKV(
"utxos", std::move(utxos));
1081 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
1082 req->
WriteHeader(
"Content-Type",
"application/json");
1093 const std::string& str_uri_part)
1096 std::string height_str;
1099 const auto blockheight{ToIntegral<int32_t>(height_str)};
1100 if (!blockheight || *blockheight < 0) {
1107 if (!maybe_chainman)
return false;
1111 if (*blockheight > active_chain.
Height()) {
1114 pblockindex = active_chain[*blockheight];
1120 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1130 req->
WriteHeader(
"Content-Type",
"application/json");
1142static 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).
static 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 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 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.