6#include <bitcoin-build-config.h>
67 uint32_t nTxVerDummy = 0;
68 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
88 auto node_context = util::AnyPtr<NodeContext>(context);
92 "Internal bug detected: Node context not found!\n"
93 "You may report this issue here: %s\n",
94 __FILE__, __LINE__, __func__, CLIENT_BUGREPORT));
109 auto node_context = util::AnyPtr<NodeContext>(context);
110 if (!node_context || !node_context->mempool) {
114 return node_context->mempool.get();
126 auto node_context = util::AnyPtr<NodeContext>(context);
127 if (!node_context || !node_context->chainman) {
130 "Internal bug detected: Chainman disabled or instance not found!\n"
131 "You may report this issue here: %s\n",
132 __FILE__, __LINE__, __func__, CLIENT_BUGREPORT));
135 return node_context->chainman.get();
142 param = strReq.substr(0, strReq.rfind(
'?'));
143 const std::string::size_type pos_format{param.rfind(
'.')};
146 if (pos_format == std::string::npos) {
151 const std::string suffix(param, pos_format + 1);
152 for (
const auto& rf_name :
rf_names) {
153 if (suffix == rf_name.name) {
154 param.erase(pos_format);
166 for (
const auto& rf_name :
rf_names) {
167 if (strlen(rf_name.name) > 0) {
169 formats.append(rf_name.name);
170 formats.append(
", ");
174 if (formats.length() > 0)
175 return formats.substr(0, formats.length() - 2);
182 std::string statusmessage;
190 const std::string& uri_part)
196 std::vector<std::string> path =
SplitString(param,
'/');
198 std::string raw_count;
200 if (path.size() == 2) {
204 }
else if (path.size() == 1) {
209 }
catch (
const std::runtime_error& e) {
213 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
216 const auto parsed_count{ToIntegral<size_t>(raw_count)};
227 std::vector<const CBlockIndex*> headers;
228 headers.reserve(*parsed_count);
230 if (!maybe_chainman)
return false;
235 tip = active_chain.
Tip();
237 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
238 headers.push_back(pindex);
239 if (headers.size() == *parsed_count) {
242 pindex = active_chain.
Next(pindex);
250 ssHeader << pindex->GetBlockHeader();
253 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
261 ssHeader << pindex->GetBlockHeader();
264 std::string strHex =
HexStr(ssHeader) +
"\n";
274 std::string strJSON = jsonHeaders.
write() +
"\n";
275 req->
WriteHeader(
"Content-Type",
"application/json");
295 coin.
out.Serialize(stream);
314 prevout.
pushKV(
"scriptPubKey", std::move(script_pub_key));
316 tx_prevouts.
push_back(std::move(prevout));
318 result.
push_back(std::move(tx_prevouts));
329 std::vector<std::string> path =
SplitString(param,
'/');
332 if (path.size() == 1) {
363 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
371 const std::string strHex{
HexStr(ssSpentResponse) +
"\n"};
380 std::string strJSON = result.
write() +
"\n";
381 req->
WriteHeader(
"Content-Type",
"application/json");
394 const std::string& uri_part,
411 if (!maybe_chainman)
return false;
421 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
429 std::vector<std::byte> block_data{};
436 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
442 const std::string strHex{
HexStr(block_data) +
"\n"};
453 std::string strJSON = objBlock.
write() +
"\n";
454 req->
WriteHeader(
"Content-Type",
"application/json");
482 std::vector<std::string> uri_parts =
SplitString(param,
'/');
483 std::string raw_count;
484 std::string raw_blockhash;
485 if (uri_parts.size() == 3) {
487 raw_blockhash = uri_parts[2];
488 raw_count = uri_parts[1];
489 }
else if (uri_parts.size() == 2) {
491 raw_blockhash = uri_parts[1];
494 }
catch (
const std::runtime_error& e) {
498 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
501 const auto parsed_count{ToIntegral<size_t>(raw_count)};
521 std::vector<const CBlockIndex*> headers;
522 headers.reserve(*parsed_count);
525 if (!maybe_chainman)
return false;
530 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
531 headers.push_back(pindex);
532 if (headers.size() == *parsed_count)
534 pindex = active_chain.
Next(pindex);
538 bool index_ready = index->BlockUntilSyncedToCurrentChain();
540 std::vector<uint256> filter_headers;
541 filter_headers.reserve(*parsed_count);
545 std::string errmsg =
"Filter not found.";
548 errmsg +=
" Block filters are still in the process of being indexed.";
550 errmsg +=
" This error is unexpected and indicates index corruption.";
555 filter_headers.push_back(filter_header);
561 for (
const uint256& header : filter_headers) {
565 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
571 for (
const uint256& header : filter_headers) {
575 std::string strHex =
HexStr(ssHeader) +
"\n";
582 for (
const uint256& header : filter_headers) {
586 std::string strJSON = jsonHeaders.
write() +
"\n";
587 req->
WriteHeader(
"Content-Type",
"application/json");
605 std::vector<std::string> uri_parts =
SplitString(param,
'/');
606 if (uri_parts.size() != 2) {
607 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
626 bool block_was_connected;
629 if (!maybe_chainman)
return false;
639 bool index_ready = index->BlockUntilSyncedToCurrentChain();
643 std::string errmsg =
"Filter not found.";
645 if (!block_was_connected) {
646 errmsg +=
" Block was not connected to active chain.";
647 }
else if (!index_ready) {
648 errmsg +=
" Block filters are still in the process of being indexed.";
650 errmsg +=
" This error is unexpected and indicates index corruption.";
661 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
669 std::string strHex =
HexStr(ssResp) +
"\n";
677 std::string strJSON =
ret.write() +
"\n";
678 req->
WriteHeader(
"Content-Type",
"application/json");
704 std::string strJSON = chainInfoObject.
write() +
"\n";
705 req->
WriteHeader(
"Content-Type",
"application/json");
722 std::string hash_str;
731 if (!hash_str.empty()) {
738 if (!chainman)
return false;
746 req->
WriteHeader(
"Content-Type",
"application/json");
764 if (param !=
"contents" && param !=
"info") {
769 if (!mempool)
return false;
773 std::string str_json;
774 if (param ==
"contents") {
775 std::string raw_verbose;
778 }
catch (
const std::runtime_error& e) {
781 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
782 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
784 std::string raw_mempool_sequence;
786 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
787 }
catch (
const std::runtime_error& e) {
790 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
791 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
793 const bool verbose{raw_verbose ==
"true"};
794 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
795 if (verbose && mempool_sequence) {
796 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
803 req->
WriteHeader(
"Content-Type",
"application/json");
826 g_txindex->BlockUntilSyncedToCurrentChain();
830 if (!
node)
return false;
842 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
851 std::string strHex =
HexStr(ssTx) +
"\n";
860 std::string strJSON = objTx.
write() +
"\n";
861 req->
WriteHeader(
"Content-Type",
"application/json");
879 std::vector<std::string> uriParts;
880 if (param.length() > 1)
882 std::string strUriParams = param.substr(1);
887 std::string strRequestMutable = req->
ReadBody();
888 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
891 bool fInputParsed =
false;
892 bool fCheckMemPool =
false;
893 std::vector<COutPoint> vOutPoints;
898 if (uriParts.size() > 0)
901 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
903 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
905 const auto txid_out{util::Split<std::string_view>(uriParts[i],
'-')};
906 if (txid_out.size() != 2) {
910 auto output{ToIntegral<uint32_t>(txid_out.at(1))};
912 if (!txid || !output) {
916 vOutPoints.emplace_back(*txid, *output);
919 if (vOutPoints.size() > 0)
928 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
929 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
936 if (strRequestMutable.size() > 0)
942 oss << strRequestMutable;
943 oss >> fCheckMemPool;
946 }
catch (
const std::ios_base::failure&) {
968 std::vector<unsigned char> bitmap;
969 std::vector<CCoin> outs;
970 std::string bitmapStringRepresentation;
971 std::vector<bool> hits;
972 bitmap.resize((vOutPoints.size() + 7) / 8);
974 if (!maybe_chainman)
return false;
980 for (
const COutPoint& vOutPoint : vOutPoints) {
981 auto coin = !mempool || !mempool->isSpent(vOutPoint) ? view.GetCoin(vOutPoint) : std::nullopt;
982 hits.push_back(coin.has_value());
983 if (coin) outs.emplace_back(std::move(*coin));
991 if (!mempool)
return false;
996 process_utxos(viewMempool, mempool);
1002 for (
size_t i = 0; i < hits.size(); ++i) {
1003 const bool hit = hits[i];
1004 bitmapStringRepresentation.append(hit ?
"1" :
"0");
1005 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
1014 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1016 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1023 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
1024 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
1036 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
1037 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.
GetHex());
1038 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
1041 for (
const CCoin& coin : outs) {
1043 utxo.
pushKV(
"height", (int32_t)coin.nHeight);
1049 utxo.
pushKV(
"scriptPubKey", std::move(o));
1052 objGetUTXOResponse.
pushKV(
"utxos", std::move(utxos));
1055 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
1056 req->
WriteHeader(
"Content-Type",
"application/json");
1067 const std::string& str_uri_part)
1070 std::string height_str;
1073 const auto blockheight{ToIntegral<int32_t>(height_str)};
1074 if (!blockheight || *blockheight < 0) {
1081 if (!maybe_chainman)
return false;
1085 if (*blockheight > active_chain.
Height()) {
1088 pblockindex = active_chain[*blockheight];
1094 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
1104 req->
WriteHeader(
"Content-Type",
"application/json");
1116static 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(const std::string &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
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.
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
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...
int Height() const
Return the maximal height in the chain.
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
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 ...
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
An output of a transaction.
Undo information for a CTransaction.
std::vector< Coin > vprevout
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
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...
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
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.
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...
void WriteReply(int nStatus, std::string_view reply="")
Write HTTP reply.
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
std::string ReadBody()
Read request body.
UniValue HandleRequest(const JSONRPCRequest &request) const
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
bool ReadRawBlock(std::vector< std::byte > &block, const FlatFilePos &pos) const
static std::optional< transaction_identifier > FromHex(std::string_view hex)
static std::optional< uint256 > FromHex(std::string_view str)
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
TxVerbosity
Verbose level for block's transaction.
@ SHOW_DETAILS_AND_PREVOUT
The same as previous option with information about prevouts if available.
@ SHOW_TXID
Only TXID for each block's transaction.
void ScriptToUniv(const CScript &script, UniValue &out, bool include_hex=true, bool include_address=false, const SigningProvider *provider=nullptr)
UniValue ValueFromAmount(const CAmount amount)
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, uint256 &hashBlock, const BlockManager &blockman)
Return transaction with a given hash.
std::vector< std::string > SplitString(std::string_view str, char sep)
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_filter(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, TxVerbosity tx_verbosity)
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 const struct @10 uri_prefixes[]
void StopREST()
Stop HTTP REST subsystem.
RPCHelpMan getdeploymentinfo()
RPCHelpMan getblockchaininfo()
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.
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)
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.