21 #include <boost/algorithm/string.hpp>
26 static const size_t MAX_GETUTXOS_OUTPOINTS = 15;
54 uint32_t nTxVerDummy = 0;
55 READWRITE(nTxVerDummy, obj.nHeight, obj.out);
72 static enum RetFormat ParseDataFormat(std::vector<std::string>& params,
const std::string& strReq)
74 boost::split(params, strReq, boost::is_any_of(
"."));
75 if (params.size() > 1) {
76 for (
unsigned int i = 0; i <
ARRAYLEN(rf_names); i++)
77 if (params[1] == rf_names[i].
name)
78 return rf_names[i].rf;
81 return rf_names[0].rf;
84 static std::string AvailableDataFormatsString()
86 std::string formats =
"";
87 for (
unsigned int i = 0; i <
ARRAYLEN(rf_names); i++)
88 if (strlen(rf_names[i].
name) > 0) {
90 formats.append(rf_names[i].
name);
94 if (formats.length() > 0)
95 return formats.substr(0, formats.length() - 2);
102 std::string statusmessage;
109 const std::string& strURIPart)
111 if (!CheckWarmup(req))
113 std::vector<std::string> params;
114 const RetFormat rf = ParseDataFormat(params, strURIPart);
115 std::vector<std::string> path;
116 boost::split(path, params[0], boost::is_any_of(
"/"));
118 if (path.size() != 2)
119 return RESTERR(req,
HTTP_BAD_REQUEST,
"No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
121 long count = strtol(path[0].c_str(),
nullptr, 10);
122 if (count < 1 || count > 2000)
123 return RESTERR(req,
HTTP_BAD_REQUEST,
"Header count out of range: " + path[0]);
125 std::string hashStr = path[1];
131 std::vector<const CBlockIndex *> headers;
132 headers.reserve(count);
138 headers.push_back(pindex);
139 if (headers.size() == (
unsigned long)count)
152 std::string binaryHeader = ssHeader.str();
153 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
159 std::string strHex =
HexStr(ssHeader) +
"\n";
169 std::string strJSON = jsonHeaders.write() +
"\n";
170 req->
WriteHeader(
"Content-Type",
"application/json");
175 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: .bin, .hex)");
181 const std::string& strURIPart,
184 if (!CheckWarmup(req))
186 std::vector<std::string> params;
187 const RetFormat rf = ParseDataFormat(params, strURIPart);
189 std::string hashStr = params[0];
206 return RESTERR(req,
HTTP_NOT_FOUND, hashStr +
" not available (pruned data)");
217 std::string binaryBlock = ssBlock.str();
218 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
224 std::string strHex =
HexStr(ssBlock) +
"\n";
232 std::string strJSON = objBlock.
write() +
"\n";
233 req->
WriteHeader(
"Content-Type",
"application/json");
239 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
244 static bool rest_block_extended(
HTTPRequest* req,
const std::string& strURIPart)
246 return rest_block(req, strURIPart,
true);
249 static bool rest_block_notxdetails(
HTTPRequest* req,
const std::string& strURIPart)
251 return rest_block(req, strURIPart,
false);
257 static bool rest_chaininfo(
HTTPRequest* req,
const std::string& strURIPart)
259 if (!CheckWarmup(req))
261 std::vector<std::string> params;
262 const RetFormat rf = ParseDataFormat(params, strURIPart);
269 std::string strJSON = chainInfoObject.
write() +
"\n";
270 req->
WriteHeader(
"Content-Type",
"application/json");
275 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
280 static bool rest_mempool_info(
HTTPRequest* req,
const std::string& strURIPart)
282 if (!CheckWarmup(req))
284 std::vector<std::string> params;
285 const RetFormat rf = ParseDataFormat(params, strURIPart);
291 std::string strJSON = mempoolInfoObject.
write() +
"\n";
292 req->
WriteHeader(
"Content-Type",
"application/json");
297 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
302 static bool rest_mempool_contents(
HTTPRequest* req,
const std::string& strURIPart)
304 if (!CheckWarmup(req))
306 std::vector<std::string> params;
307 const RetFormat rf = ParseDataFormat(params, strURIPart);
313 std::string strJSON = mempoolObject.
write() +
"\n";
314 req->
WriteHeader(
"Content-Type",
"application/json");
319 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
324 static bool rest_tx(
HTTPRequest* req,
const std::string& strURIPart)
326 if (!CheckWarmup(req))
328 std::vector<std::string> params;
329 const RetFormat rf = ParseDataFormat(params, strURIPart);
331 std::string hashStr = params[0];
346 std::string binaryTx = ssTx.str();
347 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
353 std::string strHex =
HexStr(ssTx) +
"\n";
368 TxToJSON(
nullptr, *tx, tip, pblockindex, objTx);
369 std::string strJSON = objTx.write() +
"\n";
370 req->
WriteHeader(
"Content-Type",
"application/json");
376 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
381 static bool rest_getutxos(
HTTPRequest* req,
const std::string& strURIPart)
383 if (!CheckWarmup(req))
385 std::vector<std::string> params;
386 enum RetFormat rf = ParseDataFormat(params, strURIPart);
388 std::vector<std::string> uriParts;
389 if (params.size() > 0 && params[0].length() > 1)
391 std::string strUriParams = params[0].substr(1);
392 boost::split(uriParts, strUriParams, boost::is_any_of(
"/"));
396 std::string strRequestMutable = req->
ReadBody();
397 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
400 bool fInputParsed =
false;
401 bool fCheckMemPool =
false;
402 std::vector<COutPoint> vOutPoints;
407 if (uriParts.size() > 0)
410 if (uriParts[0] ==
"checkmempool") fCheckMemPool =
true;
412 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
416 std::string strTxid = uriParts[i].substr(0, uriParts[i].find(
'-'));
417 std::string strOutput = uriParts[i].substr(uriParts[i].find(
'-')+1);
423 vOutPoints.emplace_back(txid, (uint32_t)nOutput);
426 if (vOutPoints.size() > 0)
435 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
436 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
442 if (strRequestMutable.size() > 0)
448 oss << strRequestMutable;
449 oss >> fCheckMemPool;
452 }
catch (
const std::ios_base::failure& e) {
465 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
470 if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
474 std::vector<unsigned char> bitmap;
475 std::vector<CCoin> outs;
476 std::string bitmapStringRepresentation;
477 std::vector<bool> hits;
478 bitmap.resize((vOutPoints.size() + 7) / 8);
489 view.SetBackend(viewMempool);
491 for (
size_t i = 0; i < vOutPoints.size(); i++) {
494 if (view.GetCoin(vOutPoints[i], coin) && !
mempool.
isSpent(vOutPoints[i])) {
496 outs.emplace_back(std::move(coin));
500 bitmapStringRepresentation.append(hit ?
"1" :
"0");
501 bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
511 std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
513 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
521 std::string strHex =
HexStr(ssGetUTXOResponse) +
"\n";
535 objGetUTXOResponse.pushKV(
"bitmap", bitmapStringRepresentation);
538 for (
const CCoin& coin : outs) {
540 utxo.pushKV(
"height", (int32_t)coin.
nHeight);
546 utxo.pushKV(
"scriptPubKey", o);
547 utxos.push_back(utxo);
549 objGetUTXOResponse.pushKV(
"utxos", utxos);
552 std::string strJSON = objGetUTXOResponse.write() +
"\n";
553 req->
WriteHeader(
"Content-Type",
"application/json");
558 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
563 static const struct {
567 {
"/rest/tx/", rest_tx},
568 {
"/rest/block/notxdetails/", rest_block_notxdetails},
569 {
"/rest/block/", rest_block_extended},
570 {
"/rest/chaininfo", rest_chaininfo},
571 {
"/rest/mempool/info", rest_mempool_info},
572 {
"/rest/mempool/contents", rest_mempool_contents},
573 {
"/rest/headers/", rest_headers},
574 {
"/rest/getutxos", rest_getutxos},
579 for (
unsigned int i = 0; i <
ARRAYLEN(uri_prefixes); i++)
590 for (
unsigned int i = 0; i <
ARRAYLEN(uri_prefixes); i++)
The block chain is a tree shaped structure starting with the genesis block at the root,...
CBlockHeader GetBlockHeader() const
uint256 GetBlockHash() const
unsigned int nTx
Number of transactions in this block.
uint32_t nStatus
Verification status of this block. See enum BlockStatus.
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...
CBlockIndex * Tip(bool fProofOfStake=false) const
Returns the index entry for the tip of this chain, or nullptr if none.
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 memorypool into view.
The basic transaction that is broadcasted on the network and contained in blocks.
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
bool isSpent(const COutPoint &outpoint)
An output of a transaction.
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
CTxOut out
unspent transaction output
uint32_t nHeight
at which height the containing transaction was included in the active block chain
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
std::string ReadBody()
Read request body.
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
void SetHex(const char *psz)
std::string GetHex() const
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
uint256 ParseHashStr(const std::string &, const std::string &strName)
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.
RecursiveMutex cs_main
Global state.
UniValue mempoolToJSON(bool fVerbose=false)
UniValue getblockchaininfo(const JSONRPCRequest &request)
UniValue mempoolInfoToJSON()
void StopREST()
Stop HTTP REST subsystem.
void TxToJSON(CWallet *const pwallet, const CTransaction &tx, const CBlockIndex *tip, const CBlockIndex *blockindex, UniValue &entry)
UniValue blockToJSON(const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, bool txDetails=false)
bool StartREST()
Start HTTP REST subsystem.
void InterruptREST()
Interrupt RPC REST subsystem.
UniValue blockheaderToJSON(const CBlockIndex *tip, const CBlockIndex *blockindex)
bool(* handler)(HTTPRequest *req, const std::string &strReq)
HTTPStatusCode
HTTP status codes.
@ HTTP_SERVICE_UNAVAILABLE
@ HTTP_INTERNAL_SERVER_ERROR
bool RPCIsInWarmup(std::string *outStatus)
UniValue ValueFromAmount(const CAmount &amount)
SERIALIZE_METHODS(CCoin, obj)
std::shared_ptr< const CTransaction > CTransactionRef
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::vector< unsigned char > ParseHex(const char *psz)
bool ParseInt32(const std::string &str, int32_t *out)
Convert string to signed 32-bit integer with strict parse error feedback.
bool IsHex(const std::string &str)
bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, uint256 &hashBlock, bool fAllowSlow, CBlockIndex *blockIndex)
Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock.
CTxMemPool mempool(::minRelayTxFee)
std::unique_ptr< CCoinsViewCache > pcoinsTip
Global variable that points to the active CCoinsView (protected by cs_main)
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos)
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)