Merge pull request 'z_getstats RPC' (#321) from z_getstats into dev
Reviewed-on: https://git.hush.is/hush/hush3/pulls/321
This commit is contained in:
@@ -3636,6 +3636,224 @@ UniValue z_listsentbyaddress(const UniValue& params, bool fHelp,const CPubKey&)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue z_getstats(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return NullUniValue;
|
||||||
|
|
||||||
|
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_getstats\n"
|
||||||
|
"\nReturns statistics about ztxs in block height or block height range\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"height\" (number, required) The block height\n"
|
||||||
|
"1. \"end_height\" (number, optional) The ending block height\n"
|
||||||
|
"\nResult:\n"
|
||||||
|
"\njson\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_getstats 123", "456")
|
||||||
|
+ HelpExampleRpc("z_getstats 123", "456")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
std::string strHeight = params[0].get_str();
|
||||||
|
int nHeight = -1;
|
||||||
|
try {
|
||||||
|
nHeight = std::stoi(strHeight);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nHeight < 0 || nHeight > chainActive.Height()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||||
|
}
|
||||||
|
auto strHash = chainActive[nHeight]->GetBlockHash().GetHex();
|
||||||
|
uint256 hash(uint256S(strHash));
|
||||||
|
|
||||||
|
if (mapBlockIndex.count(hash) == 0)
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
|
||||||
|
|
||||||
|
CBlock block;
|
||||||
|
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||||
|
|
||||||
|
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
|
||||||
|
|
||||||
|
if(!ReadBlockFromDisk(block, pblockindex,1))
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
|
||||||
|
|
||||||
|
int total_ztxs = 0, total_zins = 0, total_zouts = 0;
|
||||||
|
int total_ztxs_10_or_more_zins = 0, total_ztxs_10_or_more_zouts = 0;
|
||||||
|
int total_ztxs_25_or_more_zins = 0, total_ztxs_25_or_more_zouts = 0;
|
||||||
|
int total_ztxs_50_or_more_zins = 0, total_ztxs_50_or_more_zouts = 0;
|
||||||
|
int total_ztxs_100_or_more_zins = 0, total_ztxs_100_or_more_zouts = 0;
|
||||||
|
int largest_zins = 0, largest_zouts = 0;
|
||||||
|
std::string largest_zins_txid = "", largest_zouts_txid = "";
|
||||||
|
UniValue ret(UniValue::VOBJ);
|
||||||
|
ret.pushKV("start_height", nHeight);
|
||||||
|
|
||||||
|
// given a single block height, we calculate stats for that height
|
||||||
|
if (params.size() == 1) {
|
||||||
|
BOOST_FOREACH(const CTransaction&tx, block.vtx)
|
||||||
|
{
|
||||||
|
int num_zins, num_zouts = 0;
|
||||||
|
// ignore coinbase txs which have no zins or zouts
|
||||||
|
if(!tx.IsCoinBase()) {
|
||||||
|
num_zouts = tx.vShieldedOutput.size();
|
||||||
|
num_zins = tx.vShieldedSpend.size();
|
||||||
|
// tx must have some zins and zouts to count towards our stats,
|
||||||
|
// which ignores shielding coinbase txs, which have only transparent inputs.
|
||||||
|
// This mostly will only count "z2z" txs but also counts (z,t)=>z and z=>(z,t)
|
||||||
|
// which are possible but unlikely, since RPCs cannot currently create (z,t)=>z txs
|
||||||
|
// and z=>(z,t) are disallowed when ac_private=1
|
||||||
|
if(num_zins > 0 && num_zouts > 0) {
|
||||||
|
total_ztxs++;
|
||||||
|
total_zins += num_zins;
|
||||||
|
total_zouts += num_zouts;
|
||||||
|
if (num_zins > largest_zins) {
|
||||||
|
largest_zins = num_zins;
|
||||||
|
largest_zins_txid = tx.GetHash().ToString();
|
||||||
|
}
|
||||||
|
if (num_zouts > largest_zouts) {
|
||||||
|
largest_zouts = num_zouts;
|
||||||
|
largest_zouts_txid = tx.GetHash().ToString();
|
||||||
|
}
|
||||||
|
if (num_zins >= 10) {
|
||||||
|
total_ztxs_10_or_more_zins++;
|
||||||
|
if (num_zins >= 25) {
|
||||||
|
total_ztxs_25_or_more_zins++;
|
||||||
|
if (num_zins >= 50) {
|
||||||
|
total_ztxs_50_or_more_zins++;
|
||||||
|
if (num_zins >= 100) {
|
||||||
|
total_ztxs_100_or_more_zins++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_zouts >= 10) {
|
||||||
|
total_ztxs_10_or_more_zouts++;
|
||||||
|
if (num_zouts >= 25) {
|
||||||
|
total_ztxs_25_or_more_zouts++;
|
||||||
|
if (num_zouts >= 50) {
|
||||||
|
total_ztxs_50_or_more_zouts++;
|
||||||
|
if (num_zouts >= 100) {
|
||||||
|
total_ztxs_100_or_more_zouts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// given two blocks, we calculate stats for that range
|
||||||
|
std::string strHeight2 = params[1].get_str();
|
||||||
|
int nHeight2 = -1;
|
||||||
|
try {
|
||||||
|
nHeight2 = std::stoi(strHeight2);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid ending block height parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nHeight2 <= nHeight) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Ending block height must be larger than starting height");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nHeight2 < 0 || nHeight2 > chainActive.Height()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Ending block height out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.pushKV("end_height", nHeight2);
|
||||||
|
|
||||||
|
// get the stats for every block in the range
|
||||||
|
for(int currentHeight = nHeight; currentHeight <= nHeight2; currentHeight++) {
|
||||||
|
auto strHash = chainActive[currentHeight]->GetBlockHash().GetHex();
|
||||||
|
uint256 hash(uint256S(strHash));
|
||||||
|
|
||||||
|
if (mapBlockIndex.count(hash) == 0)
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
|
||||||
|
|
||||||
|
CBlock block;
|
||||||
|
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||||
|
|
||||||
|
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
|
||||||
|
|
||||||
|
if(!ReadBlockFromDisk(block, pblockindex,1))
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CTransaction&tx, block.vtx)
|
||||||
|
{
|
||||||
|
int num_zins, num_zouts = 0;
|
||||||
|
// ignore coinbase txs which have no zins or zouts
|
||||||
|
if(!tx.IsCoinBase()) {
|
||||||
|
num_zouts = tx.vShieldedOutput.size();
|
||||||
|
num_zins = tx.vShieldedSpend.size();
|
||||||
|
if(num_zins > 0 && num_zouts > 0) {
|
||||||
|
total_ztxs++;
|
||||||
|
total_zins += num_zins;
|
||||||
|
total_zouts += num_zouts;
|
||||||
|
}
|
||||||
|
if (num_zins > largest_zins) {
|
||||||
|
largest_zins = num_zins;
|
||||||
|
largest_zins_txid = tx.GetHash().ToString();
|
||||||
|
}
|
||||||
|
if (num_zouts > largest_zouts) {
|
||||||
|
largest_zouts = num_zouts;
|
||||||
|
largest_zouts_txid = tx.GetHash().ToString();
|
||||||
|
}
|
||||||
|
if (num_zins >= 10) {
|
||||||
|
total_ztxs_10_or_more_zins++;
|
||||||
|
if (num_zins >= 25) {
|
||||||
|
total_ztxs_25_or_more_zins++;
|
||||||
|
if (num_zins >= 50) {
|
||||||
|
total_ztxs_50_or_more_zins++;
|
||||||
|
if (num_zins >= 100) {
|
||||||
|
total_ztxs_100_or_more_zins++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_zouts >= 10) {
|
||||||
|
total_ztxs_10_or_more_zouts++;
|
||||||
|
if (num_zouts >= 25) {
|
||||||
|
total_ztxs_25_or_more_zouts++;
|
||||||
|
if (num_zouts >= 50) {
|
||||||
|
total_ztxs_50_or_more_zouts++;
|
||||||
|
if (num_zouts >= 100) {
|
||||||
|
total_ztxs_100_or_more_zouts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double avg_zins = total_ztxs > 0 ? (double) total_zins / total_ztxs : 0.0;
|
||||||
|
double avg_zouts = total_ztxs > 0 ? (double) total_zouts / total_ztxs : 0.0;
|
||||||
|
ret.pushKV("total_ztxs", total_ztxs);
|
||||||
|
ret.pushKV("total_zins", total_zins);
|
||||||
|
ret.pushKV("total_zouts", total_zouts);
|
||||||
|
ret.pushKV("total_ztxs_10_or_more_zins", total_ztxs_10_or_more_zins);
|
||||||
|
ret.pushKV("total_ztxs_25_or_more_zins", total_ztxs_25_or_more_zins);
|
||||||
|
ret.pushKV("total_ztxs_50_or_more_zins", total_ztxs_50_or_more_zins);
|
||||||
|
ret.pushKV("total_ztxs_100_or_more_zins", total_ztxs_100_or_more_zins);
|
||||||
|
ret.pushKV("total_ztxs_10_or_more_zouts", total_ztxs_10_or_more_zouts);
|
||||||
|
ret.pushKV("total_ztxs_25_or_more_zouts", total_ztxs_25_or_more_zouts);
|
||||||
|
ret.pushKV("total_ztxs_50_or_more_zouts", total_ztxs_50_or_more_zouts);
|
||||||
|
ret.pushKV("total_ztxs_100_or_more_zouts", total_ztxs_100_or_more_zouts);
|
||||||
|
ret.pushKV("avg_zins", avg_zins);
|
||||||
|
ret.pushKV("avg_zouts", avg_zouts);
|
||||||
|
ret.pushKV("largest_zins", largest_zins);
|
||||||
|
ret.pushKV("largest_zins_txid", largest_zins_txid);
|
||||||
|
ret.pushKV("largest_zouts", largest_zouts);
|
||||||
|
ret.pushKV("largest_zouts_txid", largest_zouts_txid);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue z_anonsetblockdelta(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
UniValue z_anonsetblockdelta(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
{
|
{
|
||||||
if (!EnsureWalletIsAvailable(fHelp))
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
@@ -8489,6 +8707,7 @@ static const CRPCCommand commands[] =
|
|||||||
{ "wallet", "z_listunspent", &z_listunspent, false },
|
{ "wallet", "z_listunspent", &z_listunspent, false },
|
||||||
{ "wallet", "z_getbalance", &z_getbalance, false },
|
{ "wallet", "z_getbalance", &z_getbalance, false },
|
||||||
{ "wallet", "z_getbalances", &z_getbalances, false },
|
{ "wallet", "z_getbalances", &z_getbalances, false },
|
||||||
|
{ "wallet", "z_getstats", &z_getstats, true },
|
||||||
{ "wallet", "z_anonsettxdelta", &z_anonsettxdelta, true },
|
{ "wallet", "z_anonsettxdelta", &z_anonsettxdelta, true },
|
||||||
{ "wallet", "z_anonsetblockdelta", &z_anonsetblockdelta, true },
|
{ "wallet", "z_anonsetblockdelta", &z_anonsetblockdelta, true },
|
||||||
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
|
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
|
||||||
|
|||||||
Reference in New Issue
Block a user