Skip to content

Rolling maturity: end coverage at RDTS expiry instead of height 6930000 - #3

Closed
Kilombino wants to merge 3 commits into
satoshipuzzles:rolling-coinbase-maturity-1yfrom
Kilombino:rolling-1y-rdts-expiry
Closed

Kilombino wants to merge 3 commits into
satoshipuzzles:rolling-coinbase-maturity-1yfrom
Kilombino:rolling-1y-rdts-expiry

Conversation

@Kilombino

Copy link
Copy Markdown

This is a proposal on top of bitcoinknots#476. It keeps the 1-year rolling maturity
exactly as it is, but makes the coverage stop when RDTS expires instead of
running until the first zero-subsidy height.

The rule after this change, on mainnet:

  • From block 979920, a coinbase mined at height 973440 or later needs 52560
    confirmations, counted from its own block. Unchanged.
  • A coinbase is covered only if it was mined while RDTS was still in force:
    the parent of the block that mined it has a median-time-past before
    RdtsExpiryTime (1819756800, 2027-09-01 00:00 UTC).
  • A coinbase covered before the expiry keeps its full 52560 blocks after the
    date passes. Nothing is released early.
  • Coinbases mined after the expiry go back to 100.

The boundary is the same one bitcoinknots#468 uses, taken from its
Consensus::CoinbaseMaturityLongEndHeight: the first uncovered height is the
first block whose parent's median-time-past has reached the expiry, searched on
the branch being validated, not on the active chain. It is also the boundary
RDTS uses for its own rules. With this, bitcoinknots#468 and bitcoinknots#476 disagree only on the
maturity depth (25920 vs 52560) and on the 973440–979918 rewards, not on when
coverage ends. If RDTS is extended, the coverage follows the new expiry.

Why: the long maturity is a defence for the RDTS period. Tied to 6930000 it locks every reward for a year for the next century. Ending it with RDTS keeps the protection while it's needed, and extending it later is a soft fork.

Changes:

  • CoinbaseMaturityRollingEndCoinHeight is replaced by
    CoinbaseMaturityRollingUntilRdts. Consensus::CoinbaseMaturityRollingEndHeight
    computes the first uncovered height; ConnectBlock, mempool acceptance and
    reorg eviction pass it to CheckTxInputs, and the wallet/GUI maturity uses
    it from the active chain.
  • getdeploymentinfo drops the fixed coinbase_end_height and reports
    coinbase_expiry_time (same name T.Softfork: consensus: 180-day rolling coinbase maturity from height 979919 until RDTS expiry bitcoinknots/bitcoin#468 uses). Once the queried block has
    reached the expiry it also reports coinbase_end_height, the last covered
    reward.
  • Regtest: the fourth field of -testcoinbasematurityrolling is gone;
    -testcoinbasematurityrollingexpiry=<time> binds the rule to an RDTS expiry
    (it must match -rdtsexpiry if both are set), like T.Softfork: consensus: 180-day rolling coinbase maturity from height 979919 until RDTS expiry bitcoinknots/bitcoin#468's
    -testcoinbasematuritylongexpiry.
  • Unit tests: mainnet schedule, regtest options, and a new
    rolling_maturity_rdts_end_height case on a synthetic chain that checks the
    boundary block and that it moves by one block when the expiry moves by one
    second.
  • feature_rolling_maturity_end_bound.py now mines with fixed timestamps so
    the expiry falls on a known block, and checks the last covered reward, the
    first uncovered one, and that a covered reward still needs its full depth
    long after the expiry. mempool_rolling_coinbase_maturity.py is updated for
    the new option.
  • Release note fragment updated.

Testing done: the full unit test suite (146/146 via ctest), the touched and
related functional tests (feature_rolling_maturity_end_bound,
mempool_rolling_coinbase_maturity, mempool_long_coinbase_maturity,
feature_chainstate_revalidation, rpc_blockchain, mining_basic, mempool_reorg,
wallet_balance and others), and a separate regtest script checking blocks and
mempool on both sides of the boundary, with and without the long window.

Commits:

  • 52be66a consensus: End rolling maturity coverage when RDTS expires
  • e80d75c test: Cover the RDTS expiry boundary of rolling maturity
  • 7d249ec doc: Describe the RDTS expiry of rolling maturity in the release note

Happy to change names or split it differently if you prefer.

Replace the fixed end coin height (6930000) with the RDTS expiry, using
the boundary knots#468 uses: a coinbase is covered only if the parent of
the block that mined it has a median-time-past before RdtsExpiryTime.
Expiry only ends coverage of new rewards; a reward covered before it
still needs the full 52560 blocks.

The first uncovered height is found on the spending branch with the
same search as bitcoin#468's CoinbaseMaturityLongEndHeight, and passed to
CheckTxInputs in ConnectBlock, mempool acceptance and reorg eviction.
Wallet and GUI maturity use it from the active chain.

getdeploymentinfo replaces coinbase_end_height (fixed) with
coinbase_expiry_time, and reports coinbase_end_height once the queried
block has reached the expiry. On regtest, the fourth field of
-testcoinbasematurityrolling is replaced by
-testcoinbasematurityrollingexpiry=<time>, which must match -rdtsexpiry
if both are given.
feature_rolling_maturity_end_bound mines blocks with fixed timestamps so
the expiry lands on a known block, and checks the last covered reward,
the first uncovered one, and that a covered reward keeps its full depth
long after the expiry. mempool_rolling_coinbase_maturity drops the end
coin height cases and checks the new option's errors.
@Kilombino

Copy link
Copy Markdown
Author

Closing this: we are going with the 180-day rule from bitcoinknots#468 that is already in the rc. Thanks!

@Kilombino Kilombino closed this Oct 25, 2026
@Kilombino
Kilombino deleted the rolling-1y-rdts-expiry branch October 25, 2026 00:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant