19 #include <boost/algorithm/string.hpp>
20 #include <boost/dynamic_bitset.hpp>
22 static const size_t MAX_GETUTXOS_OUTPOINTS = 15;
49 template<
typename Stream,
typename Operation>
50 inline void SerializationOp(Stream &s, Operation ser_action,
int nType,
int nVersion) {
76 static enum RetFormat ParseDataFormat(std::vector<std::string>& params,
const std::string& strReq) {
77 boost::split(params, strReq, boost::is_any_of(
"."));
78 if (params.size() > 1) {
79 for (
unsigned int i = 0; i <
ARRAYLEN(rf_names); i++)
80 if (params[1] == rf_names[i].
name)
81 return rf_names[i].rf;
84 return rf_names[0].rf;
87 static std::string AvailableDataFormatsString() {
88 std::string formats =
"";
89 for (
unsigned int i = 0; i <
ARRAYLEN(rf_names); i++)
90 if (strlen(rf_names[i].
name) > 0) {
92 formats.append(rf_names[i].
name);
96 if (formats.length() > 0)
97 return formats.substr(0, formats.length() - 2);
103 if (!
IsHex(strReq) || (strReq.size() != 64))
111 std::string statusmessage;
118 const std::string &strURIPart) {
119 if (!CheckWarmup(req))
122 std::vector<std::string> params;
123 const RetFormat rf = ParseDataFormat(params, strURIPart);
124 std::vector<std::string> path;
125 boost::split(path, params[0], 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(), NULL, 10);
130 if (count < 1 || count > 2000)
131 return RESTERR(req,
HTTP_BAD_REQUEST,
"Header count out of range: " + path[0]);
132 std::string hashStr = path[1];
137 std::vector<const CBlockIndex *> headers;
138 headers.reserve(count);
145 headers.push_back(pindex);
146 if (headers.size() == (
unsigned long) count)
159 std::string binaryHeader = ssHeader.str();
160 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
166 std::string strHex =
HexStr(ssHeader.begin(), ssHeader.end()) +
"\n";
176 std::string strJSON = jsonHeaders.write() +
"\n";
177 req->
WriteHeader(
"Content-Type",
"application/json");
182 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: .bin, .hex)");
191 const std::string &strURIPart,
192 bool showTxDetails) {
193 if (!CheckWarmup(req))
195 std::vector<std::string> params;
196 const RetFormat rf = ParseDataFormat(params, strURIPart);
198 std::string hashStr = params[0];
212 return RESTERR(req,
HTTP_NOT_FOUND, hashStr +
" not available (pruned data)");
223 std::string binaryBlock = ssBlock.str();
224 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
230 std::string strHex =
HexStr(ssBlock.begin(), ssBlock.end()) +
"\n";
238 std::string strJSON = objTx.write() +
"\n";
239 req->
WriteHeader(
"Content-Type",
"application/json");
246 "output format not found (available: " + AvailableDataFormatsString() +
")");
254 static bool rest_block_extended(
HTTPRequest *req,
const std::string &strURIPart) {
255 return rest_block(req, strURIPart,
true);
258 static bool rest_block_notxdetails(
HTTPRequest *req,
const std::string &strURIPart) {
259 return rest_block(req, strURIPart,
false);
262 static bool rest_chaininfo(
HTTPRequest *req,
const std::string &strURIPart) {
263 if (!CheckWarmup(req))
265 std::vector<std::string> params;
266 const RetFormat rf = ParseDataFormat(params, strURIPart);
272 std::string strJSON = chainInfoObject.
write() +
"\n";
273 req->
WriteHeader(
"Content-Type",
"application/json");
278 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
286 static bool rest_mempool_info(
HTTPRequest *req,
const std::string &strURIPart) {
287 if (!CheckWarmup(req))
289 std::vector<std::string> params;
290 const RetFormat rf = ParseDataFormat(params, strURIPart);
296 std::string strJSON = mempoolInfoObject.
write() +
"\n";
297 req->
WriteHeader(
"Content-Type",
"application/json");
302 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
310 static bool rest_mempool_contents(
HTTPRequest *req,
const std::string &strURIPart) {
311 if (!CheckWarmup(req))
313 std::vector<std::string> params;
314 const RetFormat rf = ParseDataFormat(params, strURIPart);
320 std::string strJSON = mempoolObject.
write() +
"\n";
321 req->
WriteHeader(
"Content-Type",
"application/json");
326 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: json)");
334 static bool rest_tx(
HTTPRequest *req,
const std::string &strURIPart) {
335 if (!CheckWarmup(req))
337 std::vector<std::string> params;
338 const RetFormat rf = ParseDataFormat(params, strURIPart);
340 std::string hashStr = params[0];
355 std::string binaryTx = ssTx.str();
356 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
362 std::string strHex =
HexStr(ssTx.begin(), ssTx.end()) +
"\n";
371 std::string strJSON = objTx.write() +
"\n";
372 req->
WriteHeader(
"Content-Type",
"application/json");
379 "output format not found (available: " + AvailableDataFormatsString() +
")");
388 static bool rest_getutxos(
HTTPRequest *req,
const std::string &strURIPart) {
389 if (!CheckWarmup(req))
391 std::vector<std::string> params;
392 enum RetFormat rf = ParseDataFormat(params, strURIPart);
394 std::vector<std::string> uriParts;
395 if (params.size() > 0 && params[0].length() > 1) {
396 std::string strUriParams = params[0].substr(1);
397 boost::split(uriParts, strUriParams, boost::is_any_of(
"/"));
401 std::string strRequestMutable = req->
ReadBody();
402 if (strRequestMutable.length() == 0 && uriParts.size() == 0)
405 bool fInputParsed =
false;
406 bool fCheckMemPool =
false;
407 std::vector<COutPoint> vOutPoints;
412 if (uriParts.size() > 0) {
415 if (uriParts.size() > 0 && uriParts[0] ==
"checkmempool")
416 fCheckMemPool =
true;
418 for (
size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
422 std::string strTxid = uriParts[i].substr(0, uriParts[i].find(
"-"));
423 std::string strOutput = uriParts[i].substr(uriParts[i].find(
"-") + 1);
429 vOutPoints.push_back(
COutPoint(txid, (uint32_t) nOutput));
432 if (vOutPoints.size() > 0)
441 std::vector<unsigned char> strRequestV =
ParseHex(strRequestMutable);
442 strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
448 if (strRequestMutable.size() > 0) {
451 "Combination of URI scheme inputs and raw post data is not allowed");
454 oss << strRequestMutable;
455 oss >> fCheckMemPool;
458 }
catch (
const std::ios_base::failure& e) {
473 "output format not found (available: " + AvailableDataFormatsString() +
")");
478 if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
480 strprintf(
"Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS,
485 std::vector<unsigned char> bitmap;
486 std::vector<CCoin> outs;
487 std::string bitmapStringRepresentation;
488 boost::dynamic_bitset<unsigned char> hits(vOutPoints.size());
499 view.SetBackend(viewMempool);
501 for (
size_t i = 0; i < vOutPoints.size(); i++) {
503 uint256 hash = vOutPoints[i].hash;
504 if (view.GetCoins(hash, coins)) {
514 coin.
out = coins.
vout.at(vOutPoints[i].n);
516 outs.push_back(coin);
520 bitmapStringRepresentation.append(
521 hits[i] ?
"1" :
"0");
524 boost::to_block_range(hits, std::back_inserter(bitmap));
531 std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
533 req->
WriteHeader(
"Content-Type",
"application/octet-stream");
541 std::string strHex =
HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) +
"\n";
555 objGetUTXOResponse.push_back(Pair(
"bitmap", bitmapStringRepresentation));
558 for (
const CCoin &coin : outs) {
560 utxo.push_back(Pair(
"txvers", (int32_t) coin.nTxVer));
561 utxo.push_back(Pair(
"height", (int32_t) coin.nHeight));
567 utxo.push_back(Pair(
"scriptPubKey", o));
568 utxos.push_back(utxo);
570 objGetUTXOResponse.push_back(Pair(
"utxos", utxos));
573 std::string strJSON = objGetUTXOResponse.write() +
"\n";
574 req->
WriteHeader(
"Content-Type",
"application/json");
579 return RESTERR(req,
HTTP_NOT_FOUND,
"output format not found (available: " + AvailableDataFormatsString() +
")");
587 static const struct {
591 {
"/rest/tx/", rest_tx},
592 {
"/rest/block/notxdetails/", rest_block_notxdetails},
593 {
"/rest/block/", rest_block_extended},
594 {
"/rest/chaininfo", rest_chaininfo},
595 {
"/rest/mempool/info", rest_mempool_info},
596 {
"/rest/mempool/contents", rest_mempool_contents},
597 {
"/rest/headers/", rest_headers},
598 {
"/rest/getutxos", rest_getutxos},
603 for (
unsigned int i = 0; i <
ARRAYLEN(uri_prefixes); i++)
613 for (
unsigned int i = 0; i <
ARRAYLEN(uri_prefixes); i++)