2525#include < iostream>
2626#include < univalue.h>
2727#include < mutex>
28+ #include < numeric>
2829#include < condition_variable>
2930
3031using namespace std ;
@@ -1028,66 +1029,18 @@ UniValue getfeeinfo(const UniValue& params, bool fHelp)
10281029 " \n Examples:\n " +
10291030 HelpExampleCli (" getfeeinfo" , " 5" ) + HelpExampleRpc (" getfeeinfo" , " 5" ));
10301031
1031- LOCK (cs_main);
1032-
10331032 int nBlocks = params[0 ].get_int ();
10341033 int nBestHeight = chainActive.Height ();
10351034 int nStartHeight = nBestHeight - nBlocks;
10361035 if (nBlocks < 0 || nStartHeight <= 0 )
10371036 throw JSONRPCError (RPC_INVALID_PARAMETER, " invalid start height" );
10381037
1039- CAmount nFees = 0 ;
1040- int64_t nBytes = 0 ;
1041- int64_t nTotal = 0 ;
1042- for (int i = nStartHeight; i <= nBestHeight; i++) {
1043- CBlockIndex* pindex = chainActive[i];
1044- CBlock block;
1045- if (!ReadBlockFromDisk (block, pindex))
1046- throw JSONRPCError (RPC_DATABASE_ERROR, " failed to read block from disk" );
1047-
1048- CAmount nValueIn = 0 ;
1049- CAmount nValueOut = 0 ;
1050- for (const CTransaction& tx : block.vtx ) {
1051- if (tx.IsCoinBase () || tx.IsCoinStake ())
1052- continue ;
1053-
1054- for (unsigned int j = 0 ; j < tx.vin .size (); j++) {
1055- if (tx.vin [j].IsZerocoinSpend () || tx.vin [j].IsZerocoinPublicSpend ()) {
1056- nValueIn += tx.vin [j].nSequence * COIN;
1057- continue ;
1058- }
1059-
1060- COutPoint prevout = tx.vin [j].prevout ;
1061- CTransaction txPrev;
1062- uint256 hashBlock;
1063- if (!GetTransaction (prevout.hash , txPrev, hashBlock, true ))
1064- throw JSONRPCError (RPC_DATABASE_ERROR, " failed to read tx from disk" );
1065- nValueIn += txPrev.vout [prevout.n ].nValue ;
1066- }
1067-
1068- for (unsigned int j = 0 ; j < tx.vout .size (); j++) {
1069- nValueOut += tx.vout [j].nValue ;
1070- }
1071-
1072- nFees += nValueIn - nValueOut;
1073- nBytes += tx.GetSerializeSize (SER_NETWORK, CLIENT_VERSION);
1074- nTotal++;
1075- }
1076-
1077- pindex = chainActive.Next (pindex);
1078- if (!pindex)
1079- break ;
1080- }
1081-
1082- UniValue ret (UniValue::VOBJ);
1083- CFeeRate nFeeRate = CFeeRate (nFees, nBytes);
1084- ret.push_back (Pair (" txcount" , (int64_t )nTotal));
1085- ret.push_back (Pair (" txbytes" , (int64_t )nBytes));
1086- ret.push_back (Pair (" ttlfee" , FormatMoney (nFees)));
1087- ret.push_back (Pair (" feeperkb" , FormatMoney (nFeeRate.GetFeePerK ())));
1088- ret.push_back (Pair (" rec_highpriorityfee_perkb" , FormatMoney (nFeeRate.GetFeePerK () + 1000 )));
1038+ UniValue newParams (UniValue::VARR);
1039+ newParams.push_back (UniValue (nStartHeight));
1040+ newParams.push_back (UniValue (nBlocks));
1041+ newParams.push_back (UniValue (true )); // fFeeOnly
10891042
1090- return ret ;
1043+ return getblockindexstats (newParams, false ) ;
10911044}
10921045
10931046UniValue mempoolInfoToJSON ()
@@ -1316,17 +1269,46 @@ UniValue getaccumulatorwitness(const UniValue& params, bool fHelp)
13161269 return obj;
13171270}
13181271
1272+ void validaterange (const UniValue& params, int & heightStart, int & heightEnd, int minHeightStart)
1273+ {
1274+ if (params.size () < 2 ) {
1275+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Not enough parameters in validaterange" );
1276+ }
1277+
1278+ const int nBestHeight = chainActive.Height ();
1279+
1280+ heightStart = params[0 ].get_int ();
1281+ if (heightStart > nBestHeight) {
1282+ throw JSONRPCError (RPC_INVALID_PARAMETER, strprintf (" Invalid starting block (%d). Out of range." , heightStart));
1283+ }
1284+
1285+ const int range = params[1 ].get_int ();
1286+ if (range < 1 ) {
1287+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid block range. Must be strictly positive." );
1288+ }
1289+
1290+ heightEnd = heightStart + range - 1 ;
1291+
1292+ if (heightStart < minHeightStart && heightEnd >= minHeightStart) {
1293+ heightStart = minHeightStart;
1294+ }
1295+
1296+ if (heightEnd > nBestHeight) {
1297+ throw JSONRPCError (RPC_INVALID_PARAMETER, strprintf (" Invalid ending block (%d). Out of range." , heightEnd));
1298+ }
1299+ }
1300+
13191301UniValue getmintsinblocks (const UniValue& params, bool fHelp ) {
13201302 if (fHelp || params.size () != 3 )
13211303 throw runtime_error (
1322- " getmintsinblocks \" height\" \" range\" \" coinDenomination\" \n"
1304+ " getmintsinblocks < height> < range> [ coinDenomination] \n "
13231305 " \n Returns the number of mints of a certain denomination"
13241306 " \n occurred in blocks [height, height+1, height+2, ..., height+range-1]\n "
13251307
13261308 " \n Arguments:\n "
13271309 " 1. height (numeric, required) block height where the search starts.\n "
13281310 " 2. range (numeric, required) number of blocks to include.\n "
1329- " 2 . coinDenomination (numeric, required) coin denomination.\n "
1311+ " 3 . coinDenomination (numeric, required) coin denomination.\n "
13301312
13311313 " \n Result:\n "
13321314 " {\n "
@@ -1339,19 +1321,10 @@ UniValue getmintsinblocks(const UniValue& params, bool fHelp) {
13391321 HelpExampleCli (" getmintsinblocks" , " 1200000 1000 5" ) +
13401322 HelpExampleRpc (" getmintsinblocks" , " 1200000, 1000, 5" ));
13411323
1342- int nBestHeight = chainActive.Height ();
1343-
1344- int heightStart = params[0 ].get_int ();
1345- if (heightStart < Params ().Zerocoin_StartHeight ())
1346- heightStart = Params ().Zerocoin_StartHeight ();
1347-
1348- int range = params[1 ].get_int ();
1349- if (range < 1 )
1350- throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid block range. Must be strictly positive." );
1324+ LOCK (cs_main);
13511325
1352- int heightEnd = heightStart + range - 1 ;
1353- if (heightEnd > nBestHeight)
1354- heightEnd = nBestHeight;
1326+ int heightStart, heightEnd;
1327+ validaterange (params, heightStart, heightEnd, Params ().Zerocoin_StartHeight ());
13551328
13561329 int d = params[2 ].get_int ();
13571330 libzerocoin::CoinDenomination denom = libzerocoin::IntToZerocoinDenomination (d);
@@ -1381,7 +1354,7 @@ UniValue getmintsinblocks(const UniValue& params, bool fHelp) {
13811354UniValue getserials (const UniValue& params, bool fHelp ) {
13821355 if (fHelp || params.size () < 2 || params.size () > 3 )
13831356 throw runtime_error (
1384- " getserials \" hash \" \n"
1357+ " getserials <height> <range> [fVerbose] \n "
13851358 " \n Look the inputs of any tx in a range of blocks and returns the serial numbers for any coinspend.\n "
13861359
13871360 " \n Arguments:\n "
@@ -1395,19 +1368,8 @@ UniValue getserials(const UniValue& params, bool fHelp) {
13951368
13961369 LOCK (cs_main);
13971370
1398- int nBestHeight = chainActive.Height ();
1399-
1400- int heightStart = params[0 ].get_int ();
1401- if (heightStart < Params ().Zerocoin_StartHeight ())
1402- heightStart = Params ().Zerocoin_StartHeight ();
1403-
1404- int range = params[1 ].get_int ();
1405- if (range < 1 )
1406- throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid block range. Must be strictly positive." );
1407-
1408- int heightEnd = heightStart + range - 1 ;
1409- if (heightEnd > nBestHeight)
1410- heightEnd = nBestHeight;
1371+ int heightStart, heightEnd;
1372+ validaterange (params, heightStart, heightEnd, Params ().Zerocoin_StartHeight ());
14111373
14121374 bool fVerbose = false ;
14131375 if (params.size () > 2 ) {
@@ -1496,4 +1458,161 @@ UniValue getserials(const UniValue& params, bool fHelp) {
14961458
14971459}
14981460
1461+ UniValue getblockindexstats (const UniValue& params, bool fHelp ) {
1462+ if (fHelp || params.size () < 2 || params.size () > 3 )
1463+ throw runtime_error (
1464+ " getblockindexstats <height> <range> [fFeeOnly]\n "
1465+ " \n Returns aggregated BlockIndex data for blocks "
1466+ " \n [height, height+1, height+2, ..., height+range-1]\n "
1467+
1468+ " \n Arguments:\n "
1469+ " 1. height (numeric, required) block height where the search starts.\n "
1470+ " 2. range (numeric, required) number of blocks to include.\n "
1471+ " 3. fFeeOnly (boolean, optional, default=False) return only fee info.\n "
1472+
1473+ " \n Result:\n "
1474+ " {\n "
1475+ " \" first_block\" : \" x\" (integer) First counted block\n "
1476+ " \" last_block\" : \" x\" (integer) Last counted block\n "
1477+ " \" txcount\" : xxxxx (numeric) tx count (excluding coinbase/coinstake)\n "
1478+ " \" txcount_tot\" : xxxxx (numeric) tx count (including coinbase/coinstake)\n "
1479+ " \" mintcount\" : { [if fFeeOnly=False]\n "
1480+ " \" denom_1\" : xxxx (numeric) number of mints of denom_1 occurred over the block range\n "
1481+ " \" denom_5\" : xxxx (numeric) number of mints of denom_5 occurred over the block range\n "
1482+ " ... ... number of mints of other denominations: ..., 10, 50, 100, 500, 1000, 5000\n "
1483+ " }\n "
1484+ " \" spendcount\" : { [if fFeeOnly=False]\n "
1485+ " \" denom_1\" : xxxx (numeric) number of spends of denom_1 occurred over the block range\n "
1486+ " \" denom_5\" : xxxx (numeric) number of spends of denom_5 occurred over the block range\n "
1487+ " ... ... number of spends of other denominations: ..., 10, 50, 100, 500, 1000, 5000\n "
1488+ " }\n "
1489+ " \" txbytes\" : xxxxx (numeric) Sum of the size of all txes over block range\n "
1490+ " \" ttlfee\" : xxxxx (numeric) Sum of the fee amount of all txes over block range\n "
1491+ " \" feeperkb\" : xxxxx (numeric) Average fee per kb\n "
1492+ " }\n "
1493+
1494+ " \n Examples:\n " +
1495+ HelpExampleCli (" getblockindexstats" , " 1200000 1000" ) +
1496+ HelpExampleRpc (" getblockindexstats" , " 1200000, 1000" ));
1497+
1498+ LOCK (cs_main);
1499+
1500+ int heightStart, heightEnd;
1501+ validaterange (params, heightStart, heightEnd);
1502+ // return object
1503+ UniValue ret (UniValue::VOBJ);
1504+ ret.push_back (Pair (" Starting block" , heightStart));
1505+ ret.push_back (Pair (" Ending block" , heightEnd));
1506+
1507+ bool fFeeOnly = false ;
1508+ if (params.size () > 2 ) {
1509+ fFeeOnly = params[2 ].get_bool ();
1510+ }
1511+
1512+ CAmount nFees = 0 ;
1513+ int64_t nBytes = 0 ;
1514+ int64_t nTxCount = 0 ;
1515+ int64_t nTxCount_tot = 0 ;
1516+
1517+ std::map<libzerocoin::CoinDenomination, int64_t > mapMintCount;
1518+ std::map<libzerocoin::CoinDenomination, int64_t > mapSpendCount;
1519+ for (auto & denom : libzerocoin::zerocoinDenomList) {
1520+ mapMintCount.insert (make_pair (denom, 0 ));
1521+ mapSpendCount.insert (make_pair (denom, 0 ));
1522+ }
1523+
1524+ CBlockIndex* pindex = chainActive[heightStart];
1525+
1526+ while (true ) {
1527+ CBlock block;
1528+ if (!ReadBlockFromDisk (block, pindex)) {
1529+ throw JSONRPCError (RPC_DATABASE_ERROR, " failed to read block from disk" );
1530+ }
1531+
1532+ CAmount nValueIn = 0 ;
1533+ CAmount nValueOut = 0 ;
1534+ nTxCount_tot += block.vtx .size ();
1535+
1536+ // loop through each tx in block
1537+ for (const CTransaction& tx : block.vtx ) {
1538+ if (tx.IsCoinBase ())
1539+ continue ;
1540+
1541+ if (tx.HasZerocoinSpendInputs ()) {
1542+ for (unsigned int j = 0 ; j < tx.vin .size (); j++) {
1543+ if (tx.vin [j].IsZerocoinSpend () || tx.vin [j].IsZerocoinPublicSpend ()) {
1544+ mapSpendCount[libzerocoin::IntToZerocoinDenomination (tx.vin [j].nSequence )]++;
1545+ }
1546+ }
1547+ }
1548+
1549+ if (tx.IsCoinStake ()) {
1550+ continue ;
1551+ }
1552+
1553+ nTxCount++;
1554+
1555+ // fetch input value from prevouts
1556+ for (unsigned int j = 0 ; j < tx.vin .size (); j++) {
1557+ if (tx.vin [j].IsZerocoinSpend () || tx.vin [j].IsZerocoinPublicSpend ()) {
1558+ nValueIn += tx.vin [j].nSequence * COIN;
1559+ continue ;
1560+ }
1561+
1562+ COutPoint prevout = tx.vin [j].prevout ;
1563+ CTransaction txPrev;
1564+ uint256 hashBlock;
1565+ if (!GetTransaction (prevout.hash , txPrev, hashBlock, true ))
1566+ throw JSONRPCError (RPC_DATABASE_ERROR, " failed to read tx from disk" );
1567+ nValueIn += txPrev.vout [prevout.n ].nValue ;
1568+ }
1569+
1570+ // sum output values in nValueOut
1571+ for (unsigned int j = 0 ; j < tx.vout .size (); j++) {
1572+ nValueOut += tx.vout [j].nValue ;
1573+ }
1574+
1575+ // update sums
1576+ nFees += nValueIn - nValueOut;
1577+ nBytes += tx.GetSerializeSize (SER_NETWORK, CLIENT_VERSION);
1578+ }
1579+
1580+ // add mints to map
1581+ if (!fFeeOnly ) {
1582+ for (auto & denom : libzerocoin::zerocoinDenomList) {
1583+ mapMintCount[denom] += count (pindex->vMintDenominationsInBlock .begin (), pindex->vMintDenominationsInBlock .end (), denom);
1584+ }
1585+ }
1586+
1587+ if (pindex->nHeight < heightEnd) {
1588+ pindex = chainActive.Next (pindex);
1589+ } else {
1590+ break ;
1591+ }
1592+ }
1593+
1594+ // get fee rate
1595+ CFeeRate nFeeRate = CFeeRate (nFees, nBytes);
1596+
1597+ // return UniValue object
1598+ ret.push_back (Pair (" txcount" , (int64_t )nTxCount));
1599+ ret.push_back (Pair (" txcount_tot" , (int64_t )nTxCount_tot));
1600+ if (!fFeeOnly ) {
1601+ UniValue mint_obj (UniValue::VOBJ);
1602+ UniValue spend_obj (UniValue::VOBJ);
1603+ for (auto & denom : libzerocoin::zerocoinDenomList) {
1604+ mint_obj.push_back (Pair (strprintf (" denom_%d" , ZerocoinDenominationToInt (denom)), mapMintCount[denom]));
1605+ spend_obj.push_back (Pair (strprintf (" denom_%d" , ZerocoinDenominationToInt (denom)), mapSpendCount[denom]));
1606+ }
1607+ ret.push_back (Pair (" mintcount" , mint_obj));
1608+ ret.push_back (Pair (" spendcount" , spend_obj));
1609+
1610+ }
1611+ ret.push_back (Pair (" txbytes" , (int64_t )nBytes));
1612+ ret.push_back (Pair (" ttlfee" , FormatMoney (nFees)));
1613+ ret.push_back (Pair (" feeperkb" , FormatMoney (nFeeRate.GetFeePerK ())));
1614+
1615+ return ret;
1616+
1617+ }
14991618
0 commit comments