consensus: bump COINBASE_MATURITY 10 → 240 — activate at 1,055,555 #32
Labels
No labels
enhancement
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
SubGeniusFinance/Offerings-to-Cthulhu#32
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Tighten coinbase-spend maturity from 10 to 240 blocks so it sits comfortably above the existing
MAX_REORG_DEPTH=100finality guard. At 60s blocks: 10 minutes → 4 hours.Flagged by @9019x on 2026-06-14 with a 💀 — credited as one of the headline structural issues in the codebase. (His original priority list also includes BIP66, BIP65, BIP32/39/44 HD wallets, Electrum-server, libnatpmp migration — separate issues.)
Problem
At 60s block target ×
COINBASE_MATURITY=10, a coinbase becomes spendable after 10 minutes.MAX_REORG_DEPTH=100(src/pow.h:31, enforced insrc/main.cpp:2522) allows legal reorgs up to 99 blocks deep. The two are mis-tuned relative to each other: an attacker who triggers a legal 90-block reorg can invalidate a coinbase that has already matured, been spent, and seen its descendant tx confirm 50+ blocks deep. The cascade invalidates every downstream tx that touched the coinbase output.For coinbase maturity to be a real invariant — "if you can spend it, the chain has finalized the underlying coinbase" — maturity must exceed
MAX_REORG_DEPTH. 240 is a 140-block buffer past the reorg ceiling.Comparator chains: Bitcoin 100 / Litecoin 100 / Dogecoin 30 (60s blocks). OFF at 10 is the structural outlier.
Constants
COINBASE_MATURITY_LEGACYCOINBASE_MATURITY_HARDENEDMAX_REORG_DEPTH.HARDFORK_COINBASE_MAT_MAIN_OFFHARDFORK_COINBASE_MAT_TESTNET_OFFWhy activate at 1,055,555 (post-freeze, bundled with #6)
Original draft placed activation at h=1,025,000 inside the OFFSIG window, on the "Conclave-only mining → zero split risk" rationale. Revised 2026-06-16 to honor the feature-freeze policy in #20, which prohibits merging consensus changes to
mainbetween h=998,000 and h=1,050,667. Activation moves to the post-freeze slot.Why 1,055,555 specifically:
Trade vs the original mid-OFFSIG activation: outsider miners can in principle produce blocks between h=1,050,667 and h=1,055,555 under the old rule. The freeze-end upgrade-coordination announcement closes that gap. A 3.4-day lead time is short but standard for post-freeze coordination on a small chain.
Files touched
src/main.h— replaceCOINBASE_MATURITYconstant withCOINBASE_MATURITY_LEGACY+COINBASE_MATURITY_HARDENED.src/pow.h— addHARDFORK_COINBASE_MAT_MAIN_OFF/HARDFORK_COINBASE_MAT_TESTNET_OFFconstants next to the LWMA-3 fork heights.src/main.cpp— new helperint GetCoinbaseMaturity(int nHeight); swap consensus site atCheckInputs()line 1888 (nSpendHeight - coins.nHeight < GetCoinbaseMaturity(nSpendHeight)); swap wallet site atCMerkleTx::GetBlocksToMaturity()line 1022.src/checkpoints.cpp— sync-checkpoint distance at line 500 callsGetCoinbaseMaturity(chainActive.Tip()->nHeight).src/qt/transactiondesc.cpp— GUI string at line 251 callsGetCoinbaseMaturity(chainActive.Height()) + 1(existing%1interpolation auto-updates).Approx 30 LoC total.
Semantics
The new rule applies to any spend at
nSpendHeight ≥ HARDFORK_COINBASE_MAT_MAIN_OFF, regardless of when the coinbase was mined. A holder with a 50-block-old coinbase from h=1,055,505 attempting to spend at h=1,055,556 has the tx rejected until h=1,055,745 (the coinbase reaches its new 240-block maturity). Mild brief inconvenience; no permanent loss.Pre-fork: behavior unchanged (10-block maturity).
Test plan
qa/rpc-tests/with a scenario that mines pastHARDFORK_COINBASE_MAT_TESTNET_OFF=100, attempts to spend a 10-block-old coinbase, expects mempool rejectbad-txns-premature-spend-of-coinbase.v2.0.x-rc-cbmattag with testnet activation at h=100. Mine across the fork height, confirm legacy maturity pre-fork and hardened maturity post-fork on the same node.transactiondesc.cppdisplays "240 blocks" post-fork in the GUI.Risks / mitigations
Process
Bundle into
v2.0.x-rc-bipsoftwith #33 and #34. All three rules shareHARDFORK_*_MAIN_OFF = 1,055,555. Cut tag with testnet activation at h=100; live-test on testnet for ~3 days; promote to mainnet activation tag once green. Branch development onfeat/v2.0.x-rc-bipsoft; merge tomainafter freeze-end (post h=1,050,667).Community chat for live discussion: https://23skidoo.info/discord
Activation milestone (to add to WHERE_WE_LEFT_OFF.md)
coinbase maturity 10 → 240: h=1,055,555 (bundled in v2.0.x-rc-bipsoft)References
src/main.h:60— currentCOINBASE_MATURITY = 10src/main.cpp:1888— consensus enforcement (CheckInputs)src/pow.h:31—MAX_REORG_DEPTH = 100src/main.cpp:2504-2532—MAX_REORG_DEPTHenforcement inActivateBestChain(v2.0.0-rc3, gated on LWMA-3)src/chainparams.cpp:183—nOpenMiningHeight = 1050666(OFFSIG window end)Live on mainnet. Activated on schedule at h=1,055,555 (2026-07-23), block
00000000438cf73291060c7c2caeadd568b7e432c192f4f44b3d84eafb157c7c.Coinbase maturity is now 240 blocks (~4 hours at target spacing) — newly mined OFF stays locked well past any permitted reorg (
MAX_REORG_DEPTH=100), closing the counterfeit-spend mechanics of 2018. ~5,800 blocks mined under the rule since activation with zero incident; the mixed-version soak (v2.0.8.7 / v2.0.9 / v2.1.0-rc) remains fork-free at delta 0.Shipped in v2.0.9-Eldersign. The wards hold. Closing.