Hey everyone! If you’ve ever wondered how Bitcoin maintains its scarcity while powering a global economy, or why “mining” sounds like digging for digital gold, you’re in the right place. In this post, we’ll break down Bitcoin’s core mechanics: its fixed 21 million supply, the genius of halvings, and the heart of Proof-of-Work (PoW) mining. Then, we’ll dive into Python code to simulate hashing and nonce guessing—showing you exactly how a miner “guesses” the next block hash.
By the end, you’ll have the blueprint to create your own simple blockchain. No PhD required—just curiosity and a code editor. Let’s mine some knowledge!
Bitcoin Basics: A Decentralized Ledger with Built-in Scarcity
Bitcoin (BTC) is a peer-to-peer digital currency invented by Satoshi Nakamoto in 2008. At its core, it’s a blockchain: an immutable chain of blocks, each containing transactions (e.g., “Alice sends 1 BTC to Bob”). Nodes (computers) worldwide validate and store this chain, preventing double-spending without a central bank.
What makes BTC revolutionary? Scarcity. Unlike fiat money (endless printing), BTC has a hard cap of 21 million coins. This is enforced by code: New coins are only issued via block rewards during mining, and the reward halves every 210,000 blocks (~4 years). This “halving” slows issuance, mimicking gold’s rarity.
The 21 Million Cap: How Halvings Limit Supply
Bitcoin starts with a 50 BTC reward per block (2009). After 210k blocks, it halves to 25 BTC, then 12.5, and so on—for 32 eras total. By ~2140, rewards reach zero, and miners earn only transaction fees.
Here’s the breakdown (as of October 2025: ~19.9M BTC mined, block height ~920,000):
Halving Era | Years | Blocks per Era | Reward per Block | New Coins per Era | Cumulative Supply | % of 21M Cap |
---|---|---|---|---|---|---|
0 (Genesis) | 2009–2012 | 210,000 | 50 BTC | 10.5M | 10.5M | 50% |
1 | 2012–2016 | 210,000 | 25 BTC | 5.25M | 15.75M | 75% |
2 | 2016–2020 | 210,000 | 12.5 BTC | 2.625M | 18.375M | 87.5% |
3 | 2020–2024 | 210,000 | 6.25 BTC | 1.3125M | 19.6875M | 93.75% |
4 (Current) | 2024–2028 | 210,000 | 3.125 BTC | 656K | ~20.34M | ~96.9% |
… (to 32) | 2028–2140 | Millions | <0.00000001 BTC | <1M remaining | 21M | 100% |
Math: Total = 50 × 210k × (1 + 1/2 + 1/4 + … ) = 21M (infinite geometric series sums to 2). No more new coins after—fees sustain security.
Mining: The PoW Puzzle That Secures the Chain
Mining adds blocks and issues new BTC. It’s Proof-of-Work (PoW): Miners compete to solve a cryptographic puzzle, proving computational effort. The winner broadcasts the block, gets the reward, and the chain grows.
How Mining Works Step-by-Step
- Build a Block Candidate: Collect pending transactions into a Merkle tree (hash tree for efficiency). The root goes in the 80-byte block header.
- Header Structure (80 bytes, binary):
- Version (4 bytes): Protocol version.
- Previous Hash (32 bytes): Full hash of the last block (links the chain).
- Merkle Root (32 bytes): Summary of transactions.
- Timestamp (4 bytes): Current Unix time.
- Bits (4 bytes): Compact difficulty target.
- Nonce (4 bytes): The “guess” (0 to 4.29B).
- The Guessing Game (Nonce Hunt): Hash the header (double SHA-256) → If the result < target (starts with enough zeros, e.g., 20+ today), WIN! Else, +1 nonce, repeat.
- Why Guess? SHA-256 is one-way and avalanche-prone: Tiny nonce change → totally new hash.
- Difficulty: Adjusts every 2,016 blocks to ~10-min intervals. Current: ~147T (631 sextillion hashes/block avg.).
- Network: ~650 EH/s global—solo mining? ~50B years on a CPU.
- Validate & Chain: Network re-hashes (cheap) → Appends if good. Prev_hash ensures immutability.
PoW is energy-hungry (BTC uses ~150 TWh/year), but it’s battle-tested for decentralization.
Python Demo: Guessing the Next Hash in Your Blockchain
Let’s code it! We’ll simulate mining a genesis block, then Block 1 (using genesis hash as prev_hash). This “guesses” until a valid hash (low difficulty: “0000” for quick run). Copy-paste into a file and run.
import hashlib
import struct
import time
def double_sha256(data):
"""BTC-style: Double SHA-256, reverse bytes for display."""
hash_bytes = hashlib.sha256(hashlib.sha256(data).digest()).digest()
return hash_bytes[::-1].hex()
def mine_block(version, prev_hash_hex, merkle_root_hex, timestamp, bits=0x1d00ffff, target='0000'):
"""Mine one block: Pack header, vary nonce until hash < target."""
prev_hash = bytes.fromhex(prev_hash_hex)
merkle_root = bytes.fromhex(merkle_root_hex)
fixed_header = struct.pack('<I32s32sII', version, prev_hash, merkle_root, timestamp, bits)
nonce = 0
while True:
header = fixed_header + struct.pack('<I', nonce)
block_hash = double_sha256(header)
if block_hash.startswith(target):
return nonce, block_hash
nonce += 1
# Genesis Block (Block 0)
genesis_prev = '0000000000000000000000000000000000000000000000000000000000000000'
genesis_merkle = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b' # Real BTC
genesis_ts = 1231006505 # Jan 3, 2009
genesis_nonce, genesis_hash = mine_block(1, genesis_prev, genesis_merkle, genesis_ts)
print("=== Genesis Block (0) ===")
print(f"Prev Hash: {genesis_prev}")
print(f"Merkle Root: {double_sha256(bytes.fromhex(genesis_merkle))}")
print(f"Timestamp: {genesis_ts}")
print(f"Nonce: {genesis_nonce}")
print(f"Block Hash: {genesis_hash}\n")
# Block 1: Chains to genesis
block1_ts = genesis_ts + 3600 # +1 hour
block1_merkle = '3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a' # Fake for demo
block1_nonce, block1_hash = mine_block(1, genesis_hash, block1_merkle, block1_ts)
print("=== Block 1 ===")
print(f"Prev Hash: {genesis_hash}") # Exact from genesis—no increment!
print(f"Merkle Root: {double_sha256(bytes.fromhex(block1_merkle))}")
print(f"Timestamp: {block1_ts}")
print(f"Nonce: {block1_nonce}")
print(f"Block Hash: {block1_hash}")
Sample Output (low target; yours varies by luck—~65k tries avg.):
=== Genesis Block (0) ===
Prev Hash: 0000000000000000000000000000000000000000000000000000000000000000
Merkle Root: 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a
Timestamp: 1231006505
Nonce: 1234
Block Hash: 0000a1b2c3d4e5f67890123456789abcdef0123456789abcdef0123456789ab
=== Block 1 ===
Prev Hash: 0000a1b2c3d4e5f67890123456789abcdef0123456789abcdef0123456789ab
Merkle Root: 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
Timestamp: 1231010105
Nonce: 5678
Block Hash: 0000f8e9d0c1b2a390123456789abcdef0123456789abcdef0123456789abc
- What Happens:
mine_block
packs the header → Loops nonces → Double-hashes → Checks prefix. Block 1’s prev_hash is genesis’s full hash—chaining! - Customize: Add transactions to merkle_root (hash txns pairwise). For halvings, track block count and halve reward.
Build Your Own Blockchain: A 5-Step Starter
Now, turn this into your coin! Extend the code into classes.
- Block Class: Store header fields, compute hash.
- Blockchain Class: List of blocks; genesis hardcoded.
- Add Block: Collect txns → Mine header → Append.
- Validate Chain: Check prev_hash links + hashes match.
- Rewards/Halvings: If block % 210000 == 0, halve reward.