TeachMeBitcoin

Custom Python Reward Simulator

From TeachMeBitcoin, the free encyclopedia ⏱️ 3 min read

Building a Block Subsidy and Halving Simulator in Pure Python

To understand how the Bitcoin consensus protocol enforces the 33-epoch halving schedule and calculates the exact final coin supply of $20,999,999.9769\text{ BTC}$, we can implement a custom Reward and Halving Simulator in Python.

By writing this simulator from scratch using only Python's standard libraries, we can model how the C++ consensus code executes bitwise right-shift divisions and track the total circulating supply down to the individual satoshi.


💻 1. The Block Subsidy Simulator Source Code

Save the following standard-library Python script as python_reward_simulator.py.

class BitcoinRewardSimulator:
    def __init__(self):
        self.blocks_per_epoch = 210000
        # Starting block subsidy: 50 BTC in Satoshis (5,000,000,000 Satoshis)
        self.initial_subsidy_sats = 50 * 100000000

    def calculate_block_subsidy(self, height: int) -> int:
        """
        Calculates the maximum allowable block subsidy in satoshis for a given block height.
        Emulates Bitcoin Core's C++ bitwise right-shift operator (>>).
        """
        # Calculate how many halvings have occurred
        halvings = height // self.blocks_per_epoch

        # In C++, shifting a 64-bit signed integer by 64 or more positions is undefined or 0
        if halvings >= 64:
            return 0

        # Perform C++ style bitwise right-shift division
        # This divides the initial reward by 2^halvings and truncates decimals
        return self.initial_subsidy_sats >> halvings

    def run_supply_simulation(self) -> dict:
        """
        Simulates the entire 33-epoch issuance schedule.
        Calculates the exact total coin supply in Satoshis.
        """
        total_supply_sats = 0
        epoch_details = []

        # Iterate through the 33 valid epochs (Epoch 0 to 32)
        # Epoch 33 drops the reward to 0 satoshis.
        for epoch in range(34):
            # Calculate height at the start of this epoch
            start_height = epoch * self.blocks_per_epoch

            # Query subsidy for a block in this epoch
            subsidy_sats = self.calculate_block_subsidy(start_height)

            # Total blocks mined in this epoch is blocks_per_epoch (210,000)
            blocks_mined = self.blocks_per_epoch

            # Total coins created in this epoch
            epoch_mint = subsidy_sats * blocks_mined
            total_supply_sats += epoch_mint

            epoch_details.append({
                "epoch": epoch,
                "start_height": start_height,
                "subsidy_sats": subsidy_sats,
                "subsidy_btc": subsidy_sats / 1e8,
                "epoch_mint_btc": epoch_mint / 1e8,
                "total_supply_btc": total_supply_sats / 1e8
            })

            # If the subsidy reaches 0, we can stop
            if subsidy_sats == 0:
                break

        return {
            "total_supply_sats": total_supply_sats,
            "total_supply_btc": total_supply_sats / 1e8,
            "epochs": epoch_details
        }

if __name__ == "__main__":
    simulator = BitcoinRewardSimulator()

    print("=== Block Subsidy Query ===")
    test_heights = [100, 210000, 420000, 630000, 840000, 6930000]
    for h in test_heights:
        subsidy = simulator.calculate_block_subsidy(h)
        print(f"[*] Block Height {h:,} -> Subsidy: {subsidy:,} Satoshis ({subsidy / 1e8:.8f} BTC)")

    print("\n=== Programmatic Supply Schedule Simulation ===")
    results = simulator.run_supply_simulation()

    print(f"[*] Total Circulating Supply Cap: {results['total_supply_btc']:,.8f} BTC")
    print(f"[*] Total Satoshis Created:       {results['total_supply_sats']:,} Satoshis\n")

    print("=== Epoch-by-Epoch Issuance Logs ===")
    print(f"{'Epoch':<6} | {'Start Height':<12} | {'Subsidy (BTC)':<15} | {'Coins Created':<15} | {'Circulating Supply':<18}")
    print("-" * 76)
    for ep in results["epochs"][:6]: # Show first 6 epochs
        print(f"{ep['epoch']:<6} | {ep['start_height']:<12,} | {ep['subsidy_btc']:<15.8f} | {ep['epoch_mint_btc']:<15,.4f} | {ep['total_supply_btc']:<18,.4f}")

    print("...")
    # Show the final epochs where bitwise shift division hits the 0 threshold
    for ep in results["epochs"][-3:]:
        print(f"{ep['epoch']:<6} | {ep['start_height']:<12,} | {ep['subsidy_btc']:<15.8f} | {ep['epoch_mint_btc']:<15,.4f} | {ep['total_supply_btc']:<18,.4f}")

As displayed, the simulator calculates block heights, implements bitwise shift boundaries, and proves that Bitcoin's supply ends at exactly $20,999,999.9769\text{ BTC}$ inside Epoch 32.

☕ Help support TeachMeBitcoin

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:

Ethereum: 0x578417C51783663D8A6A811B3544E1f779D39A85
Bitcoin: bc1q77k9e95rn669kpzyjr8ke9w95zhk7pa5s63qzz
Solana: 4ycT2ayqeMucixj3wS8Ay8Tq9NRDYRPKYbj3UGESyQ4J
Address copied to clipboard!