Repository navigation
T.Softfork: Long coinbase maturity (part 2 of 3): extend from 45 days to 1 year #429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 29.x-knots
Are you sure you want to change the base?
Changes from all commits
8ca5fd9
01cc968
c2a9406
a7bc9db
bb9d7de
6d1b070
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| Long coinbase maturity: one year, expiring with RDTS | ||
| ---------------------------------------------------- | ||
|
|
||
| The temporary softfork that Bitcoin Knots 29.4.2 deployed to hold generated bitcoins for longer is extended: instead of ending at block 979920, it expires together with RDTS. Bitcoins generated by block 973440 or any later block cannot be spent in any block whose parent has a median time past earlier than 2027 September 1st 00:00 UTC. From the first block past that, they are spendable at the original maturity of 100 blocks. | ||
|
|
||
| This is a softfork on top of 29.4.2. Up to block 979919 the rules are the same, so nothing changes until then. Block 979920 is the first that 29.4.2 could accept and this version reject (one spending bitcoins generated since block 973440), so miners and nodes need to upgrade before it, expected around the end of October at the current block rate (the date moves with the hashrate). | ||
|
|
||
| A 29.4.2 node that upgrades only after block 979920 rechecks the blocks it connected from that height on at its first start: it rewinds to block 979919 and reconnects everything above it. A node coming from 29.4.1 or from another implementation has no record of having checked the long maturity rule at all, so it rewinds to block 973439 instead, as it would when upgrading to 29.4.2. Either way the rewind needs the block and undo data of those blocks, so a pruned node that upgrades late may have to reindex. Upgrading before block 979920 avoids all of this. | ||
|
|
||
| Policy and the wallet now apply the same delay to every coin generated by block 973440 or later, measured in time rather than in blocks: the mempool does not relay a spend of such a coin until the median time past of the chain tip is at least one year (365 days) past that of the block that generated it, and the wallet counts the coin as immature until then. Coins generated before block 973440 need only the original maturity of 100 blocks; 29.4.2 policy held them for 6480 blocks, which they all reach by block 979919. For the covered coins this is never sooner than the consensus expiry, which the mempool also enforces directly, so a wallet holding them can no longer select one that consensus would still reject. The GUI shows how many days such a coin still has to wait; the number of blocks to maturity shown for it elsewhere is an estimate, updated with every block. | ||
|
|
||
| A spend held by the consensus rule is rejected as `bad-txns-premature-spend-of-coinbase-long` and one held by the policy delay as `premature-spend-of-coinbase-long`; the original 100-block rule keeps `bad-txns-premature-spend-of-coinbase`. | ||
|
|
||
| `getdeploymentinfo` reports the expiry as `expiry_time` for `long_coinbase_maturity`, the same field RDTS uses, and no longer reports `height_end` or `maturity` for it. The regtest option `-testcoinbasematuritylong` now takes `<start_height>:<enforce_height>:<expiry_time>`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,10 +79,14 @@ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits | |
|
|
||
| static void AddLongCoinbaseMaturityRevalidationDeployment(Consensus::Params& consensus) | ||
| { | ||
| // The rule expires by time, so the last height it applies to depends on | ||
| // the chain: every block from the enforce height on may need checking. | ||
| // Blocks keep being marked as checked under this name after the expiry, | ||
| // so an extension of the rule needs a new deployment name. | ||
| consensus.chainstate_revalidation_deployments.push_back({ | ||
| .name = "long_coinbase_maturity", | ||
| .start_height = consensus.CoinbaseMaturityLongEnforceHeight, | ||
| .stop_height = consensus.CoinbaseMaturityLongReleaseHeight - 1, | ||
| .stop_height = std::numeric_limits<int>::max(), | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will keep flagging blocks as checked long after they actually stop getting checked... I suppose it's acceptable if there's no better way, but it means any extension would need a new name.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, and the comment now says so: blocks keep being marked as checked under this name after the expiry, so an extension of the rule needs a new deployment name. A stop time next to the stop height in the revalidation framework would be the cleaner way if we ever need it; I did not want to touch the framework in this PR. |
||
| }); | ||
| } | ||
|
|
||
|
|
@@ -140,10 +144,10 @@ class CMainParams : public CChainParams { | |
| // reaching ACTIVE, and that deployment has been removed.) | ||
| consensus.RdtsExpiryTime = 1819756800; // September 1st, 2027 00:00 UTC | ||
|
|
||
| // Long coinbase maturity: held until RDTS expires | ||
| consensus.CoinbaseMaturityLongStartHeight = 973440; | ||
| consensus.CoinbaseMaturityLongEnforceHeight = 973440; | ||
| consensus.CoinbaseMaturityLongReleaseHeight = 979920; | ||
| consensus.CoinbaseMaturityLong = consensus.CoinbaseMaturityLongReleaseHeight - consensus.CoinbaseMaturityLongStartHeight; | ||
| consensus.CoinbaseMaturityLongReleaseTime = consensus.RdtsExpiryTime; | ||
| AddLongCoinbaseMaturityRevalidationDeployment(consensus); | ||
|
|
||
| consensus.nMinimumChainWork = uint256{"00000000000000000000000000000000000000013e00277374c9f9eeadc70200"}; | ||
|
|
@@ -419,10 +423,10 @@ class CTestNet4Params : public CChainParams { | |
| consensus.Blake2bHeight = 150308; | ||
| consensus.RdtsExpiryTime = 1791903600; // October 13th, 2026 15:00:00 UTC | ||
|
|
||
| // Long coinbase maturity: held until RDTS expires | ||
| consensus.CoinbaseMaturityLongStartHeight = 151406; | ||
| consensus.CoinbaseMaturityLongEnforceHeight = 151550; | ||
| consensus.CoinbaseMaturityLongReleaseHeight = 158111; | ||
| consensus.CoinbaseMaturityLong = consensus.CoinbaseMaturityLongReleaseHeight - consensus.CoinbaseMaturityLongStartHeight; | ||
| consensus.CoinbaseMaturityLongReleaseTime = consensus.RdtsExpiryTime; | ||
| AddLongCoinbaseMaturityRevalidationDeployment(consensus); | ||
|
|
||
| consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000001d6dce8651b6094e4c1"}; | ||
|
|
@@ -689,8 +693,7 @@ class CRegTestParams : public CChainParams | |
| if (opts.coinbase_maturity_long_start_height) { | ||
| consensus.CoinbaseMaturityLongStartHeight = *opts.coinbase_maturity_long_start_height; | ||
| consensus.CoinbaseMaturityLongEnforceHeight = *opts.coinbase_maturity_long_enforce_height; | ||
| consensus.CoinbaseMaturityLongReleaseHeight = *opts.coinbase_maturity_long_release_height; | ||
| consensus.CoinbaseMaturityLong = consensus.CoinbaseMaturityLongReleaseHeight - consensus.CoinbaseMaturityLongStartHeight; | ||
| consensus.CoinbaseMaturityLongReleaseTime = *opts.coinbase_maturity_long_release_time; | ||
| AddLongCoinbaseMaturityRevalidationDeployment(consensus); | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With no stop height, a node with no marker takes the enforce height as its rewind target, so a late upgrade rewinds from wherever its tip is and that cost grows without bound.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stop height doesn't set the rewind. It always runs from the tip down to the lowest block the node's marker doesn't cover, so a node with no marker rewinds to 973439 with or without a stop height, exactly as it would upgrading to 29.4.2, and a 29.4.2 node rewinds to 979919 either way. What bounds the cost is upgrading before 979920, where nothing needs rechecking.