pyblock/pybitblock/mempool_monitor.py
2024-07-31 18:10:04 -03:00

168 lines
6.6 KiB
Python

import asyncio
from rich.live import Live
from rich.table import Table
from rich.panel import Panel
from rich.layout import Layout
from rich.text import Text
import subprocess
import json
import time
import plotext as plt
from execute_load_config import load_config
# Load configuration
path, settings, settingsClock = load_config()
def fetch_mempool_data(path):
raw_mempool = subprocess.run([path["bitcoincli"], "getmempoolinfo"], capture_output=True, text=True)
mempool_data = json.loads(raw_mempool.stdout)
return mempool_data
def fetch_mempool_transactions(path):
raw_mempool = subprocess.run([path["bitcoincli"], "getrawmempool", "true"], capture_output=True, text=True)
mempool_transactions = json.loads(raw_mempool.stdout)
return mempool_transactions
def fetch_blockchain_info(path):
raw_info = subprocess.run([path["bitcoincli"], "getblockchaininfo"], capture_output=True, text=True)
blockchain_info = json.loads(raw_info.stdout)
return blockchain_info
def calculate_average_median_fee(mempool_transactions):
fees_per_byte = []
for tx in mempool_transactions.values():
fee = tx['fees']['base'] * 1e8 # Convert BTC to satoshis
size = tx['vsize']
fee_per_byte = fee / size
fees_per_byte.append(fee_per_byte)
average_fee = sum(fees_per_byte) / len(fees_per_byte) if fees_per_byte else 0
median_fee = sorted(fees_per_byte)[len(fees_per_byte) // 2] if fees_per_byte else 0
return average_fee, median_fee
def create_mempool_info_table(mempool_data, mempool_transactions):
table = Table(title="Mempool Information")
table.add_column("Metric", style="cyan")
table.add_column("Value", style="magenta")
table.add_row("Mempool Size", f"{mempool_data['size']} transactions")
table.add_row("Mempool Bytes", f"{mempool_data['bytes']} bytes")
table.add_row("Usage", f"{mempool_data['usage']} bytes")
table.add_row("Max Mempool", f"{mempool_data['maxmempool']} bytes")
table.add_row("Mempool Min Fee", f"{mempool_data['mempoolminfee']:.8f} BTC")
table.add_row("Min Relay Tx Fee", f"{mempool_data['minrelaytxfee']:.8f} BTC")
average_fee, median_fee = calculate_average_median_fee(mempool_transactions)
table.add_row("Average Fee", f"{average_fee:.2f} sat/byte")
table.add_row("Median Fee", f"{median_fee:.2f} sat/byte")
segwit_txs = sum(1 for tx in mempool_transactions.values() if tx.get('wtxid'))
non_segwit_txs = len(mempool_transactions) - segwit_txs
table.add_row("SegWit Transactions", str(segwit_txs))
table.add_row("Non-SegWit Transactions", str(non_segwit_txs))
return table
def create_recent_blocks_table(path):
table = Table(title="Recent Blocks")
table.add_column("Height", style="cyan")
table.add_column("Transactions", style="magenta")
table.add_column("Size", style="green")
table.add_column("Time", style="yellow")
recent_blocks = fetch_blockchain_info(path)
latest_height = recent_blocks['blocks']
for i in range(17):
block_height = latest_height - i
block_hash = subprocess.run([path["bitcoincli"], "getblockhash", str(block_height)], capture_output=True, text=True).stdout.strip()
block_info = subprocess.run([path["bitcoincli"], "getblock", block_hash], capture_output=True, text=True)
block_data = json.loads(block_info.stdout)
table.add_row(
str(block_height),
str(block_data['nTx']),
f"{block_data['size']} bytes",
time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(block_data['time']))
)
return table
def create_mempool_transactions_table(mempool_transactions):
table = Table(title="Mempool Transactions")
table.add_column("Transaction ID", style="cyan")
table.add_column("Size", style="magenta")
table.add_column("Fee", style="green")
sorted_transactions = sorted(mempool_transactions.items(), key=lambda item: item[1]['time'], reverse=True)
for txid, details in sorted_transactions[:17]:
fee = details.get('fees', {}).get('base', 0)
size = details.get('vsize', 'N/A')
table.add_row(txid, str(size), f"{fee:.8f} BTC")
return table
def create_mempool_flow_chart():
plt.clear_color()
plt.title("Mempool Flow")
plt.xlabel("Time")
plt.ylabel("Transactions")
plt.plot_size(80, 20)
# Add dummy data
x = list(range(10))
y = [i ** 2 for i in x]
plt.plot(x, y)
chart = plt.build()
return chart
async def display_mempool_info():
layout = Layout()
layout.split_column(
Layout(name="header", size=3),
Layout(name="main", ratio=1),
Layout(name="footer", size=1),
)
layout["main"].split_row(
Layout(name="left", ratio=1),
Layout(name="right", ratio=1),
)
layout["left"].split(Layout(name="mempool_info"), Layout(name="recent_blocks"))
layout["right"].split(Layout(name="mempool_chart"), Layout(name="mempool_transactions"))
layout["footer"].update(Text("Cypherpunk Style loading..."))
layout["mempool_info"].update(Panel(Text("Cypherpunk Style loading..."), title="General Information"))
layout["mempool_chart"].update(Panel(Text("Cypherpunk Style loading..."), title="Mempool Flow"))
layout["recent_blocks"].update(Panel(Text("Cypherpunk Style loading..."), title="Last Blocks"))
layout["header"].update(Text("Mempool Monitor", style="bold magenta"))
mempool_data_points = []
with Live(layout, refresh_per_second=1, screen=True):
while True:
mempool_data = fetch_mempool_data(path)
mempool_transactions = fetch_mempool_transactions(path)
mempool_info_table = create_mempool_info_table(mempool_data, mempool_transactions)
recent_blocks_table = create_recent_blocks_table(path)
mempool_transactions_table = create_mempool_transactions_table(mempool_transactions)
current_time = time.time()
mempool_data_points.append({'time': current_time, 'size': mempool_data['size']})
if len(mempool_data_points) > 10: # Keep only the last 10 data points
mempool_data_points.pop(0)
mempool_flow_chart = create_mempool_flow_chart()
layout["mempool_info"].update(Panel(mempool_info_table, title="General Information"))
layout["recent_blocks"].update(Panel(recent_blocks_table, title="Recent Blocks"))
layout["mempool_transactions"].update(Panel(mempool_transactions_table, title="Recent Transactions"))
layout["mempool_chart"].update(Panel(mempool_flow_chart, title="Mempool Flow"))
layout["footer"].update(Text("Running the node."))
if __name__ == "__main__":
asyncio.run(display_mempool_info())