Initial commit

This commit is contained in:
Ben Wilson 2020-03-31 09:48:16 -04:00
commit 9f221870b5
8 changed files with 662 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
zmetrics

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# zmetrics
Software to query a zcashd rpc interface for information about blocks and write the data to a json file.
## Usage
```
./zmetrics --help
zmetrics gathers data about the Zcash blockchain
Usage:
zmetrics [flags]
Flags:
--config string config file (default is current directory, zmetric.yaml)
--end-height int Ending block height (working backwards)
-h, --help help for zmetrics
--log-level uint32 log level (logrus 1-7) (default 4)
--num-blocks int Number of blocks (default 10)
--output-dir string Output directory (default "./blocks")
--rpc-host string rpc host (default "127.0.0.1")
--rpc-password string rpc password (default "notsecret")
--rpc-port string rpc port (default "38232")
--rpc-user string rpc user account (default "zcashrpc")
--start-height int Starting block height, defaults to current height (working backwards)
```
Example `zmetric.yaml` file
```
num-blocks: 100
output-dir: /var/www/html/data
rpc-host: zcashd01.z.cash
rpc-user: zcashrpc
rpc-password: notverysecure
```
Example run to get the last 30 blocks, write them to the current directory:
```
zmetrics --rpc-host 192.168.86.41 \
--rpc-port 38232 \
--rpc-user zcashrpc \
--rpc-password notsecure \
--num-blocks 30 \
--output-dir .
```
Example [data](data/zcashmetrics.json)

237
cmd/root.go Normal file
View File

