Spaces:
Sleeping
Sleeping
import gradio as gr | |
import networkx as nx | |
import matplotlib.pyplot as plt | |
import hashlib | |
import time | |
import io | |
from PIL import Image | |
# ------------------- BLOCKCHAIN LOGIC -------------------- # | |
class Block: | |
def __init__(self, index, data, previous_hash="0"): | |
self.index = index | |
self.timestamp = time.time() | |
self.data = data | |
self.previous_hash = previous_hash | |
self.nonce = 0 | |
self.hash = self.calculate_hash() | |
def calculate_hash(self): | |
block_string = ( | |
str(self.index) + | |
str(self.timestamp) + | |
str(self.data) + | |
str(self.previous_hash) + | |
str(self.nonce) | |
) | |
return hashlib.sha256(block_string.encode()).hexdigest() | |
def mine_block(block, difficulty=1): | |
""" | |
A quick "proof-of-work": | |
The block's hash must start with '0' * difficulty, e.g. '0' for difficulty=1. | |
If this is still slow for you, set difficulty=0 to skip "mining" entirely. | |
""" | |
target_prefix = "0" * difficulty | |
while not block.hash.startswith(target_prefix): | |
block.nonce += 1 | |
block.hash = block.calculate_hash() | |
def create_genesis_block(): | |
genesis = Block(index=0, data="Genesis Block", previous_hash="0") | |
mine_block(genesis, difficulty=1) | |
return genesis | |
# The global chain | |
chain = [] | |
# Initialize the chain with a genesis block if empty | |
if not chain: | |
chain.append(create_genesis_block()) | |
def add_block_to_chain(data): | |
previous_block = chain[-1] | |
new_block = Block( | |
index=len(chain), | |
data=data, | |
previous_hash=previous_block.hash | |
) | |
mine_block(new_block, difficulty=1) | |
chain.append(new_block) | |
# ------------------- VISUALIZATION -------------------- # | |
def visualize_chain(chain): | |
""" | |
Creates a LINEAR graph of the blockchain using NetworkX | |
and returns it as a PIL image. | |
We'll place blocks in a line (x=index, y=0) to avoid | |
expensive layout computations each time. | |
""" | |
G = nx.DiGraph() | |
# Add nodes | |
for blk in chain: | |
# node label shows index + partial hash | |
node_label = f"Block {blk.index}\nHash: {blk.hash[:6]}..." | |
G.add_node(blk.index, label=node_label) | |
# Add edges | |
for i in range(len(chain) - 1): | |
G.add_edge(chain[i].index, chain[i+1].index) | |
# Fixed, linear layout: x = index, y = 0 | |
pos = {blk.index: (blk.index, 0) for blk in chain} | |
# Draw the graph | |
plt.figure(figsize=(10, 3)) | |
nx.draw_networkx_nodes(G, pos, node_color="lightblue", node_size=1500) | |
nx.draw_networkx_edges(G, pos, arrowstyle='->', arrowsize=20) | |
node_labels = nx.get_node_attributes(G, 'label') | |
nx.draw_networkx_labels(G, pos, labels=node_labels, font_size=8) | |
plt.title("Toy Blockchain Visualization (Linear Layout)") | |
plt.axis("off") | |
# Convert the Matplotlib figure to a PIL image | |
buf = io.BytesIO() | |
plt.savefig(buf, format='png', bbox_inches='tight') | |
buf.seek(0) | |
plt.close() | |
return Image.open(buf) | |
def add_and_visualize_block(data): | |
# Add a new block with user-provided data | |
add_block_to_chain(data) | |
# Generate the updated visualization | |
return visualize_chain(chain) | |
# ------------------- GRADIO INTERFACE -------------------- # | |
demo = gr.Interface( | |
fn=add_and_visualize_block, | |
inputs=gr.Textbox(lines=2, label="Data for New Block", placeholder="e.g. 'My transaction'"), | |
outputs="image", | |
title="Toy Blockchain Demo (Faster Visualization)", | |
description=( | |
"Enter any data to create a new block. " | |
"Mining difficulty is set to 1, so it should be fast. " | |
"Blocks are displayed in a linear chain." | |
), | |
) | |
demo.launch(debug=True) |