Outputs aggregated metrics from the Zcash blockchain
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Output stats from Zcash blockchain using Blocksci
Uses https://github.com/cryptolu/BlockSci for Zcash Blocksci adaptation
Credit @st4d https://github.com/str4d for transaction type detection
"""
import blocksci
import os
import pandas as pd
import time
# Pass our blocksci data directory
chain = blocksci.Blockchain(os.path.expanduser("~/blocksci/zcash-data"))
data = []
# Loop through all blocks
# Filter this e.g for blk in chain[419200:] for Sapling only data
for blk in chain:
for tx in blk:
transaction_type = None
pool = None
tx_contains_transparent_out = tx.output_count > 0
tx_contains_transparent = (tx.input_count > 0) or tx_contains_transparent_out
# can also use is_sprout helper but using this for clarity
tx_contains_sprout = tx.vpub_count > 0
tx_contains_sapling = (tx.sspend_count > 0) or (
tx.soutput_count > 0) # equivalent to is_sapling helper
sprout_in = tx.sum_vpubold > tx.sum_vpubnew
sapling_in = tx.value_balance < 0
# Simple metric for unshielding: it isn't shielding, and there is another type
# of output to consume it (thus not unshielding solely for fees)
sprout_out = (tx.sum_vpubold < tx.sum_vpubnew) and (
sapling_in or tx_contains_transparent_out)
sapling_out = (tx.value_balance > 0) and (
sprout_in or tx_contains_transparent_out)
# Fully-shielded (solely Sprout or Sapling)
if not tx_contains_transparent:
if tx.is_sproutshielded and (not tx.is_saplingshielded):
transaction_type = "Shielded"
pool = "Sprout"
if (not tx.is_sproutshielded) and tx.is_saplingshielded:
transaction_type = "Shielded"
pool = "Sapling"
if sprout_out and sapling_in:
transaction_type = "Migration"
pool = "Transparent"
# Not fully shielded
if sprout_in:
transaction_type = "Shielding"
pool = "Sprout"
if sprout_out and (not sapling_in):
transaction_type = "Deshielding"
pool = "Sprout"
if sapling_in and (not sprout_out):
transaction_type = "Shielding"
pool = "Sapling"
if sapling_out:
transaction_type = "Deshielding"
pool = "Sapling"
# Catch everything else as transparent
if not transaction_type:
transaction_type = "Transparent"
pool = "Transparent"
# Write our data
data.append([tx.hash, tx.block_time, tx.block_height,
tx.is_coinbase, pool, transaction_type])
# Setup our dataframe and preview it
df = pd.DataFrame(data)
df.columns = ["Txid", "BlockTime", "Block", "Coinbase", "Pool", "Type"]
# Format the categories
df["Pool"] = df["Pool"].astype("category")
df["Type"] = df["Type"].astype("category")
# Preview our dataframe
# print(df.head(5))
df.BlockTime = df.BlockTime.dt.strftime('%Y-%m')
output = df.pivot_table(index="BlockTime", values="Txid", fill_value=0, aggfunc="count", columns=[
"Pool", "Type"], margins=True, margins_name="Total")
output.to_csv("zcash-data.csv")
print(output)