@ -0,0 +1,237 @@
package cmd
import (
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/ybbus/jsonrpc"
"github.com/zcash-hackworks/zTypes"
)
var cfgFile string
var log *logrus.Entry
var logger = logrus.New()
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "zmetrics",
Short: "zmetrics gathers data about the Zcash blockchain",
Long: `zmetrics gathers data about the Zcash blockchain`,
Run: func(cmd *cobra.Command, args []string) {
opts := &Options{
RPCUser: viper.GetString("rpc-user"),
RPCPassword: viper.GetString("rpc-password"),
RPCHost: viper.GetString("rpc-host"),
RPCPort: viper.GetString("rpc-port"),
}
basicAuth := base64.StdEncoding.EncodeToString([]byte(opts.RPCUser + ":" + opts.RPCPassword))
rpcClient := jsonrpc.NewClientWithOpts("http://"+opts.RPCHost+":"+opts.RPCPort,
&jsonrpc.RPCClientOpts{
CustomHeaders: map[string]string{
"Authorization": "Basic " + basicAuth,
}})
if err := tryWritingFile(viper.GetString("output-dir")); err != nil {
log.Fatalf("Test to write metrics file failed: %s", err)
}
if err := generateMetrics(rpcClient); err != nil {
log.Fatalf("Failed to write metrics file: %s", err)
}
},
}
func generateMetrics(rpcClient jsonrpc.RPCClient) (err error) {
outputDir := viper.GetString("output-dir")
numBlocks := viper.GetInt("num-blocks")
if numBlocks == 0 {
numBlocks = 10
}
var startHeight *int = new(int)
if viper.GetInt("start-height") == 0 {
startHeight, err = getCurrentHeight(rpcClient)
if err != nil {
return err
}
} else {
*startHeight = viper.GetInt("start-height")
}
var endHeight *int = new(int)
if viper.GetInt("end-height") == 0 {
*endHeight = *startHeight - numBlocks
} else {
*endHeight = viper.GetInt("end-height")
}
// currentHeight, err := getCurrentHeight(rpcClient)
// if err != nil {
// return err
// }
// var endHeight *int = new(int)
//*endHeight = 347500 // Overwinter
//*endHeight = *currentHeight - 10
fmt.Printf("Getting metrics startng at %d through %d\n", *startHeight, *endHeight)
metrics, err := getBlockRangeMetrics(startHeight, endHeight, rpcClient)
if err != nil {
return err
}
blockFile := outputDir + "/zcashmetrics.json"
blockJSON, err := json.MarshalIndent(metrics, "", " ")
if err != nil {
log.Fatalln("generateMetrics MarshalIndent error: %s", err)
}
return ioutil.WriteFile(blockFile, blockJSON, 0644)
}
func getBlockRangeMetrics(startHeight *int, endHeight *int, rpcClient jsonrpc.RPCClient) ([]*zTypes.BlockMetric, error) {
if startHeight == nil {
currentHeight, err := getCurrentHeight(rpcClient)
if err != nil {
return nil, err
}
startHeight = currentHeight
}
if endHeight == nil {
*endHeight = *startHeight - 100
if *endHeight < 0 {
*endHeight = 0
}
}
if *endHeight > *startHeight {
return nil, fmt.Errorf("End height before Start height, bailing")
}
var blockMetrics []*zTypes.BlockMetric
for height := *endHeight; height <= *startHeight; height++ {
var block *zTypes.Block
log.Debugf("Calling getblock for block %d", height)
err := rpcClient.CallFor(&block, "getblock", strconv.Itoa(height), 2)
if err != nil {
return nil, err
}
//var blockMetric *BlockMetric
blockMetric := &zTypes.BlockMetric{
Height: height,
SaplingValuePool: block.SaplingValuePool(),
SproutValuePool: block.SproutValuePool(),
Size: block.Size,
Time: block.Time,
}
for _, tx := range block.TX {
blockMetric.NumberofTransactions = blockMetric.NumberofTransactions + 1
if tx.IsTransparent() {
blockMetric.NumberofTransparent = blockMetric.NumberofTransparent + 1
} else if tx.IsMixed() {
blockMetric.NumberofMixed = blockMetric.NumberofMixed + 1
} else if tx.IsShielded() {
blockMetric.NumberofShielded = blockMetric.NumberofShielded + 1
}
}
blockMetrics = append(blockMetrics, blockMetric)
}
return blockMetrics, nil
}
func getCurrentHeight(rpcClient jsonrpc.RPCClient) (currentHeight *int, err error) {
var blockChainInfo *zTypes.GetBlockchainInfo
if err := rpcClient.CallFor(&blockChainInfo, "getblockchaininfo"); err != nil {
return nil, err
}
height := &blockChainInfo.Blocks
return height, nil
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is current directory, zmetrics.yaml)")
rootCmd.PersistentFlags().Uint32("log-level", uint32(logrus.InfoLevel), "log level (logrus 1-7)")
rootCmd.PersistentFlags().String("rpc-user", "zcashrpc", "rpc user account")
rootCmd.PersistentFlags().String("rpc-password", "notsecret", "rpc password")
rootCmd.PersistentFlags().String("rpc-host", "127.0.0.1", "rpc host")
rootCmd.PersistentFlags().String("rpc-port", "38232", "rpc port")
rootCmd.PersistentFlags().Int("start-height", 0, "Starting block height, defaults to current height (working backwards)")
rootCmd.PersistentFlags().Int("end-height", 0, "Ending block height (working backwards)")
rootCmd.PersistentFlags().Int("num-blocks", 10, "Number of blocks")
rootCmd.PersistentFlags().String("output-dir", "./blocks", "Output directory")
viper.BindPFlag("log-level", rootCmd.PersistentFlags().Lookup("log-level"))
viper.SetDefault("log-level", int(logrus.InfoLevel))
viper.BindPFlag("rpc-user", rootCmd.PersistentFlags().Lookup("rpc-user"))
viper.SetDefault("rpc-user", "zcashrpc")
viper.BindPFlag("rpc-password", rootCmd.PersistentFlags().Lookup("rpc-password"))
viper.SetDefault("rpc-password", "notsecret")
viper.BindPFlag("rpc-host", rootCmd.PersistentFlags().Lookup("rpc-host"))
viper.SetDefault("rpc-host", "127.0.0.1")
viper.BindPFlag("rpc-port", rootCmd.PersistentFlags().Lookup("rpc-port"))
viper.SetDefault("rpc-port", "38232")
viper.BindPFlag("start-height", rootCmd.PersistentFlags().Lookup("start-height"))
viper.BindPFlag("end-height", rootCmd.PersistentFlags().Lookup("end-height"))
viper.BindPFlag("num-blocks", rootCmd.PersistentFlags().Lookup("num-blocks"))
viper.BindPFlag("output-dir", rootCmd.PersistentFlags().Lookup("output-dir"))
logger.SetFormatter(&logrus.TextFormatter{
//DisableColors: true,
//FullTimestamp: true,
//DisableLevelTruncation: true,
})
onexit := func() {
fmt.Printf("zmetric died with a Fatal error. Check logfile for details.\n")
}
log = logger.WithFields(logrus.Fields{
"app": "zmetric",
})
log.Logger.SetLevel(7)
logrus.RegisterExitHandler(onexit)
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Look in the current directory for a configuration file
viper.AddConfigPath(".")
// Viper auto appends extention to this config name
// For example, lightwalletd.yml
viper.SetConfigName("zmetrics")
}
// Replace `-` in config options with `_` for ENV keys
replacer := strings.NewReplacer("-", "_")
viper.SetEnvKeyReplacer(replacer)
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
var err error
if err = viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}

