aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Janík <Pavel@Janik.cz>2015-08-06 19:38:19 +0200
committerPavel Janík <Pavel@Janik.cz>2015-08-14 07:01:03 +0200
commit70180b2e576ebcb675c905ef4bd9d5b4fd378b6c (patch)
treed4c055ad001d5d127f7b7bd6b19a5c920682e5c8
parenta4fe57da6207c1e5691a1e843d22db571f3f0186 (diff)
Implement REST mempool API, add test and documentation.
-rw-r--r--doc/REST-interface.md14
-rwxr-xr-xqa/rpc-tests/rest.py13
-rw-r--r--src/rest.cpp56
-rw-r--r--src/rpcblockchain.cpp97
4 files changed, 136 insertions, 44 deletions
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index ac7cd45f70..bf669235e3 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -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.
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index b0cde7268e..2da5219507 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -292,6 +292,19 @@ class RESTTest (BitcoinTestFramework):
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()
diff --git a/src/rest.cpp b/src/rest.cpp
index 0dd238b683..74d27e73bb 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -65,6 +65,8 @@ public:
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);
@@ -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,
@@ -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},
};
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 80d49490d2..e6751de96b 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -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);
@@ -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)
@@ -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)
@@ -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)