Implement REST mempool API, add test and documentation.
This commit is contained in:
@@ -301,6 +301,19 @@ class RESTTest (BitcoinTestFramework):
|
|||||||
txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1))
|
txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1))
|
||||||
self.sync_all()
|
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
|
# now mine the transactions
|
||||||
newblockhash = self.nodes[1].generate(1)
|
newblockhash = self.nodes[1].generate(1)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|||||||
56
src/rest.cpp
56
src/rest.cpp
@@ -64,6 +64,8 @@ public:
|
|||||||
|
|
||||||
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
|
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 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 void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
|
||||||
extern UniValue blockheaderToJSON(const CBlockIndex* blockindex);
|
extern UniValue blockheaderToJSON(const CBlockIndex* blockindex);
|
||||||
|
|
||||||
@@ -292,6 +294,58 @@ static bool rest_chaininfo(AcceptedConnection* conn,
|
|||||||
return true; // continue to process further HTTP reqs on this cxn
|
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,
|
static bool rest_tx(AcceptedConnection* conn,
|
||||||
const std::string& strURIPart,
|
const std::string& strURIPart,
|
||||||
const std::string& strRequest,
|
const std::string& strRequest,
|
||||||
@@ -552,6 +606,8 @@ static const struct {
|
|||||||
{"/rest/block/notxdetails/", rest_block_notxdetails},
|
{"/rest/block/notxdetails/", rest_block_notxdetails},
|
||||||
{"/rest/block/", rest_block_extended},
|
{"/rest/block/", rest_block_extended},
|
||||||
{"/rest/chaininfo", rest_chaininfo},
|
{"/rest/chaininfo", rest_chaininfo},
|
||||||
|
{"/rest/mempool/info", rest_mempool_info},
|
||||||
|
{"/rest/mempool/contents", rest_mempool_contents},
|
||||||
{"/rest/headers/", rest_headers},
|
{"/rest/headers/", rest_headers},
|
||||||
{"/rest/getutxos", rest_getutxos},
|
{"/rest/getutxos", rest_getutxos},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -191,45 +191,8 @@ UniValue getdifficulty(const UniValue& params, bool fHelp)
|
|||||||
return GetNetworkDifficulty();
|
return GetNetworkDifficulty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue mempoolToJSON(bool fVerbose = false)
|
||||||
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 bitcoins\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)
|
if (fVerbose)
|
||||||
{
|
{
|
||||||
LOCK(mempool.cs);
|
LOCK(mempool.cs);
|
||||||
@@ -277,6 +240,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 bitcoins\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)
|
UniValue getblockhash(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() != 1)
|
if (fHelp || params.size() != 1)
|
||||||
@@ -777,6 +781,16 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
|
|||||||
return res;
|
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)
|
UniValue getmempoolinfo(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() != 0)
|
if (fHelp || params.size() != 0)
|
||||||
@@ -794,12 +808,7 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp)
|
|||||||
+ HelpExampleRpc("getmempoolinfo", "")
|
+ HelpExampleRpc("getmempoolinfo", "")
|
||||||
);
|
);
|
||||||
|
|
||||||
UniValue ret(UniValue::VOBJ);
|
return mempoolInfoToJSON();
|
||||||
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 invalidateblock(const UniValue& params, bool fHelp)
|
UniValue invalidateblock(const UniValue& params, bool fHelp)
|
||||||
|
|||||||
Reference in New Issue
Block a user