Building a Nakamoto Consensus Simulator in Pure Python
Building a Nakamoto Consensus Simulator in Pure Python
To visualize how the "Most Work" rule protects the network from double-spending, we can build a Consensus Race Simulator. This script simulates two competing entities: an Honest Network and an Attacker, each with a defined percentage of the total hashrate.
1. The Consensus Race Source Code
Save the following Python script as consensus_race_sim.py.
import random
class ConsensusRaceSim:
def __init__(self, attacker_hashrate_pct: float, confirm_threshold: int):
self.q = attacker_hashrate_pct / 100.0 # Attacker power
self.p = 1.0 - self.q # Honest power
self.z = confirm_threshold # Number of blocks to catch up
def simulate_race(self):
"""
Simulates a single race. Returns True if attacker catches up,
False if they fail after a reasonable number of blocks.
"""
# Attacker starts z blocks behind
attacker_blocks = 0
honest_blocks = self.z
# We cap the simulation at a high number to avoid infinite loops
# though math says p > q will eventually converge to 0 probability.
max_blocks = 1000
while honest_blocks < max_blocks:
# Roll for who finds the next block
if random.random() < self.q:
attacker_blocks += 1
else:
honest_blocks += 1
# If attacker catches up or overtakes
if attacker_blocks >= honest_blocks:
return True
return False
def run_monte_carlo(self, trials: int = 10000):
print(f"[*] Starting Monte Carlo Simulation...")
print(f"[*] Attacker Hashrate: {self.q*100:.1f}%")
print(f"[*] Honest Hashrate: {self.p*100:.1f}%")
print(f"[*] Confirmations: {self.z}")
successes = 0
for _ in range(trials):
if self.simulate_race():
successes += 1
prob = (successes / trials) * 100
print(f"\n[✔] Results after {trials:,} trials:")
print(f" └─ Attacker Successes: {successes}")
print(f" └─ Success Probability: {prob:.4f}%")
if __name__ == "__main__":
# Example 1: Attacker with 10% hashrate vs 6 confirmations
sim1 = ConsensusRaceSim(attacker_hashrate_pct=10, confirm_threshold=6)
sim1.run_monte_carlo()
print("\n" + "="*40 + "\n")
# Example 2: Attacker with 35% hashrate vs 6 confirmations
sim2 = ConsensusRaceSim(attacker_hashrate_pct=35, confirm_threshold=6)
sim2.run_monte_carlo()
️ 2. Interpreting the Results
When you run this script, you will see how sensitive the network is to the confirmation threshold:
-
Low Hashrate Attacker (10%): Even with 10,000 trials, an attacker with only 10% hashrate will almost never catch up after 6 blocks. The probability is typically $<0.1\%$.
-
High Hashrate Attacker (35%): An attacker with 35% hashrate has a much better chance. You will likely see a success probability around 10-15%. This is why for extremely high-value transactions, waiting for 10 or 20 confirmations is recommended.
Key Takeaways
-
Hashpower is King: The rule of thumb is that if an attacker has $>50\%$ hashrate ($q > 0.5$), the success probability is 100% given enough time.
-
Time is Security: Each additional block added to the chain increases the "cost" and "luck" required for an attacker to reorganize the ledger.
TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation: