@ -3636,6 +3636,224 @@ UniValue z_listsentbyaddress(const UniValue& params, bool fHelp,const CPubKey&)
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 "
" \n Returns statistics about ztxs in block height or block height range \n "
" \n Arguments: \n "
" 1. \" height \" (number, required) The block height \n "
" 1. \" end_height \" (number, optional) The ending block height \n "
" \n Result: \n "
" \n json \n "
" \n Examples: \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 )
{
if ( ! EnsureWalletIsAvailable ( fHelp ) )
@ -8489,6 +8707,7 @@ static const CRPCCommand commands[] =
{ " wallet " , " z_listunspent " , & z_listunspent , false } ,
{ " wallet " , " z_getbalance " , & z_getbalance , false } ,
{ " wallet " , " z_getbalances " , & z_getbalances , false } ,
{ " wallet " , " z_getstats " , & z_getstats , true } ,
{ " wallet " , " z_anonsettxdelta " , & z_anonsettxdelta , true } ,
{ " wallet " , " z_anonsetblockdelta " , & z_anonsetblockdelta , true } ,
{ " wallet " , " z_gettotalbalance " , & z_gettotalbalance , false } ,