10
cmd/types.go Normal file
View File

@ -0,0 +1,10 @@
package cmd
// Options provides any flags used by zmetrics
type Options struct {
LogLevel uint64 `json:"log_level,omitempty"`
RPCUser string `json:"rpcUser,omitempty"`
RPCPassword string `json:"rpcPassword,omitempty"`
RPCHost string `json:"rpcHost,omitempty"`
RPCPort string `json:"rpcPort,omitempty"`
}

11
cmd/verify.go Normal file
View File

@ -0,0 +1,11 @@
package cmd
import "os"
func tryWritingFile(path string) (err error) {
_, err = os.Stat(path)
if err != nil {
return err
}
return nil
}

343
data/zcashmetrics.json Normal file
View File

@ -0,0 +1,343 @@
[
{
"height": 780428,
"number_of_transactions": 11,
"sapling_value_pool": 288774.62842571,
"sprout_value_pool": 130470.72948295,
"size": 13872,
"time": 1585659625,
"number_of_transparent_transactions": 9,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 2
},
{
"height": 780429,
"number_of_transactions": 1,
"sapling_value_pool": 288774.62842571,
"sprout_value_pool": 130470.72948295,
"size": 1666,
"time": 1585659636,
"number_of_transparent_transactions": 1,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780430,
"number_of_transactions": 2,
"sapling_value_pool": 288774.62842571,
"sprout_value_pool": 130470.72948295,
"size": 1910,
"time": 1585659644,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780431,
"number_of_transactions": 2,
"sapling_value_pool": 288774.62842571,
"sprout_value_pool": 130470.72948295,
"size": 1880,
"time": 1585659671,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780432,
"number_of_transactions": 1,
"sapling_value_pool": 288774.62842571,
"sprout_value_pool": 130470.72948295,
"size": 1666,
"time": 1585659697,
"number_of_transparent_transactions": 1,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780433,
"number_of_transactions": 5,
"sapling_value_pool": 288769.62841031,
"sprout_value_pool": 130470.72948295,
"size": 2961,
"time": 1585659752,
"number_of_transparent_transactions": 4,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 1
},
{
"height": 780434,
"number_of_transactions": 1,
"sapling_value_pool": 288769.62841031,
"sprout_value_pool": 130470.72948295,
"size": 1635,
"time": 1585659824,
"number_of_transparent_transactions": 1,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780435,
"number_of_transactions": 1,
"sapling_value_pool": 288769.62841031,
"sprout_value_pool": 130470.72948295,
"size": 1635,
"time": 1585659834,
"number_of_transparent_transactions": 1,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780436,
"number_of_transactions": 2,
"sapling_value_pool": 288769.62841031,
"sprout_value_pool": 130470.72948295,
"size": 1911,
"time": 1585659859,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780437,
"number_of_transactions": 3,
"sapling_value_pool": 288769.62841031,
"sprout_value_pool": 130470.72948295,
"size": 7710,
"time": 1585659937,
"number_of_transparent_transactions": 3,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780438,
"number_of_transactions": 3,
"sapling_value_pool": 288769.62841031,
"sprout_value_pool": 130485.73102069,
"size": 4178,
"time": 1585659954,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 1
},
{
"height": 780439,
"number_of_transactions": 1,
"sapling_value_pool": 288769.62841031,
"sprout_value_pool": 130485.73102069,
"size": 1629,
"time": 1585659958,
"number_of_transparent_transactions": 1,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780440,
"number_of_transactions": 12,
"sapling_value_pool": 288799.63100223,
"sprout_value_pool": 130485.73102069,
"size": 10792,
"time": 1585660224,
"number_of_transparent_transactions": 9,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 3
},
{
"height": 780441,
"number_of_transactions": 2,
"sapling_value_pool": 288799.63100223,
"sprout_value_pool": 130485.73102069,
"size": 1899,
"time": 1585660236,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780442,
"number_of_transactions": 7,
"sapling_value_pool": 288794.63065463,
"sprout_value_pool": 130485.73102069,
"size": 5563,
"time": 1585660350,
"number_of_transparent_transactions": 6,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 1
},
{
"height": 780443,
"number_of_transactions": 7,
"sapling_value_pool": 288794.63065463,
"sprout_value_pool": 130485.73102069,
"size": 16037,
"time": 1585660669,
"number_of_transparent_transactions": 7,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780444,
"number_of_transactions": 3,
"sapling_value_pool": 288794.63065463,
"sprout_value_pool": 130485.73102069,
"size": 2122,
"time": 1585660713,
"number_of_transparent_transactions": 3,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780445,
"number_of_transactions": 3,
"sapling_value_pool": 288794.63065463,
"sprout_value_pool": 130485.73102069,
"size": 2125,
"time": 1585660753,
"number_of_transparent_transactions": 3,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780446,
"number_of_transactions": 2,
"sapling_value_pool": 288794.63065463,
"sprout_value_pool": 130485.73102069,
"size": 3206,
"time": 1585660780,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780447,
"number_of_transactions": 1,
"sapling_value_pool": 288794.63065463,
"sprout_value_pool": 130485.73102069,
"size": 1635,
"time": 1585660826,
"number_of_transparent_transactions": 1,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780448,
"number_of_transactions": 9,
"sapling_value_pool": 288794.63065463,
"sprout_value_pool": 130485.73102069,
"size": 4254,
"time": 1585660938,
"number_of_transparent_transactions": 9,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780449,
"number_of_transactions": 6,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 36578,
"time": 1585661011,
"number_of_transparent_transactions": 5,
"number_of_shielded_transactions": 1,
"number_of_mixed_transactions": 0
},
{
"height": 780450,
"number_of_transactions": 1,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 1629,
"time": 1585661032,
"number_of_transparent_transactions": 1,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780451,
"number_of_transactions": 2,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 1910,
"time": 1585661102,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780452,
"number_of_transactions": 2,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 6157,
"time": 1585661132,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780453,
"number_of_transactions": 2,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 3171,
"time": 1585661171,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780454,
"number_of_transactions": 4,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 2366,
"time": 1585661286,
"number_of_transparent_transactions": 4,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780455,
"number_of_transactions": 2,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 1880,
"time": 1585661366,
"number_of_transparent_transactions": 2,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780456,
"number_of_transactions": 1,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 1629,
"time": 1585661370,
"number_of_transparent_transactions": 1,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780457,
"number_of_transactions": 3,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 2861,
"time": 1585661419,
"number_of_transparent_transactions": 3,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
},
{
"height": 780458,
"number_of_transactions": 9,
"sapling_value_pool": 288794.63055463,
"sprout_value_pool": 130485.73102069,
"size": 3586,
"time": 1585661604,
"number_of_transparent_transactions": 9,
"number_of_shielded_transactions": 0,
"number_of_mixed_transactions": 0
}
]

7
main.go Normal file
View File

@ -0,0 +1,7 @@
package main
import "github.com/zcash-hackworks/zmetrics/cmd"
func main() {
cmd.Execute()
}

5
zmetrics.yaml Normal file
View File

@ -0,0 +1,5 @@
num-blocks: 100
output-dir: .
rpc-host: zcashd01.z.cash
rpc-user: zcashrpc
rpc-password: notverysecure