{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import json\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import hvplot.pandas\n", "import panel as pn\n", "\n", "STATE_FILE = './chain-state.ndjson'\n", "\n", "MINER_STATE_COL_RENAMES = {\n", " 'Info.MinerAddr': 'Miner',\n", " 'Info.MinerPower.MinerPower.RawBytePower': 'Info.MinerPowerRaw',\n", " 'Info.MinerPower.MinerPower.QualityAdjPower': 'Info.MinerPowerQualityAdj',\n", " 'Info.MinerPower.TotalPower.RawBytePower': 'Info.TotalPowerRaw',\n", " 'Info.MinerPower.TotalPower.QualityAdjPower': 'Info.TotalPowerQualityAdj',\n", "}\n", "\n", "MINER_NUMERIC_COLS = [\n", " 'Info.MinerPowerRaw',\n", " 'Info.MinerPowerQualityAdj',\n", " 'Info.TotalPowerRaw',\n", " 'Info.TotalPowerQualityAdj',\n", " 'Info.Balance',\n", " 'Info.CommittedBytes',\n", " 'Info.ProvingBytes',\n", " 'Info.FaultyBytes',\n", " 'Info.FaultyPercentage',\n", " 'Info.PreCommitDeposits',\n", " 'Info.LockedFunds',\n", " 'Info.AvailableFunds',\n", " 'Info.WorkerBalance',\n", " 'Info.MarketEscrow',\n", " 'Info.MarketLocked',\n", "]\n", "\n", "DERIVED_COLS = [\n", " 'CommittedSectors',\n", " 'ProvingSectors',\n", "]\n", "\n", "ATTO_FIL_COLS = [\n", " 'Info.Balance',\n", " 'Info.PreCommitDeposits',\n", " 'Info.LockedFunds',\n", " 'Info.AvailableFunds',\n", " 'Info.WorkerBalance',\n", " 'Info.MarketEscrow',\n", " 'Info.MarketLocked',\n", "]\n", "\n", "def atto_to_fil(x):\n", " return float(x) * pow(10, -18)\n", "\n", "def chain_state_to_pandas(statefile):\n", " chain = None\n", " \n", " with open(statefile, 'rt') as f:\n", " for line in f.readlines():\n", " j = json.loads(line)\n", " chain_height = j['Height']\n", " \n", " miners = j['MinerStates']\n", " for m in miners.values():\n", " df = pd.json_normalize(m)\n", " df['Height'] = chain_height\n", " df.rename(columns=MINER_STATE_COL_RENAMES, inplace=True)\n", " if chain is None:\n", " chain = df\n", " else:\n", " chain = chain.append(df, ignore_index=True)\n", " chain.fillna(0, inplace=True)\n", " chain.set_index('Height', inplace=True)\n", " \n", " for c in ATTO_FIL_COLS:\n", " chain[c] = chain[c].apply(atto_to_fil)\n", " \n", " for c in MINER_NUMERIC_COLS:\n", " chain[c] = chain[c].apply(pd.to_numeric)\n", " \n", " # the Sectors.* fields are lists of sector ids, but we want to plot counts, so\n", " # we pull the length of each list into a new column\n", " chain['CommittedSectors'] = chain['Sectors.Committed'].apply(lambda x: len(x))\n", " chain['ProvingSectors'] = chain['Sectors.Proving'].apply(lambda x: len(x))\n", " return chain\n", " \n", "cs = chain_state_to_pandas(STATE_FILE)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# choose which col to plot using a widget\n", "\n", "cols_to_plot = MINER_NUMERIC_COLS + DERIVED_COLS\n", "\n", "col_selector = pn.widgets.Select(name='Field', options=cols_to_plot)\n", "cols = ['Miner'] + cols_to_plot\n", "plot = cs[cols].hvplot(by='Miner', y=col_selector)\n", "pn.Column(pn.WidgetBox(col_selector), plot)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# plot all line charts in a vertical stack\n", "\n", "plots = []\n", "for c in cols_to_plot:\n", " title = c.split('.')[-1]\n", " p = cs[['Miner', c]].hvplot(by='Miner', y=c, title=title)\n", " plots.append(p)\n", "pn.Column(*plots)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# miner power area chart\n", "\n", "mp = cs[['Miner', 'Info.MinerPowerRaw']].rename(columns={'Info.MinerPowerRaw': 'Power'})\n", "mp = mp.pivot_table(values=['Power'], index=cs.index, columns='Miner', aggfunc='sum')\n", "mp = mp.div(mp.sum(1), axis=0)\n", "mp.columns = mp.columns.get_level_values(1)\n", "mp.hvplot.area(title='Miner Power Distribution')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.2" } }, "nbformat": 4, "nbformat_minor": 4 }