Skip to content

Commit

Permalink
Merge pull request #6013
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Garzik committed Aug 15, 2015
2 parents ddd8d80 + 70180b2 commit 6feeec1
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 44 deletions.
14 changes: 14 additions & 0 deletions doc/REST-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ $ curl localhost:18332/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff76
}
```

####Memory pool
`GET /rest/mempool/info.json`

Returns various information about the TX mempool.
Only supports JSON as output format.
* size : (numeric) the number of transactions in the TX mempool
* bytes : (numeric) size of the TX mempool in bytes
* usage : (numeric) total TX mempool memory usage

`GET /rest/mempool/contents.json`

Returns transactions in the TX mempool.
Only supports JSON as output format.

Risks
-------------
Running a web browser on the same node with a REST enabled bitcoind can be a risk. Accessing prepared XSS websites could read out tx/block data of your node by placing links like `<script src="http://127.0.0.1:8332/rest/tx/1234567890.json">` which might break the nodes privacy.
13 changes: 13 additions & 0 deletions qa/rpc-tests/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,19 @@ def run_test(self):
txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11))
self.sync_all()

# check that there are exactly 3 transactions in the TX memory pool before generating the block
json_string = http_get_call(url.hostname, url.port, '/rest/mempool/info'+self.FORMAT_SEPARATOR+'json')
json_obj = json.loads(json_string)
assert_equal(json_obj['size'], 3)
# the size of the memory pool should be greater than 3x ~100 bytes
assert_greater_than(json_obj['bytes'], 300)

# check that there are our submitted transactions in the TX memory pool
json_string = http_get_call(url.hostname, url.port, '/rest/mempool/contents'+self.FORMAT_SEPARATOR+'json')
json_obj = json.loads(json_string)
for tx in txs:
assert_equal(tx in json_obj, True)

# now mine the transactions
newblockhash = self.nodes[1].generate(1)
self.sync_all()
Expand Down
56 changes: 56 additions & 0 deletions src/rest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class RestErr

extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
extern UniValue mempoolInfoToJSON();
extern UniValue mempoolToJSON(bool fVerbose = false);
extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
extern UniValue blockheaderToJSON(const CBlockIndex* blockindex);

Expand Down Expand Up @@ -293,6 +295,58 @@ static bool rest_chaininfo(AcceptedConnection* conn,
return true; // continue to process further HTTP reqs on this cxn
}

static bool rest_mempool_info(AcceptedConnection* conn,
const std::string& strURIPart,
const std::string& strRequest,
const std::map<std::string, std::string>& mapHeaders,
bool fRun)
{
vector<string> params;
const RetFormat rf = ParseDataFormat(params, strURIPart);

switch (rf) {
case RF_JSON: {
UniValue mempoolInfoObject = mempoolInfoToJSON();

string strJSON = mempoolInfoObject.write() + "\n";
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true;
}
default: {
throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: json)");
}
}

// not reached
return true; // continue to process further HTTP reqs on this cxn
}

static bool rest_mempool_contents(AcceptedConnection* conn,
const std::string& strURIPart,
const std::string& strRequest,
const std::map<std::string, std::string>& mapHeaders,
bool fRun)
{
vector<string> params;
const RetFormat rf = ParseDataFormat(params, strURIPart);

switch (rf) {
case RF_JSON: {
UniValue mempoolObject = mempoolToJSON(true);

string strJSON = mempoolObject.write() + "\n";
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true;
}
default: {
throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: json)");
}
}

// not reached
return true; // continue to process further HTTP reqs on this cxn
}

static bool rest_tx(AcceptedConnection* conn,
const std::string& strURIPart,
const std::string& strRequest,
Expand Down Expand Up @@ -553,6 +607,8 @@ static const struct {
{"/rest/block/notxdetails/", rest_block_notxdetails},
{"/rest/block/", rest_block_extended},
{"/rest/chaininfo", rest_chaininfo},
{"/rest/mempool/info", rest_mempool_info},
{"/rest/mempool/contents", rest_mempool_contents},
{"/rest/headers/", rest_headers},
{"/rest/getutxos", rest_getutxos},
};
Expand Down
97 changes: 53 additions & 44 deletions src/rpcblockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,45 +175,8 @@ UniValue getdifficulty(const UniValue& params, bool fHelp)
return GetDifficulty();
}


UniValue getrawmempool(const UniValue& params, bool fHelp)
UniValue mempoolToJSON(bool fVerbose = false)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"getrawmempool ( verbose )\n"
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
"\nArguments:\n"
"1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
"\nResult: (for verbose = false):\n"
"[ (json array of string)\n"
" \"transactionid\" (string) The transaction id\n"
" ,...\n"
"]\n"
"\nResult: (for verbose = true):\n"
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
" \"size\" : n, (numeric) transaction size in bytes\n"
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n"
" \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
" \"currentpriority\" : n, (numeric) transaction priority now\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ]\n"
" }, ...\n"
"}\n"
"\nExamples\n"
+ HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
);

LOCK(cs_main);

bool fVerbose = false;
if (params.size() > 0)
fVerbose = params[0].get_bool();

if (fVerbose)
{
LOCK(mempool.cs);
Expand Down Expand Up @@ -261,6 +224,47 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
}
}

UniValue getrawmempool(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"getrawmempool ( verbose )\n"
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
"\nArguments:\n"
"1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
"\nResult: (for verbose = false):\n"
"[ (json array of string)\n"
" \"transactionid\" (string) The transaction id\n"
" ,...\n"
"]\n"
"\nResult: (for verbose = true):\n"
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
" \"size\" : n, (numeric) transaction size in bytes\n"
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n"
" \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
" \"currentpriority\" : n, (numeric) transaction priority now\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ]\n"
" }, ...\n"
"}\n"
"\nExamples\n"
+ HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
);

LOCK(cs_main);

bool fVerbose = false;
if (params.size() > 0)
fVerbose = params[0].get_bool();

return mempoolToJSON(fVerbose);
}

UniValue getblockhash(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
Expand Down Expand Up @@ -757,6 +761,16 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
return res;
}

UniValue mempoolInfoToJSON()
{
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("size", (int64_t) mempool.size()));
ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage()));

return ret;
}

UniValue getmempoolinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
Expand All @@ -774,12 +788,7 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getmempoolinfo", "")
);

UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("size", (int64_t) mempool.size()));
ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage()));

return ret;
return mempoolInfoToJSON();
}

UniValue invalidateblock(const UniValue& params, bool fHelp)
Expand Down

0 comments on commit 6feeec1

Please sign in to comment.