1. What is being audited
| ID | Invariant |
|---|---|
| C-1 | Block subsidy halves at every 210 000 blocks (mainnet) |
| C-2 | Sum of all subsidies converges to 20 999 999.97690000 B3C |
| C-3 | Subsidy returns exactly 0 once halvings ≥ 64 |
| C-4 | Difficulty retarget enforces the 4× lower / upper bounds |
2. Why it matters
The 21M cap is the most-quoted property of Bitcoin. If a single line
of GetBlockSubsidy() in src/validation.cpp is
miscoded, the whole supply schedule breaks — and unlike a UI bug
you can never undo it once anyone has used the chain. The audit is
short, but it is the kind of bug that has bitten other forks (and one
that an external auditor will absolutely check first), so we test it
with both an analytic argument and live mining on regtest across four
halvings.
3. The math
The subsidy at height h on a chain with halving interval
I is:
subsidy(h) = (50 * COIN) >> floor(h / I)
Total supply is the geometric series:
S = I * sum_{n=0}^{63} (50 * COIN) >> n
= 50 * COIN * I * (2 - 2^-63)
≈ 21 000 000 * COIN
For mainnet (I = 210 000) the exact value is
2 099 999 997 690 000 satoshi
(= 20 999 999.97690000 B3C).
4. How to run
cd b3chain python3 contrib/testing/audit/audit-supply-cap.py
5. Expected output
[C-1..C-4] Supply cap and halving schedule ======================================================================== PASS [C-2] geometric sum at mainnet interval (210000) equals 20999999.97690000 PASS [C-3] subsidy returns 0 at halving 64 PASS [C-4] CalculateNextWorkRequired retains the 4x retarget bounds Spawning regtest node and mining 600 blocks (4 halvings)... PASS [C-1] subsidy at height 1 (halving 0) = 50.00000000 B3C PASS [C-1] subsidy at height 151 (halving 1) = 25.00000000 B3C PASS [C-1] subsidy at height 301 (halving 2) = 12.50000000 B3C PASS [C-1] subsidy at height 451 (halving 3) = 6.25000000 B3C PASS [C-2] cumulative subsidy through height 600: 14015.62500000 B3C (matches analytic sum) PASS [C-1] subsidy halving schedule observed across 4 halvings on regtest ------------------------------------------------------------------------ 9/9 checks passed in 11.7s AUDIT RESULT: PASS [C-1..C-4]
6. Common pitfalls
- Right-shift ≥ 64. In C/C++,
x >> 64on a 64-bit type is undefined behaviour. The Bitcoin Core implementation guards this withif (halvings >= 64) return 0;. Removing the guard looks innocuous and is a classic fork-killer. - Off-by-one halving boundaries. The first block paying the
new (halved) subsidy is at exactly
I, notI − 1. The audit samples blockI + 1for each halving epoch to catch this. - Coinbase fees vs subsidy. Block reward = subsidy + fees. The audit only mines empty blocks, so coinbase value equals the subsidy exactly.
7. Source files
The problem in one sentence
Once a chain emits more than its declared supply, you cannot un-issue the excess; this is the single most reputation-defining bug a fork can ship.
The theory
Bitcoin's supply formula is a geometric series:
\[ S = I \cdot \sum_{n=0}^{63} \lfloor (50 \cdot 10^8) / 2^n \rfloor \]
where I is the halving interval (210000 blocks on mainnet) and the sum is truncated at n = 63 because the C++ expression (50 * COIN) >> 64 on a 64-bit type is undefined behaviour. The guard if (halvings >= 64) return 0; is not optional; it changes the answer on most compilers.
For B3Chain, all parameters are inherited unchanged. The cap evaluates to 2099999997690000 satoshi exactly = 20999999.97690000 B3C.
Hands-on demo
python3 contrib/testing/audit/audit-supply-cap.py
Expected output:
[C-1..C-4] Supply cap and halving schedule ======================================================================== PASS [C-2] geometric sum at mainnet interval (210000) equals 20999999.97690000 PASS [C-3] subsidy returns 0 at halving 64 PASS [C-4] CalculateNextWorkRequired retains the 4x retarget bounds Spawning regtest node and mining 600 blocks (4 halvings)... PASS [C-1] subsidy at height 1 (halving 0) = 50.00000000 B3C PASS [C-1] subsidy at height 151 (halving 1) = 25.00000000 B3C ... AUDIT RESULT: PASS [C-1..C-4]
Exercise
Open src/validation.cpp and locate GetBlockSubsidy(). Remove the >= 64 guard, rebuild, re-run the audit. You should see C-3 fail with a non-zero subsidy at high heights.
// Before if (halvings >= 64) return 0; // After (introduces UB) // (deleted)
Expected new output (compiler-dependent — gcc tends to wrap, clang often optimises to 0 anyway):
FAIL [C-3] subsidy at halving 64 returned 50.00000000 B3C, expected 0 AUDIT RESULT: FAIL [C-1..C-4]
This is exactly the kind of "looks like it works in your tests" bug that has bitten other forks. The audit catches it.
Further reading
- Bitcoin Core PR for the original guard:
github.com/bitcoin/bitcoin/blob/master/src/validation.cpp
- Bitcoin Talk thread on the geometric-series cap (Satoshi 2010):
bitcointalk.org/index.php?topic=583.0
- C++ standard on undefined right-shift (ISO/IEC 14882:2017 §8.7):
open-std.org/jtc1/sc22/wg21/