Duration: 2.5β3 hours | Difficulty: Intermediate | Platform: Jupyter Notebook / Google Colab
Alignment: Course Objectives 1, 3, 7 (Understand blockchain structures, analyze consensus/network models, assess scalability)
Prerequisites: Python fundamentals, familiarity with SHA-256 hashing (Week 2), basic understanding of distributed systems
web3==6.15.1
ipywidgets
numpyCopy each cell block below into a new Jupyter Notebook or Google Colab session in exact order.
# π¦ Install dependencies (Colab only; skip if running locally)
import sys
!{sys.executable} -m pip install web3 numpy -q
import struct
import hashlib
import random
import time
from datetime import datetime## π LAB 3: Blockchain Architecture & Network Simulation
**Real-World Context:**
- Bitcoin blocks use an 80-byte header structure globally recognized by ~15,000 full nodes
- P2P gossip protocols propagate blocks across continents in <5 seconds
- Architecture dictates the trust-throughput-finality trade-off: Bitcoin ~7 TPS vs PostgreSQL ~10,000+ TPS
**Your Tasks:**
1. Simulate a decentralized P2P network with gossip-based block propagation
2. Parse a real Bitcoin block header and verify cryptographic chaining
3. Calculate architectural throughput limits and compare with traditional systems
4. Run the auto-grader for immediate feedback (0β100%)
β οΈ **Do not modify grading cells.** Fill only `# YOUR CODE HERE` sections.# === PART A: P2P GOSSIP SIMULATION ===
class P2PNode:
def __init__(self, node_id):
self.node_id = node_id
self.peers = []
self.known_blocks = set()
self.received_at = None
def add_peers(self, peers_list):
self.peers = [p for p in peers_list if p.node_id != self.node_id]
def receive_block(self, block_hash, timestamp):
if block_hash not in self.known_blocks:
self.known_blocks.add(block_hash)
self.received_at = timestamp
return True
return False
def simulate_gossip_network(num_nodes=10, source_id=0, max_hops=5):
"""Simulate block propagation using gossip protocol."""
random.seed(42) # Deterministic for grading
nodes = [P2PNode(i) for i in range(num_nodes)]
# Connect nodes in a random mesh (each node connects to 3 peers)
for node in nodes:
candidates = [n for n in nodes if n not in node.peers and n.node_id != node.node_id]
if candidates:
node.peers = random.sample(candidates, min(3, len(candidates)))
# Seed block
block_hash = f"0x{hashlib.sha256(b'block_800000').hexdigest()[:16]}"
start_time = time.time()
# Queue for propagation: (node, block_hash, current_hop, timestamp)
queue = [(nodes[source_id], block_hash, 0, start_time)]
visited = set()
while queue:
current_node, b_hash, hops, ts = queue.pop(0)
if current_node.receive_block(b_hash, ts) and hops < max_hops:
# Gossip to 2 random peers
targets = random.sample(current_node.peers, min(2, len(current_node.peers)))
for peer in targets:
if b_hash not in peer.known_blocks:
queue.append((peer, b_hash, hops + 1, time.time()))
propagation_time = time.time() - start_time
covered = sum(1 for n in nodes if b_hash in n.known_blocks)
return covered, propagation_time, nodes
# Quick Test
covered, prop_time, net = simulate_gossip_network(10)
print(f"Nodes receiving block: {covered}/10 | Time: {prop_time:.4f}s")# === PART B: BITCOIN BLOCK HEADER PARSER ===
def parse_block_header(header_hex):
"""Parse 80-byte Bitcoin block header and return structured dict."""
# YOUR CODE HERE: Use struct.unpack to extract version, prev_hash, merkle_root, timestamp, bits, nonce
# Note: Bitcoin stores integers in little-endian, hashes are reversed in explorers
pass
def verify_chain_linkage(prev_block_hash_hex, current_header_hex):
"""Verify current header's prev_hash matches actual previous block hash."""
# YOUR CODE HERE: Parse current header, compare prev_hash field with provided prev_block_hash_hex
pass
def verify_pow_difficulty(bits_hex, block_hash_hex):
"""Check if block hash meets difficulty target defined by 'bits' field."""
# YOUR CODE HERE: Convert bits to target, compare block_hash <= target
pass
# Test Data (Bitcoin Block #800,000 - April 2024 Halving)
TEST_HEADER_HEX = "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" # Simplified for lab; real parser handles actual hex
# Note: Full lab uses deterministic mock header for grading stability# === PART C: ARCHITECTURAL TRADE-OFF CALCULATIONS ===
def calculate_theoretical_tps(block_size_mb=1.0, avg_tx_size_bytes=250, block_interval_sec=600):
"""Calculate max theoretical TPS for Bitcoin-like architecture."""
# YOUR CODE HERE: Convert MB to bytes, divide by avg_tx_size, then by interval
pass
def compare_architecture_throughput(blockchain_tps, traditional_tps=10000):
"""Return overhead ratio and architectural insight."""
# YOUR CODE HERE: Compute (traditional_tps / blockchain_tps) and return ratio + brief reason
pass
# Quick Test
tps = calculate_theoretical_tps()
print(f"Theoretical BTC TPS: {tps:.2f} | Traditional DB: ~10,000+ TPS")# === π€ AUTO-GRADER ===
class Lab3Grader:
def __init__(self):
self.score = 0
self.total = 100
self.feedback = []
def grade(self, name, func, *args, expected, points):
try:
result = func(*args)
if result == expected:
self.score += points
self.feedback.append(f"β
{name}: Passed (+{points})")
else:
self.feedback.append(f"β {name}: Expected {expected}, got {result}")
except Exception as e:
self.feedback.append(f"β {name}: Error - {str(e)}")
def grade_p2p(self):
covered, _, _ = simulate_gossip_network(10)
self.grade("P2P Coverage", lambda: covered, expected=10, points=20)
def grade_parser(self):
# Mock deterministic header for grading
mock_header = bytes([
0x00, 0x00, 0x00, 0x20, # Version 32
0x01]*32, # Prev hash (simplified)
0x02]*32, # Merkle root
0x40, 0x1a, 0x11, 0x60, # Timestamp 1611717184
0x17, 0x0e, 0x4b, 0x1f, # Bits
0x85, 0x00, 0x00, 0x00 # Nonce 133
])
mock_hex = mock_header.hex()
parsed = parse_block_header(mock_hex)
self.grade("Header Parsing - Version", lambda: parsed.get('version'), expected=32, points=10)
self.grade("Header Parsing - Timestamp", lambda: parsed.get('timestamp'), expected=1611717184, points=10)
self.grade("Header Parsing - Nonce", lambda: parsed.get('nonce'), expected=133, points=10)
def grade_architecture(self):
tps = calculate_theoretical_tps()
self.grade("TPS Calculation", lambda: round(tps, 2), expected=6.67, points=25)
ratio = compare_architecture_throughput(6.67)[0]
self.grade("Throughput Ratio", lambda: ratio > 1000, expected=True, points=15)
def report(self):
self.grade_p2p()
self.grade_parser()
self.grade_architecture()
print("\nπ LAB 3 AUTO-GRADER RESULTS")
print("="*30)
for msg in self.feedback: print(msg)
print(f"\nπ― FINAL SCORE: {self.score}/{self.total} ({(self.score/self.total)*100:.1f}%)")
if self.score >= 80: print("β
PASS - Architecture concepts verified")
else: print("β οΈ REVIEW NEEDED - Check failed tests above")
# Run Grader
grader = Lab3Grader()
grader.report()- Open Google Colab or launch Jupyter Notebook locally.
- Create a new notebook:
lab3_blockchain_architecture.ipynb - Paste Cell 1 and run (
Shift+Enter). This installs required packages. - Paste Cell 2 to review objectives.
- Paste Cell 3.
- The simulation is pre-written but requires you to understand the gossip mechanism.
- Modify
simulate_gossip_networkto track propagation hops per node (addself.hopstoP2PNode). - Run the cell. Verify output shows
10/10coverage with deterministic seed. - Concept Check: Why does gossip scale to O(log N) propagation time? How does this differ from centralized broadcast?
- Paste Cell 4.
- Replace
passinparse_block_headerwith:b = bytes.fromhex(header_hex) return { 'version': struct.unpack('<I', b[0:4])[0], 'prev_hash': b[4:36][::-1].hex(), 'merkle_root': b[36:68][::-1].hex(), 'timestamp': struct.unpack('<I', b[68:72])[0], 'bits': struct.unpack('<I', b[72:76])[0], 'nonce': struct.unpack('<I', b[76:80])[0] }
- Implement
verify_chain_linkageandverify_pow_difficultyusing parsed fields. - Run cell. Verify parser correctly extracts version, timestamp, nonce from mock header.
- Paste Cell 5.
- Implement
calculate_theoretical_tps:block_bytes = block_size_mb * 1024 * 1024 tx_count = block_bytes / avg_tx_size_bytes return tx_count / block_interval_sec
- Implement
compare_architecture_throughputto return(ratio, "Blockchain sacrifices throughput for decentralization & BFT"). - Run cell. Confirm TPS β 6.67 and ratio > 1000.
- Paste Cell 6 at notebook bottom.
- Run it. Grader tests P2P coverage, header parsing accuracy, and throughput math.
- Submission Requirements:
- Export notebook as PDF
- Include screenshots of:
- Auto-grader score β₯80%
- P2P network output (nodes covered, propagation time)
- Parsed header fields vs expected values
- Upload as
CSN4104_Week3_Lab_YourName.pdf
| Issue | Solution |
|---|---|
ModuleNotFoundError: No module named 'web3' |
Run Cell 1 again. If local: pip install web3 numpy |
| P2P coverage < 10/10 | Check random.seed(42) placement. Ensure max_hops >= 5 and peer list isn't empty |
| Parser returns wrong version/timestamp | Bitcoin uses little-endian for integers (<I). Hashes need [::-1] reversal |
| TPS calculation mismatch | Verify: 1MB = 1,048,576 bytes. 1,048,576 / 250 / 600 β 6.67 |
Auto-grader shows Error |
Ensure function signatures exactly match templates. Do not change parameter names |
| Criteria | Auto-Graded | Manual Review | Weight |
|---|---|---|---|
| P2G Network Simulation | β Coverage & propagation logic | Graph/diagram of gossip flow | 25% |
| Block Header Parsing | β Field extraction accuracy | Correct endianness handling, hash reversal | 30% |
| Architectural Analysis | β TPS math, ratio calculation | Insight on CAP trade-offs, real-world justification | 25% |
| Submission & Documentation | β | PDF quality, reflection, troubleshooting notes | 20% |
web3.py/bitcoinjs-lib: Industry-standard node interaction libraries- P2P Gossip: Modeled after Bitcoin's
INV/GETDATAprotocol & Ethereum'sdevp2p - Block Structure: Matches BIP 31 header specification (80 bytes, little-endian integers)
- Throughput Math: Aligns with Cambridge CBEI & Visa/BTC architectural comparisons
- π¦ GitHub Repos for Extension:
libp2p/go-libp2p(real P2P stack)bitcoin/bitcoin(header parsing in C++)ethereum/go-ethereum(EVM block architecture)