From 3f76b913f16c8462a0d60ae7b22fdb79b412e054 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 2 Oct 2017 15:21:26 +0200 Subject: [PATCH] Merge #11021: [rpc] fix getchaintxstats() 07704c1 Add some tests for getchaintxstats (Akio Nakamura) 3336676 Fix getchaintxstats() (Akio Nakamura) Pull request description: 1. calculate nblocks more adaptive. -> set default nblocks to min (blocks for 1 month, target block's height - 1) -> before PR: if not specify nblocks-parameter, illegal parameter error will happen when target block height is below nblocks. 2. correct error message. -> nblocks accepts [1 .. block's height -1] . so add a word "-1". 3. add check 0-divide. -> if nTimeDiff = 0 then use UniValue(UniValue::VNULL) and returns {... "txrate": null} . -> before PR: if nTimeDiff = 0 then returns {... "txrate":} and bitcoin-cli cannot handle the response. Tree-SHA512: e1962ce7bb05a5bc7dec03eb04a8e7578f50fdb68927fcfc0a2232905ef4d679293eee148ebe0866682d209a8c458d21fbe71715e7311adb81f37089aae1ed93 --- src/rpc/blockchain.cpp | 32 ++++++++++++++++++++++---------- test/functional/blockchain.py | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 28c52c44a937a3..79bc322379a5bb 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1782,9 +1782,12 @@ UniValue getchaintxstats(const JSONRPCRequest& request) "2. \"blockhash\" (string, optional) The hash of the block that ends the window.\n" "\nResult:\n" "{\n" - " \"time\": xxxxx, (numeric) The timestamp for the statistics in UNIX format.\n" - " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n" - " \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window.\n" + " \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n" + " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n" + " \"window_block_count\": xxxxx, (numeric) Size of the window in number of blocks.\n" + " \"window_tx_count\": xxxxx, (numeric) The number of transactions in the window. Only returned if \"window_block_count\" is > 0.\n" + " \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n" + " \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n" "}\n" "\nExamples:\n" + HelpExampleCli("getchaintxstats", "") @@ -1794,10 +1797,6 @@ UniValue getchaintxstats(const JSONRPCRequest& request) const CBlockIndex* pindex; int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month - if (!request.params[0].isNull()) { - blockcount = request.params[0].get_int(); - } - bool havehash = !request.params[1].isNull(); uint256 hash; if (havehash) { @@ -1822,8 +1821,14 @@ UniValue getchaintxstats(const JSONRPCRequest& request) assert(pindex != nullptr); - if (blockcount < 1 || blockcount >= pindex->nHeight) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 1 and the block's height"); + if (request.params[0].isNull()) { + blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1)); + } else { + blockcount = request.params[0].get_int(); + + if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1"); + } } const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->nHeight - blockcount); @@ -1833,7 +1838,14 @@ UniValue getchaintxstats(const JSONRPCRequest& request) UniValue ret(UniValue::VOBJ); ret.push_back(Pair("time", (int64_t)pindex->nTime)); ret.push_back(Pair("txcount", (int64_t)pindex->nChainTx)); - ret.push_back(Pair("txrate", ((double)nTxDiff) / nTimeDiff)); + ret.push_back(Pair("window_block_count", blockcount)); + if (blockcount > 0) { + ret.push_back(Pair("window_tx_count", nTxDiff)); + ret.push_back(Pair("window_interval", nTimeDiff)); + if (nTimeDiff > 0) { + ret.push_back(Pair("txrate", ((double)nTxDiff) / nTimeDiff)); + } + } return ret; } diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index 8b504b4e328ee5..ad6b6cb47d78bf 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -81,6 +81,28 @@ def _test_getchaintxstats(self): # we have to round because of binary math assert_equal(round(chaintxstats['txrate'] * 156, 10), Decimal(1)) + b1 = self.nodes[0].getblock(self.nodes[0].getblockhash(1)) + b200 = self.nodes[0].getblock(self.nodes[0].getblockhash(200)) + time_diff = b200['mediantime'] - b1['mediantime'] + + chaintxstats = self.nodes[0].getchaintxstats() + assert_equal(chaintxstats['time'], b200['time']) + assert_equal(chaintxstats['txcount'], 201) + assert_equal(chaintxstats['window_block_count'], 199) + assert_equal(chaintxstats['window_tx_count'], 199) + assert_equal(chaintxstats['window_interval'], time_diff) + assert_equal(round(chaintxstats['txrate'] * time_diff, 10), Decimal(199)) + + chaintxstats = self.nodes[0].getchaintxstats(blockhash=b1['hash']) + assert_equal(chaintxstats['time'], b1['time']) + assert_equal(chaintxstats['txcount'], 2) + assert_equal(chaintxstats['window_block_count'], 0) + assert('window_tx_count' not in chaintxstats) + assert('window_interval' not in chaintxstats) + assert('txrate' not in chaintxstats) + + assert_raises_jsonrpc(-8, "Invalid block count: should be between 0 and the block's height - 1", self.nodes[0].getchaintxstats, 201) + def _test_gettxoutsetinfo(self): node = self.nodes[0] res = node.gettxoutsetinfo()