LCOV - code coverage report
Current view: top level - src - rest.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 219 266 82.3 %
Date: 2015-10-12 22:39:14 Functions: 18 25 72.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "chain.h"
       7             : #include "primitives/block.h"
       8             : #include "primitives/transaction.h"
       9             : #include "main.h"
      10             : #include "httpserver.h"
      11             : #include "rpcserver.h"
      12             : #include "streams.h"
      13             : #include "sync.h"
      14             : #include "txmempool.h"
      15             : #include "utilstrencodings.h"
      16             : #include "version.h"
      17             : 
      18             : #include <boost/algorithm/string.hpp>
      19             : #include <boost/dynamic_bitset.hpp>
      20             : 
      21             : #include <univalue.h>
      22             : 
      23             : using namespace std;
      24             : 
      25             : static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
      26             : 
      27             : enum RetFormat {
      28             :     RF_UNDEF,
      29             :     RF_BINARY,
      30             :     RF_HEX,
      31             :     RF_JSON,
      32             : };
      33             : 
      34             : static const struct {
      35             :     enum RetFormat rf;
      36             :     const char* name;
      37             : } rf_names[] = {
      38             :       {RF_UNDEF, ""},
      39             :       {RF_BINARY, "bin"},
      40             :       {RF_HEX, "hex"},
      41             :       {RF_JSON, "json"},
      42             : };
      43             : 
      44         155 : struct CCoin {
      45             :     uint32_t nTxVer; // Don't call this nVersion, that name has a special meaning inside IMPLEMENT_SERIALIZE
      46             :     uint32_t nHeight;
      47             :     CTxOut out;
      48             : 
      49           0 :     ADD_SERIALIZE_METHODS;
      50             : 
      51             :     template <typename Stream, typename Operation>
      52           0 :     inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
      53             :     {
      54           0 :         READWRITE(nTxVer);
      55           0 :         READWRITE(nHeight);
      56           0 :         READWRITE(out);
      57           0 :     }
      58             : };
      59             : 
      60             : extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
      61             : extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
      62             : extern UniValue mempoolInfoToJSON();
      63             : extern UniValue mempoolToJSON(bool fVerbose = false);
      64             : extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
      65             : extern UniValue blockheaderToJSON(const CBlockIndex* blockindex);
      66             : 
      67           4 : static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, string message)
      68             : {
      69          20 :     req->WriteHeader("Content-Type", "text/plain");
      70           8 :     req->WriteReply(status, message + "\r\n");
      71           4 :     return false;
      72             : }
      73             : 
      74          27 : static enum RetFormat ParseDataFormat(std::string& param, const std::string& strReq)
      75             : {
      76          27 :     const std::string::size_type pos = strReq.rfind('.');
      77          27 :     if (pos == std::string::npos)
      78             :     {
      79             :         param = strReq;
      80             :         return rf_names[0].rf;
      81             :     }
      82             : 
      83          54 :     param = strReq.substr(0, pos);
      84          27 :     const std::string suff(strReq, pos + 1);
      85             : 
      86          68 :     for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
      87         190 :         if (suff == rf_names[i].name)
      88          27 :             return rf_names[i].rf;
      89             : 
      90             :     /* If no suffix is found, return original string.  */
      91             :     param = strReq;
      92             :     return rf_names[0].rf;
      93             : }
      94             : 
      95           0 : static string AvailableDataFormatsString()
      96             : {
      97           0 :     string formats = "";
      98           0 :     for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
      99           0 :         if (strlen(rf_names[i].name) > 0) {
     100           0 :             formats.append(".");
     101           0 :             formats.append(rf_names[i].name);
     102           0 :             formats.append(", ");
     103             :         }
     104             : 
     105           0 :     if (formats.length() > 0)
     106           0 :         return formats.substr(0, formats.length() - 2);
     107             : 
     108           0 :     return formats;
     109             : }
     110             : 
     111          13 : static bool ParseHashStr(const string& strReq, uint256& v)
     112             : {
     113          26 :     if (!IsHex(strReq) || (strReq.size() != 64))
     114             :         return false;
     115             : 
     116          13 :     v.SetHex(strReq);
     117          13 :     return true;
     118             : }
     119             : 
     120          27 : static bool CheckWarmup(HTTPRequest* req)
     121             : {
     122             :     std::string statusmessage;
     123          27 :     if (RPCIsInWarmup(&statusmessage))
     124           0 :          return RESTERR(req, HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: " + statusmessage);
     125             :     return true;
     126             : }
     127             : 
     128           4 : static bool rest_headers(HTTPRequest* req,
     129             :                          const std::string& strURIPart)
     130             : {
     131           4 :     if (!CheckWarmup(req))
     132             :         return false;
     133             :     std::string param;
     134           4 :     const RetFormat rf = ParseDataFormat(param, strURIPart);
     135           4 :     vector<string> path;
     136           4 :     boost::split(path, param, boost::is_any_of("/"));
     137             : 
     138           8 :     if (path.size() != 2)
     139           0 :         return RESTERR(req, HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
     140             : 
     141           8 :     long count = strtol(path[0].c_str(), NULL, 10);
     142           4 :     if (count < 1 || count > 2000)
     143           0 :         return RESTERR(req, HTTP_BAD_REQUEST, "Header count out of range: " + path[0]);
     144             : 
     145           8 :     string hashStr = path[1];
     146             :     uint256 hash;
     147           4 :     if (!ParseHashStr(hashStr, hash))
     148           0 :         return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
     149             : 
     150             :     std::vector<const CBlockIndex *> headers;
     151           4 :     headers.reserve(count);
     152             :     {
     153           4 :         LOCK(cs_main);
     154           4 :         BlockMap::const_iterator it = mapBlockIndex.find(hash);
     155           8 :         const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : NULL;
     156          20 :         while (pindex != NULL && chainActive.Contains(pindex)) {
     157           8 :             headers.push_back(pindex);
     158          16 :             if (headers.size() == (unsigned long)count)
     159             :                 break;
     160           4 :             pindex = chainActive.Next(pindex);
     161             :         }
     162             :     }
     163             : 
     164             :     CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);
     165          64 :     BOOST_FOREACH(const CBlockIndex *pindex, headers) {
     166          16 :         ssHeader << pindex->GetBlockHeader();
     167             :     }
     168             : 
     169           4 :     switch (rf) {
     170             :     case RF_BINARY: {
     171           1 :         string binaryHeader = ssHeader.str();
     172           5 :         req->WriteHeader("Content-Type", "application/octet-stream");
     173           1 :         req->WriteReply(HTTP_OK, binaryHeader);
     174           1 :         return true;
     175             :     }
     176             : 
     177             :     case RF_HEX: {
     178           2 :         string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n";
     179           5 :         req->WriteHeader("Content-Type", "text/plain");
     180           1 :         req->WriteReply(HTTP_OK, strHex);
     181           1 :         return true;
     182             :     }
     183             :     case RF_JSON: {
     184           6 :         UniValue jsonHeaders(UniValue::VARR);
     185          42 :         BOOST_FOREACH(const CBlockIndex *pindex, headers) {
     186           6 :             jsonHeaders.push_back(blockheaderToJSON(pindex));
     187             :         }
     188           4 :         string strJSON = jsonHeaders.write() + "\n";
     189          10 :         req->WriteHeader("Content-Type", "application/json");
     190           2 :         req->WriteReply(HTTP_OK, strJSON);
     191           4 :         return true;
     192             :     }
     193             :     default: {
     194           0 :         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)");
     195             :     }
     196             :     }
     197             : 
     198             :     // not reached
     199             :     return true; // continue to process further HTTP reqs on this cxn
     200             : }
     201             : 
     202           5 : static bool rest_block(HTTPRequest* req,
     203             :                        const std::string& strURIPart,
     204             :                        bool showTxDetails)
     205             : {
     206           5 :     if (!CheckWarmup(req))
     207             :         return false;
     208             :     std::string hashStr;
     209           5 :     const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
     210             : 
     211             :     uint256 hash;
     212           5 :     if (!ParseHashStr(hashStr, hash))
     213           0 :         return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
     214             : 
     215           5 :     CBlock block;
     216           5 :     CBlockIndex* pblockindex = NULL;
     217             :     {
     218           5 :         LOCK(cs_main);
     219           5 :         if (mapBlockIndex.count(hash) == 0)
     220           0 :             return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
     221             : 
     222           5 :         pblockindex = mapBlockIndex[hash];
     223           5 :         if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
     224           0 :             return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
     225             : 
     226           5 :         if (!ReadBlockFromDisk(block, pblockindex))
     227           0 :             return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
     228             :     }
     229             : 
     230             :     CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
     231             :     ssBlock << block;
     232             : 
     233           5 :     switch (rf) {
     234             :     case RF_BINARY: {
     235           1 :         string binaryBlock = ssBlock.str();
     236           5 :         req->WriteHeader("Content-Type", "application/octet-stream");
     237           1 :         req->WriteReply(HTTP_OK, binaryBlock);
     238           1 :         return true;
     239             :     }
     240             : 
     241             :     case RF_HEX: {
     242           2 :         string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";
     243           5 :         req->WriteHeader("Content-Type", "text/plain");
     244           1 :         req->WriteReply(HTTP_OK, strHex);
     245           1 :         return true;
     246             :     }
     247             : 
     248             :     case RF_JSON: {
     249           3 :         UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails);
     250           6 :         string strJSON = objBlock.write() + "\n";
     251          15 :         req->WriteHeader("Content-Type", "application/json");
     252           3 :         req->WriteReply(HTTP_OK, strJSON);
     253           6 :         return true;
     254             :     }
     255             : 
     256             :     default: {
     257           0 :         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
     258             :     }
     259             :     }
     260             : 
     261             :     // not reached
     262             :     return true; // continue to process further HTTP reqs on this cxn
     263             : }
     264             : 
     265           4 : static bool rest_block_extended(HTTPRequest* req, const std::string& strURIPart)
     266             : {
     267           4 :     return rest_block(req, strURIPart, true);
     268             : }
     269             : 
     270           1 : static bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPart)
     271             : {
     272           1 :     return rest_block(req, strURIPart, false);
     273             : }
     274             : 
     275           1 : static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
     276             : {
     277           1 :     if (!CheckWarmup(req))
     278             :         return false;
     279             :     std::string param;
     280           1 :     const RetFormat rf = ParseDataFormat(param, strURIPart);
     281             : 
     282           1 :     switch (rf) {
     283             :     case RF_JSON: {
     284           3 :         UniValue rpcParams(UniValue::VARR);
     285           2 :         UniValue chainInfoObject = getblockchaininfo(rpcParams, false);
     286           2 :         string strJSON = chainInfoObject.write() + "\n";
     287           5 :         req->WriteHeader("Content-Type", "application/json");
     288           1 :         req->WriteReply(HTTP_OK, strJSON);
     289           2 :         return true;
     290             :     }
     291             :     default: {
     292           0 :         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
     293             :     }
     294             :     }
     295             : 
     296             :     // not reached
     297             :     return true; // continue to process further HTTP reqs on this cxn
     298             : }
     299             : 
     300           1 : static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
     301             : {
     302           1 :     if (!CheckWarmup(req))
     303             :         return false;
     304             :     std::string param;
     305           1 :     const RetFormat rf = ParseDataFormat(param, strURIPart);
     306             : 
     307           1 :     switch (rf) {
     308             :     case RF_JSON: {
     309           1 :         UniValue mempoolInfoObject = mempoolInfoToJSON();
     310             : 
     311           2 :         string strJSON = mempoolInfoObject.write() + "\n";
     312           5 :         req->WriteHeader("Content-Type", "application/json");
     313           1 :         req->WriteReply(HTTP_OK, strJSON);
     314           2 :         return true;
     315             :     }
     316             :     default: {
     317           0 :         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
     318             :     }
     319             :     }
     320             : 
     321             :     // not reached
     322             :     return true; // continue to process further HTTP reqs on this cxn
     323             : }
     324             : 
     325           1 : static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart)
     326             : {
     327           1 :     if (!CheckWarmup(req))
     328             :         return false;
     329             :     std::string param;
     330           1 :     const RetFormat rf = ParseDataFormat(param, strURIPart);
     331             : 
     332           1 :     switch (rf) {
     333             :     case RF_JSON: {
     334           1 :         UniValue mempoolObject = mempoolToJSON(true);
     335             : 
     336           2 :         string strJSON = mempoolObject.write() + "\n";
     337           5 :         req->WriteHeader("Content-Type", "application/json");
     338           1 :         req->WriteReply(HTTP_OK, strJSON);
     339           2 :         return true;
     340             :     }
     341             :     default: {
     342           0 :         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
     343             :     }
     344             :     }
     345             : 
     346             :     // not reached
     347             :     return true; // continue to process further HTTP reqs on this cxn
     348             : }
     349             : 
     350           4 : static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
     351             : {
     352           4 :     if (!CheckWarmup(req))
     353             :         return false;
     354             :     std::string hashStr;
     355           4 :     const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
     356             : 
     357             :     uint256 hash;
     358           4 :     if (!ParseHashStr(hashStr, hash))
     359           0 :         return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
     360             : 
     361           4 :     CTransaction tx;
     362             :     uint256 hashBlock = uint256();
     363           4 :     if (!GetTransaction(hash, tx, hashBlock, true))
     364           0 :         return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
     365             : 
     366             :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
     367             :     ssTx << tx;
     368             : 
     369           4 :     switch (rf) {
     370             :     case RF_BINARY: {
     371           0 :         string binaryTx = ssTx.str();
     372           0 :         req->WriteHeader("Content-Type", "application/octet-stream");
     373           0 :         req->WriteReply(HTTP_OK, binaryTx);
     374           0 :         return true;
     375             :     }
     376             : 
     377             :     case RF_HEX: {
     378           2 :         string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";
     379           5 :         req->WriteHeader("Content-Type", "text/plain");
     380           1 :         req->WriteReply(HTTP_OK, strHex);
     381           1 :         return true;
     382             :     }
     383             : 
     384             :     case RF_JSON: {
     385           9 :         UniValue objTx(UniValue::VOBJ);
     386           3 :         TxToJSON(tx, hashBlock, objTx);
     387           6 :         string strJSON = objTx.write() + "\n";
     388          15 :         req->WriteHeader("Content-Type", "application/json");
     389           3 :         req->WriteReply(HTTP_OK, strJSON);
     390           6 :         return true;
     391             :     }
     392             : 
     393             :     default: {
     394           0 :         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
     395             :     }
     396             :     }
     397             : 
     398             :     // not reached
     399             :     return true; // continue to process further HTTP reqs on this cxn
     400             : }
     401             : 
     402          11 : static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
     403             : {
     404          11 :     if (!CheckWarmup(req))
     405             :         return false;
     406             :     std::string param;
     407          11 :     const RetFormat rf = ParseDataFormat(param, strURIPart);
     408             : 
     409          11 :     vector<string> uriParts;
     410          11 :     if (param.length() > 1)
     411             :     {
     412           8 :         std::string strUriParams = param.substr(1);
     413           8 :         boost::split(uriParts, strUriParams, boost::is_any_of("/"));
     414             :     }
     415             : 
     416             :     // throw exception in case of a empty request
     417          11 :     std::string strRequestMutable = req->ReadBody();
     418          19 :     if (strRequestMutable.length() == 0 && uriParts.size() == 0)
     419           0 :         return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
     420             : 
     421          11 :     bool fInputParsed = false;
     422          11 :     bool fCheckMemPool = false;
     423             :     vector<COutPoint> vOutPoints;
     424             : 
     425             :     // parse/deserialize input
     426             :     // input-format = output-format, rest/getutxos/bin requires binary input, gives binary output, ...
     427             : 
     428          22 :     if (uriParts.size() > 0)
     429             :     {
     430             : 
     431             :         //inputs is sent over URI scheme (/rest/getutxos/checkmempool/txid1-n/txid2-n/...)
     432          16 :         if (uriParts.size() > 0 && uriParts[0] == "checkmempool")
     433           7 :             fCheckMemPool = true;
     434             : 
     435          98 :         for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
     436             :         {
     437             :             uint256 txid;
     438             :             int32_t nOutput;
     439         123 :             std::string strTxid = uriParts[i].substr(0, uriParts[i].find("-"));
     440         123 :             std::string strOutput = uriParts[i].substr(uriParts[i].find("-")+1);
     441             : 
     442          41 :             if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
     443           0 :                 return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
     444             : 
     445          41 :             txid.SetHex(strTxid);
     446          82 :             vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));
     447             :         }
     448             : 
     449          16 :         if (vOutPoints.size() > 0)
     450             :             fInputParsed = true;
     451             :         else
     452           3 :             return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
     453             :     }
     454             : 
     455          10 :     switch (rf) {
     456             :     case RF_HEX: {
     457             :         // convert hex to bin, continue then with bin part
     458           0 :         std::vector<unsigned char> strRequestV = ParseHex(strRequestMutable);
     459           0 :         strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
     460             :     }
     461             : 
     462             :     case RF_BINARY: {
     463             :         try {
     464             :             //deserialize only if user sent a request
     465           2 :             if (strRequestMutable.size() > 0)
     466             :             {
     467           2 :                 if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
     468           1 :                     return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Combination of URI scheme inputs and raw post data is not allowed");
     469             : 
     470             :                 CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);
     471             :                 oss << strRequestMutable;
     472             :                 oss >> fCheckMemPool;
     473             :                 oss >> vOutPoints;
     474             :             }
     475           1 :         } catch (const std::ios_base::failure& e) {
     476             :             // abort in case of unreadable binary data
     477           3 :             return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
     478             :         }
     479             :         break;
     480             :     }
     481             : 
     482             :     case RF_JSON: {
     483           8 :         if (!fInputParsed)
     484           3 :             return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
     485             :         break;
     486             :     }
     487             :     default: {
     488           0 :         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
     489             :     }
     490             :     }
     491             : 
     492             :     // limit max outpoints
     493          16 :     if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
     494           2 :         return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
     495             : 
     496             :     // check spentness and form a bitmap (as well as a JSON capable human-readble string representation)
     497             :     vector<unsigned char> bitmap;
     498           7 :     vector<CCoin> outs;
     499             :     std::string bitmapStringRepresentation;
     500          21 :     boost::dynamic_bitset<unsigned char> hits(vOutPoints.size());
     501             :     {
     502           7 :         LOCK2(cs_main, mempool.cs);
     503             : 
     504             :         CCoinsView viewDummy;
     505          14 :         CCoinsViewCache view(&viewDummy);
     506             : 
     507           7 :         CCoinsViewCache& viewChain = *pcoinsTip;
     508           7 :         CCoinsViewMemPool viewMempool(&viewChain, mempool);
     509             : 
     510           7 :         if (fCheckMemPool)
     511           6 :             view.SetBackend(viewMempool); // switch cache backend to db+mempool in case user likes to query mempool
     512             : 
     513          51 :         for (size_t i = 0; i < vOutPoints.size(); i++) {
     514          22 :             CCoins coins;
     515          44 :             uint256 hash = vOutPoints[i].hash;
     516          22 :             if (view.GetCoins(hash, coins)) {
     517          18 :                 mempool.pruneSpent(hash, coins);
     518          54 :                 if (coins.IsAvailable(vOutPoints[i].n)) {
     519          36 :                     hits[i] = true;
     520             :                     // Safe to index into vout here because IsAvailable checked if it's off the end of the array, or if
     521             :                     // n is valid but points to an already spent output (IsNull).
     522             :                     CCoin coin;
     523          18 :                     coin.nTxVer = coins.nVersion;
     524          18 :                     coin.nHeight = coins.nHeight;
     525          54 :                     coin.out = coins.vout.at(vOutPoints[i].n);
     526          18 :                     assert(!coin.out.IsNull());
     527          18 :                     outs.push_back(coin);
     528             :                 }
     529             :             }
     530             : 
     531          44 :             bitmapStringRepresentation.append(hits[i] ? "1" : "0"); // form a binary string representation (human-readable for json output)
     532             :         }
     533             :     }
     534           7 :     boost::to_block_range(hits, std::back_inserter(bitmap));
     535             : 
     536           7 :     switch (rf) {
     537             :     case RF_BINARY: {
     538             :         // serialize data
     539             :         // use exact same output as mentioned in Bip64
     540             :         CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
     541           6 :         ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs;
     542           1 :         string ssGetUTXOResponseString = ssGetUTXOResponse.str();
     543             : 
     544           5 :         req->WriteHeader("Content-Type", "application/octet-stream");
     545           1 :         req->WriteReply(HTTP_OK, ssGetUTXOResponseString);
     546           1 :         return true;
     547             :     }
     548             : 
     549             :     case RF_HEX: {
     550             :         CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
     551           0 :         ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs;
     552           0 :         string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n";
     553             : 
     554           0 :         req->WriteHeader("Content-Type", "text/plain");
     555           0 :         req->WriteReply(HTTP_OK, strHex);
     556           0 :         return true;
     557             :     }
     558             : 
     559             :     case RF_JSON: {
     560          18 :         UniValue objGetUTXOResponse(UniValue::VOBJ);
     561             : 
     562             :         // pack in some essentials
     563             :         // use more or less the same output as mentioned in Bip64
     564          12 :         objGetUTXOResponse.push_back(Pair("chainHeight", chainActive.Height()));
     565          24 :         objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex()));
     566          18 :         objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation));
     567             : 
     568          24 :         UniValue utxos(UniValue::VARR);
     569         126 :         BOOST_FOREACH (const CCoin& coin, outs) {
     570          54 :             UniValue utxo(UniValue::VOBJ);
     571          36 :             utxo.push_back(Pair("txvers", (int32_t)coin.nTxVer));
     572          36 :             utxo.push_back(Pair("height", (int32_t)coin.nHeight));
     573          36 :             utxo.push_back(Pair("value", ValueFromAmount(coin.out.nValue)));
     574             : 
     575             :             // include the script in a json output
     576          72 :             UniValue o(UniValue::VOBJ);
     577          18 :             ScriptPubKeyToJSON(coin.out.scriptPubKey, o, true);
     578          36 :             utxo.push_back(Pair("scriptPubKey", o));
     579          18 :             utxos.push_back(utxo);
     580          18 :         }
     581          12 :         objGetUTXOResponse.push_back(Pair("utxos", utxos));
     582             : 
     583             :         // return json string
     584          12 :         string strJSON = objGetUTXOResponse.write() + "\n";
     585          30 :         req->WriteHeader("Content-Type", "application/json");
     586           6 :         req->WriteReply(HTTP_OK, strJSON);
     587          12 :         return true;
     588             :     }
     589             :     default: {
     590           0 :         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
     591             :     }
     592             :     }
     593             : 
     594             :     // not reached
     595             :     return true; // continue to process further HTTP reqs on this cxn
     596             : }
     597             : 
     598             : static const struct {
     599             :     const char* prefix;
     600             :     bool (*handler)(HTTPRequest* req, const std::string& strReq);
     601             : } uri_prefixes[] = {
     602             :       {"/rest/tx/", rest_tx},
     603             :       {"/rest/block/notxdetails/", rest_block_notxdetails},
     604             :       {"/rest/block/", rest_block_extended},
     605             :       {"/rest/chaininfo", rest_chaininfo},
     606             :       {"/rest/mempool/info", rest_mempool_info},
     607             :       {"/rest/mempool/contents", rest_mempool_contents},
     608             :       {"/rest/headers/", rest_headers},
     609             :       {"/rest/getutxos", rest_getutxos},
     610             : };
     611             : 
     612          89 : bool StartREST()
     613             : {
     614         801 :     for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++)
     615        3560 :         RegisterHTTPHandler(uri_prefixes[i].prefix, false, uri_prefixes[i].handler);
     616          89 :     return true;
     617             : }
     618             : 
     619          94 : void InterruptREST()
     620             : {
     621          94 : }
     622             : 
     623          94 : void StopREST()
     624             : {
     625         846 :     for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++)
     626        2256 :         UnregisterHTTPHandler(uri_prefixes[i].prefix, false);
     627         379 : }

Generated by: LCOV version 1.11