22 #include <boost/algorithm/string.hpp> 26 static const size_t MAX_GETUTXOS_OUTPOINTS = 15;
54 template <
typename Stream,
typename Operation>
57 uint32_t nTxVerDummy = 0;
71 static RetFormat ParseDataFormat(std::string& param,
const std::string& strReq)
73 const std::string::size_type pos = strReq.rfind(
'.');
74 if (pos == std::string::npos)
77 return rf_names[0].rf;
80 param = strReq.substr(0, pos);
81 const std::string suff(strReq, pos + 1);
83 for (
unsigned int i = 0; i <
ARRAYLEN(rf_names); i++)
84 if (suff == rf_names[i].
name)
85 return rf_names[i].rf;
89 return rf_names[0].rf;
92 static std::string AvailableDataFormatsString()
95 for (
unsigned int i = 0; i <
ARRAYLEN(rf_names); i++)
96 if (strlen(rf_names[i].
name) > 0) {
98 formats.append(rf_names[i].
name);
102 if (formats.length() > 0)
103 return formats.substr(0, formats.length() - 2);
110 std::string statusmessage;
117 const std::string& strURIPart)
119 if (!CheckWarmup(req))
122 const RetFormat rf = ParseDataFormat(param, strURIPart);
123 std::vector<std::string> path;
124 boost::split(path, param, boost::is_any_of(
"/"));
126 if (path.size() != 2)
127 return RESTERR(req,
HTTP_BAD_REQUEST,
"No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
129 long count = strtol(path[0].c_str(),
nullptr, 10);
130 if (count < 1 || count > 2000)
131 return RESTERR(req,
HTTP_BAD_REQUEST,
"Header count out of range: " + path[0]);
133 std::string hashStr = path[1];
138 std::vector<const CBlockIndex *> headers;
139 headers.reserve(count);
144 headers.push_back(pindex);
145 if (headers.size() == (
unsigned long)count)
158 std::string binaryHeader = ssHeader.str();
159 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
170 std::string strHex =
HexStr(ssHeader.begin(), ssHeader.end()) +
"\n";
183 std::string strJSON = jsonHeaders.write() +
"\n";
184 req->
WriteHeader(
"Content-Type",
"application/json");
189 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: .bin, .hex)");
195 const std::string& strURIPart,
198 if (!CheckWarmup(req))
201 const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
217 return RESTERR(req,
HTTP_NOT_FOUND, hashStr +
" not available (pruned data)");
227 std::string binaryBlock = ssBlock.str();
228 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
236 std::string strHex =
HexStr(ssBlock.begin(), ssBlock.end()) +
"\n";
246 objBlock =
blockToJSON(block, pblockindex, showTxDetails);
248 std::string strJSON = objBlock.
write() +
"\n";
249 req->
WriteHeader(
"Content-Type",
"application/json");
255 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
260 static bool rest_block_extended(
HTTPRequest* req,
const std::string& strURIPart)
262 return rest_block(req, strURIPart,
true);
265 static bool rest_block_notxdetails(
HTTPRequest* req,
const std::string& strURIPart)
267 return rest_block(req, strURIPart,
false);
273 static bool rest_chaininfo(
HTTPRequest* req,
const std::string& strURIPart)
275 if (!CheckWarmup(req))
278 const RetFormat rf = ParseDataFormat(param, strURIPart);
285 std::string strJSON = chainInfoObject.
write() +
"\n";
286 req->
WriteHeader(
"Content-Type",
"application/json");
291 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
296 static bool rest_mempool_info(
HTTPRequest* req,
const std::string& strURIPart)
298 if (!CheckWarmup(req))
301 const RetFormat rf = ParseDataFormat(param, strURIPart);
307 std::string strJSON = mempoolInfoObject.
write() +
"\n";
308 req->
WriteHeader(
"Content-Type",
"application/json");
313 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
318 static bool rest_mempool_contents(
HTTPRequest* req,
const std::string& strURIPart)
320 if (!CheckWarmup(req))
323 const RetFormat rf = ParseDataFormat(param, strURIPart);
329 std::string strJSON = mempoolObject.
write() +
"\n";
330 req->
WriteHeader(
"Content-Type",
"application/json");
335 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
340 static bool rest_tx(
HTTPRequest* req,
const std::string& strURIPart)
342 if (!CheckWarmup(req))
345 const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
352 g_txindex->BlockUntilSyncedToCurrentChain();
365 std::string binaryTx = ssTx.str();
366 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
375 std::string strHex =
HexStr(ssTx.begin(), ssTx.end()) +
"\n";
384 std::string strJSON = objTx.write() +
"\n";
385 req->
WriteHeader(
"Content-Type",
"application/json");
391 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
396 static bool rest_getutxos(
HTTPRequest* req,
const std::string& strURIPart)
398 if (!CheckWarmup(req))
401 const RetFormat rf = ParseDataFormat(param, strURIPart);
403 std::vector<std::string> uriParts;
404 if (param.length() > 1)
406 std::string strUriParams = param.substr(1);
407 boost::split(uriParts, strUriParams, boost::is_any_of(
"/"));
411 std::string strRequestMutable = req->
ReadBody();
412 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
415 bool fInputParsed =
false;
416 bool fCheckMemPool =
false;
417 std::vector<COutPoint> vOutPoints;
422 if (uriParts.size() > 0)
425 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
427 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
431 std::string strTxid = uriParts[i].substr(0, uriParts[i].find(
'-'));
432 std::string strOutput = uriParts[i].substr(uriParts[i].find(
'-')+1);
438 vOutPoints.push_back(
COutPoint(txid, (uint32_t)nOutput));
441 if (vOutPoints.size() > 0)
450 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
451 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
457 if (strRequestMutable.size() > 0)
460 return RESTERR(req,
HTTP_BAD_REQUEST,
"Combination of URI scheme inputs and raw post data is not allowed");
463 oss << strRequestMutable;
464 oss >> fCheckMemPool;
467 }
catch (
const std::ios_base::failure&) {
480 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
485 if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
486 return RESTERR(req,
HTTP_BAD_REQUEST,
strprintf(
"Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
489 std::vector<unsigned char> bitmap;
490 std::vector<CCoin> outs;
491 std::string bitmapStringRepresentation;
492 std::vector<bool> hits;
493 bitmap.resize((vOutPoints.size() + 7) / 8);
496 for (
const COutPoint& vOutPoint : vOutPoints) {
498 bool hit = !
mempool.
isSpent(vOutPoint) && view.GetCoin(vOutPoint, coin);
500 if (hit) outs.emplace_back(std::move(coin));
509 process_utxos(viewMempool,
mempool);
515 for (
size_t i = 0; i < hits.size(); ++i) {
516 const bool hit = hits[i];
517 bitmapStringRepresentation.append(hit ?
"1" :
"0");
518 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
528 std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
530 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
538 std::string strHex =
HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) +
"\n";
552 objGetUTXOResponse.pushKV(
"bitmap", bitmapStringRepresentation);
555 for (
const CCoin& coin : outs) {
557 utxo.pushKV(
"height", (int32_t)coin.
nHeight);
563 utxo.pushKV(
"scriptPubKey", o);
564 utxos.push_back(utxo);
566 objGetUTXOResponse.pushKV(
"utxos", utxos);
569 std::string strJSON = objGetUTXOResponse.write() +
"\n";
570 req->
WriteHeader(
"Content-Type",
"application/json");
575 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
580 static const struct {
584 {
"/rest/tx/", rest_tx},
585 {
"/rest/block/notxdetails/", rest_block_notxdetails},
586 {
"/rest/block/", rest_block_extended},
587 {
"/rest/chaininfo", rest_chaininfo},
588 {
"/rest/mempool/info", rest_mempool_info},
589 {
"/rest/mempool/contents", rest_mempool_contents},
590 {
"/rest/headers/", rest_headers},
591 {
"/rest/getutxos", rest_getutxos},
596 for (
unsigned int i = 0; i <
ARRAYLEN(uri_prefixes); i++)
606 for (
unsigned int i = 0; i <
ARRAYLEN(uri_prefixes); i++)
bool(* handler)(HTTPRequest *req, const std::string &strReq)
bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus::Params &consensusParams, uint256 &hashBlock, bool fAllowSlow, CBlockIndex *blockIndex)
Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock...
UniValue mempoolInfoToJSON()
Mempool information to JSON.
CBlockHeader GetBlockHeader() const
int Height() const
Return the maximal height in the chain.
CTxOut out
unspent transaction output
UniValue ValueFromAmount(const CAmount &amount)
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
HTTPStatusCode
HTTP status codes.
UniValue blockheaderToJSON(const CBlockIndex *blockindex)
Block header to JSON.
Double ended buffer combining vector and stream-like interfaces.
std::shared_ptr< const CTransaction > CTransactionRef
bool isSpent(const COutPoint &outpoint) const
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
std::unique_ptr< CCoinsViewCache > pcoinsTip
Global variable that points to the active CCoinsView (protected by cs_main)
uint256 GetBlockHash() const
uint32_t nHeight
at which height this containing transaction was included in the active block chain ...
Abstract view on the open txout dataset.
bool ParseInt32(const std::string &str, int32_t *out)
Convert string to signed 32-bit integer with strict parse error feedback.
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
UniValue getblockchaininfo(const JSONRPCRequest &request)
Implementation of IsSuperMajority with better feedback.
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...
bool IsHex(const std::string &str)
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
An output of a transaction.
An outpoint - a combination of a transaction hash and an index n into its vout.
UniValue mempoolToJSON(bool fVerbose)
Mempool to JSON.
void StartREST()
Start HTTP REST subsystem.
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.
void StopREST()
Stop HTTP REST subsystem.
The block chain is a tree shaped structure starting with the genesis block at the root...
const CChainParams & Params()
Return the currently selected parameters.
bool IsBlockPruned(const CBlockIndex *pblockindex)
Check whether the block associated with this index entry is pruned or not.
int RPCSerializationFlags()
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
std::string GetHex() const
bool RPCIsInWarmup(std::string *outStatus)
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
std::string ReadBody()
Read request body.
void TxToUniv(const CTransaction &tx, const uint256 &hashBlock, UniValue &entry, bool include_hex=true, int serialize_flags=0)
bool ParseHashStr(const std::string &strHex, uint256 &result)
Parse a hex string into 256 bits.
void SerializationOp(Stream &s, Operation ser_action)
bool ReadBlockFromDisk(CBlock &block, const CDiskBlockPos &pos, const Consensus::Params &consensusParams)
Functions for disk access for blocks.
void InterruptREST()
Interrupt RPC REST subsystem.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
CChain & chainActive
The currently-connected chain of blocks (protected by cs_main).
UniValue blockToJSON(const CBlock &block, const CBlockIndex *blockindex, bool txDetails)
Block description to JSON.
void SetHex(const char *psz)
CCoinsView that brings transactions from a mempool into view.
std::vector< unsigned char > ParseHex(const char *psz)
CBlockIndex * LookupBlockIndex(const uint256 &hash)