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
This commit is contained in:
Wladimir J. van der Laan 2017-10-02 15:21:26 +02:00
commit 90926db238
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
2 changed files with 44 additions and 10 deletions

View File

@ -1484,9 +1484,12 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
"2. \"blockhash\" (string, optional) The hash of the block that ends the window.\n" "2. \"blockhash\" (string, optional) The hash of the block that ends the window.\n"
"\nResult:\n" "\nResult:\n"
"{\n" "{\n"
" \"time\": xxxxx, (numeric) The timestamp for the statistics in UNIX format.\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" " \"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" " \"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" "}\n"
"\nExamples:\n" "\nExamples:\n"
+ HelpExampleCli("getchaintxstats", "") + HelpExampleCli("getchaintxstats", "")
@ -1496,10 +1499,6 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
const CBlockIndex* pindex; const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month 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(); bool havehash = !request.params[1].isNull();
uint256 hash; uint256 hash;
if (havehash) { if (havehash) {
@ -1524,8 +1523,14 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
assert(pindex != nullptr); assert(pindex != nullptr);
if (blockcount < 1 || blockcount >= pindex->nHeight) { if (request.params[0].isNull()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 1 and the block's height"); 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); const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->nHeight - blockcount);
@ -1535,7 +1540,14 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ); UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("time", (int64_t)pindex->nTime)); ret.push_back(Pair("time", (int64_t)pindex->nTime));
ret.push_back(Pair("txcount", (int64_t)pindex->nChainTx)); 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; return ret;
} }

View File

@ -81,6 +81,28 @@ class BlockchainTest(BitcoinTestFramework):
# we have to round because of binary math # we have to round because of binary math
assert_equal(round(chaintxstats['txrate'] * 600, 10), Decimal(1)) assert_equal(round(chaintxstats['txrate'] * 600, 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): def _test_gettxoutsetinfo(self):
node = self.nodes[0] node = self.nodes[0]
res = node.gettxoutsetinfo() res = node.gettxoutsetinfo()