6 #include <bitcoin-build-config.h> 66 uint32_t nTxVerDummy = 0;
67 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
87 auto node_context = util::AnyPtr<NodeContext>(context);
91 "Internal bug detected: Node context not found!\n" 92 "You may report this issue here: %s\n",
93 __FILE__, __LINE__, __func__, CLIENT_BUGREPORT));
108 auto node_context = util::AnyPtr<NodeContext>(context);
109 if (!node_context || !node_context->mempool) {
113 return node_context->mempool.get();
125 auto node_context = util::AnyPtr<NodeContext>(context);
126 if (!node_context || !node_context->chainman) {
129 "Internal bug detected: Chainman disabled or instance not found!\n" 130 "You may report this issue here: %s\n",
131 __FILE__, __LINE__, __func__, CLIENT_BUGREPORT));
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& strURIPart)
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)) {
237 headers.push_back(pindex);
238 if (headers.size() == *parsed_count) {
241 pindex = active_chain.
Next(pindex);
249 ssHeader << pindex->GetBlockHeader();
252 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
260 ssHeader << pindex->GetBlockHeader();
263 std::string strHex =
HexStr(ssHeader) +
"\n";
273 std::string strJSON = jsonHeaders.
write() +
"\n";
274 req->
WriteHeader(
"Content-Type",
"application/json");
286 const std::string& strURIPart,
303 if (!maybe_chainman)
return false;
313 if (chainman.
m_blockman.IsBlockPruned(*pblockindex)) {
321 std::vector<uint8_t> block_data{};
328 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
334 const std::string strHex{
HexStr(block_data) +
"\n"};
345 std::string strJSON = objBlock.
write() +
"\n";
346 req->
WriteHeader(
"Content-Type",
"application/json");
374 std::vector<std::string> uri_parts =
SplitString(param,
'/');
375 std::string raw_count;
376 std::string raw_blockhash;
377 if (uri_parts.size() == 3) {
379 raw_blockhash = uri_parts[2];
380 raw_count = uri_parts[1];
381 }
else if (uri_parts.size() == 2) {
383 raw_blockhash = uri_parts[1];
386 }
catch (
const std::runtime_error& e) {
390 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
393 const auto parsed_count{ToIntegral<size_t>(raw_count)};
413 std::vector<const CBlockIndex*> headers;
414 headers.reserve(*parsed_count);
417 if (!maybe_chainman)
return false;
422 while (pindex !=
nullptr && active_chain.
Contains(pindex)) {
423 headers.push_back(pindex);
424 if (headers.size() == *parsed_count)
426 pindex = active_chain.
Next(pindex);
430 bool index_ready = index->BlockUntilSyncedToCurrentChain();
432 std::vector<uint256> filter_headers;
433 filter_headers.reserve(*parsed_count);
437 std::string errmsg =
"Filter not found.";
440 errmsg +=
" Block filters are still in the process of being indexed.";
442 errmsg +=
" This error is unexpected and indicates index corruption.";
447 filter_headers.push_back(filter_header);
453 for (
const uint256& header : filter_headers) {
457 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
463 for (
const uint256& header : filter_headers) {
467 std::string strHex =
HexStr(ssHeader) +
"\n";
474 for (
const uint256& header : filter_headers) {
478 std::string strJSON = jsonHeaders.
write() +
"\n";
479 req->
WriteHeader(
"Content-Type",
"application/json");
497 std::vector<std::string> uri_parts =
SplitString(param,
'/');
498 if (uri_parts.size() != 2) {
499 return RESTERR(req,
HTTP_BAD_REQUEST,
"Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
518 bool block_was_connected;
521 if (!maybe_chainman)
return false;
531 bool index_ready = index->BlockUntilSyncedToCurrentChain();
535 std::string errmsg =
"Filter not found.";
537 if (!block_was_connected) {
538 errmsg +=
" Block was not connected to active chain.";
539 }
else if (!index_ready) {
540 errmsg +=
" Block filters are still in the process of being indexed.";
542 errmsg +=
" This error is unexpected and indicates index corruption.";
553 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
561 std::string strHex =
HexStr(ssResp) +
"\n";
569 std::string strJSON =
ret.write() +
"\n";
570 req->
WriteHeader(
"Content-Type",
"application/json");
596 std::string strJSON = chainInfoObject.
write() +
"\n";
597 req->
WriteHeader(
"Content-Type",
"application/json");
614 std::string hash_str;
623 if (!hash_str.empty()) {
630 if (!chainman)
return false;
638 req->
WriteHeader(
"Content-Type",
"application/json");
656 if (param !=
"contents" && param !=
"info") {
661 if (!mempool)
return false;
665 std::string str_json;
666 if (param ==
"contents") {
667 std::string raw_verbose;
670 }
catch (
const std::runtime_error& e) {
673 if (raw_verbose !=
"true" && raw_verbose !=
"false") {
674 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"verbose\" query parameter must be either \"true\" or \"false\".");
676 std::string raw_mempool_sequence;
678 raw_mempool_sequence = req->
GetQueryParameter(
"mempool_sequence").value_or(
"false");
679 }
catch (
const std::runtime_error& e) {
682 if (raw_mempool_sequence !=
"true" && raw_mempool_sequence !=
"false") {
683 return RESTERR(req,
HTTP_BAD_REQUEST,
"The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
685 const bool verbose{raw_verbose ==
"true"};
686 const bool mempool_sequence{raw_mempool_sequence ==
"true"};
687 if (verbose && mempool_sequence) {
688 return RESTERR(req,
HTTP_BAD_REQUEST,
"Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")");
695 req->
WriteHeader(
"Content-Type",
"application/json");
718 g_txindex->BlockUntilSyncedToCurrentChain();
722 if (!
node)
return false;
734 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
743 std::string strHex =
HexStr(ssTx) +
"\n";
752 std::string strJSON = objTx.
write() +
"\n";
753 req->
WriteHeader(
"Content-Type",
"application/json");
771 std::vector<std::string> uriParts;
772 if (param.length() > 1)
774 std::string strUriParams = param.substr(1);
779 std::string strRequestMutable = req->
ReadBody();
780 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
783 bool fInputParsed =
false;
784 bool fCheckMemPool =
false;
785 std::vector<COutPoint> vOutPoints;
790 if (uriParts.size() > 0)
793 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
795 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
797 const auto txid_out{util::Split<std::string_view>(uriParts[i],
'-')};
798 if (txid_out.size() != 2) {
802 auto output{ToIntegral<uint32_t>(txid_out.at(1))};
804 if (!txid || !output) {
808 vOutPoints.emplace_back(*txid, *output);
811 if (vOutPoints.size() > 0)
820 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
821 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
828 if (strRequestMutable.size() > 0)
834 oss << strRequestMutable;
835 oss >> fCheckMemPool;
838 }
catch (
const std::ios_base::failure&) {
860 std::vector<unsigned char> bitmap;
861 std::vector<CCoin> outs;
862 std::string bitmapStringRepresentation;
863 std::vector<bool> hits;
864 bitmap.resize((vOutPoints.size() + 7) / 8);
866 if (!maybe_chainman)
return false;
872 for (
const COutPoint& vOutPoint : vOutPoints) {
873 auto coin = !mempool || !mempool->isSpent(vOutPoint) ? view.GetCoin(vOutPoint) : std::nullopt;
874 hits.push_back(coin.has_value());
875 if (coin) outs.emplace_back(std::move(*coin));
883 if (!mempool)
return false;
888 process_utxos(viewMempool, mempool);
894 for (
size_t i = 0; i < hits.size(); ++i) {
895 const bool hit = hits[i];
896 bitmapStringRepresentation.append(hit ?
"1" :
"0");
897 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
906 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
908 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
915 ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
916 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
928 objGetUTXOResponse.
pushKV(
"chainHeight", active_height);
929 objGetUTXOResponse.
pushKV(
"chaintipHash", active_hash.GetHex());
930 objGetUTXOResponse.
pushKV(
"bitmap", bitmapStringRepresentation);
933 for (
const CCoin& coin : outs) {
935 utxo.
pushKV(
"height", (int32_t)coin.nHeight);
941 utxo.
pushKV(
"scriptPubKey", std::move(o));
944 objGetUTXOResponse.
pushKV(
"utxos", std::move(utxos));
947 std::string strJSON = objGetUTXOResponse.
write() +
"\n";
948 req->
WriteHeader(
"Content-Type",
"application/json");
959 const std::string& str_uri_part)
962 std::string height_str;
965 int32_t blockheight = -1;
966 if (!
ParseInt32(height_str, &blockheight) || blockheight < 0) {
973 if (!maybe_chainman)
return false;
977 if (blockheight > active_chain.
Height()) {
980 pblockindex = active_chain[blockheight];
986 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
996 req->
WriteHeader(
"Content-Type",
"application/json");
1008 static const struct {
std::shared_ptr< const CTransaction > CTransactionRef
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
static ChainstateManager * GetChainman(const std::any &context, HTTPRequest *req)
Get the node context chainstatemanager.
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
void push_back(UniValue val)
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
static bool CheckWarmup(HTTPRequest *req)
std::vector< std::string > SplitString(std::string_view str, char sep)
The same as previous option with information about prevouts if available.
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
bool ReadRawBlock(std::vector< uint8_t > &block, const FlatFilePos &pos) const
void WriteReply(int nStatus, std::string_view reply="")
Write HTTP reply.
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
TxVerbosity
Verbose level for block's transaction.
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity, const uint256 pow_limit)
Block description to JSON.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
static bool rest_getutxos(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
An in-memory indexed chain of blocks.
static std::string AvailableDataFormatsString()
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
static bool rest_tx(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
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.
int Height() const
Return the maximal height in the chain.
HTTPStatusCode
HTTP status codes.
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const uint256 &hash, uint256 &hashBlock, const BlockManager &blockman)
Return transaction with a given hash.
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
static const struct @10 uri_prefixes[]
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...
static bool rest_headers(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
SERIALIZE_METHODS(CCoin, obj)
uint256 GetBlockHash() const
static bool rest_mempool(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.
NodeContext struct containing references to chain state and connection state.
uint256 powLimit
Proof of work parameters.
static bool rest_block_extended(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
static bool RESTERR(HTTPRequest *req, enum HTTPStatusCode status, std::string message)
static bool rest_block(const std::any &context, HTTPRequest *req, const std::string &strURIPart, TxVerbosity tx_verbosity)
void ScriptToUniv(const CScript &script, UniValue &out, bool include_hex=true, bool include_address=false, const SigningProvider *provider=nullptr)
Abstract view on the open txout dataset.
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex, const uint256 pow_limit)
Block header to JSON.
Double ended buffer combining vector and stream-like interfaces.
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
Complete block filter struct as defined in BIP 157.
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
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...
static std::optional< uint256 > FromHex(std::string_view str)
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
const Consensus::Params & GetConsensus() const
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
An output of a transaction.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
An outpoint - a combination of a transaction hash and an index n into its vout.
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
static const struct @9 rf_names[]
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
bool ParseInt32(std::string_view str, int32_t *out)
Convert string to signed 32-bit integer with strict parse error feedback.
static bool rest_blockhash_by_height(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
static bool rest_block_notxdetails(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
bool IsValid(enum BlockStatus nUpTo=BLOCK_VALID_TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
static CTxMemPool * GetMemPool(const std::any &context, HTTPRequest *req)
Get the node context mempool.
static const size_t MAX_GETUTXOS_OUTPOINTS
RPCHelpMan getblockchaininfo()
static bool rest_filter_header(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
Only TXID for each block's transaction.
RPCHelpMan getdeploymentinfo()
void StopREST()
Stop HTTP REST subsystem.
The block chain is a tree shaped structure starting with the genesis block at the root...
void pushKV(std::string key, UniValue val)
static NodeContext * GetNodeContext(const std::any &context, HTTPRequest *req)
Get the node context.
static bool rest_block_filter(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
std::string GetHex() const
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
UniValue ValueFromAmount(const CAmount amount)
bool RPCIsInWarmup(std::string *outStatus)
std::string ReadBody()
Read request body.
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
void InterruptREST()
Interrupt RPC REST subsystem.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
full block available in blk*.dat
UniValue HandleRequest(const JSONRPCRequest &request) const
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
CCoinsView that brings transactions from a mempool into view.
static bool rest_deploymentinfo(const std::any &context, HTTPRequest *req, const std::string &str_uri_part)
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...
static std::optional< transaction_identifier > FromHex(std::string_view hex)
static constexpr unsigned int MAX_REST_HEADERS_RESULTS
static bool rest_chaininfo(const std::any &context, HTTPRequest *req, const std::string &strURIPart)
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it...
static constexpr TransactionSerParams TX_WITH_WITNESS
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
void StartREST(const std::any &context)
Start HTTP REST subsystem.