DCP: 0012 Title: Change PoW/PoS Subsidy Split To 1/89 Author: Dave Collins <[email protected]> Jake Yocom-Piatt Status: Active Created: 2023-04-13 License: CC0-1.0 License-Code: ISC Requires: DCP0006 Replaces: DCP0010
This specifies modifications to the block reward subsidy split such that 1% goes to Proof-of-Work (PoW) and 89% goes to Proof-of-Stake (PoS). The Treasury subsidy remains at 10%.
This proposal is the result of continued analysis after the previous subsidy split change made by DCP0010 which shows that the majority of the PoW hash power continues to be highly centralized and used to maliciously manipulate Decred markets.
The proposed modification, in tandem with changing the PoW hashing function as described in DCP0011, is intended break up the mining cartel and further improve decentralization of the issuance process.
See the Politeia proposal for further details.
In order to facilitate better compatibility across implementations and languages, the formulas defined by the specification make use of integer math instead of floating point math as denoted by the use of the floor function. This is highly desirable for consensus code since floating point math can be problematic across languages due to issues such as rounding errors and uncertainty in their respective libraries.
The calculated full subsidy for each block MUST remain the same as it is prior to this specification. Since calculation of the modified subsidy proportions for PoW and PoS relies on first calculating the full subsidy, the details of the existing calculation are also provided in this specification.
Explanation of terms:
Sfull = The full block subsidy at a given height
h = The height for which the full subsidy is to be calculated
P = The coins generated by the first block (1,680,000 X 108 on mainnet
)
I = The number of blocks in the subsidy reduction interval (6144 on mainnet
)
c0 = The base coin subsidy before any reductions (3,119,582,664 on mainnet
)
Rm = The coin subsidy reduction multiplier (100 on mainnet
)
Rd = The coin subsidy reduction divisor (101 on mainnet
)
The subsidy split for the full block subsidy MUST be split between Proof-of-Work (PoW), Proof-of-Stake (PoS), and the decentralized Treasury as follows:
- PoW - 1%
- PoS - 89%
- Treasury - 10% (no change from existing)
The Treasury subsidy proportion MUST remain the same and otherwise retain all existing semantics it has prior to this specification.
The following formulas precisely specify the calculations for the modified
subsidy splits for arbitrary heights. This ensures the semantics are fully
specified for all heights; however, it is important to note that they MUST
only be applied to mainnet
, and current testnet
, for
heights where the new rules are active per the associated on-chain vote.
Explanation of terms:
Sfull = The full block subsidy at a given height
Spow = The subsidy for proof of work at a given height for a given number of votes
Svote = The subsidy for a single vote at a given height
h = The height for which the subsidy is to be calculated
v = The number of votes included in the block
Hsv = The height at which stake validation begins (4096 on mainnet
)
vb = The number of votes per block (5 on all networks)
vm = The minimum number of required votes (3 on all networks)
IMPORTANT: The PoS subsidy, and hence each individual vote subsidy, is based on the block PRIOR to the one that contains the vote since that prior block is the one being voted on. In practice, this means the formula to calculate the vote subsidy MUST be called with a height of one less than the PoW subsidy formula once the height that voting begins at is reached.
The following modified rules MUST be enforced:
- The input value of the one and only input of the coinbase transaction MUST commit to the modified PoW subsidy proportion
- The total of the output values of the coinbase transaction MUST NOT exceed the modified PoW subsidy proportion plus the total fees from all transactions contained in the block
- The input value of the stakebase of vote transactions MUST commit to the modified single vote subsidy proportion
- The proportional payouts of vote transactions MUST be calculated based on the modified single vote subsidy proportion
- The total of the output values of vote transactions MUST NOT exceed modified single vote subsidy proportion
The rule regarding the total of the output values of the coinbase transaction takes into account that DCP0006 is already active.
As previously described in the Rationale section of DCP0010, Proof of Work is intended to provide several key properties to Decred, some of which are:
- Unambiguous determination of the exact contents of a block
- Unforgeable historical timestamps
- A source of entropy
- Significantly increased cost to conduct a wide variety of attacks
- Protection against data manipulation and double spends
- Fair coin distribution
A commonly overlooked aspect of PoW mining is that it has to behave similarly to gold mining in order for it to achieve the expected results of a fair coin distribution. That is the reason the process is referred to as mining.
More concretely, the price is expected to track the cost of production such that, as the profitability goes up, the incentives for competition also go up which leads to more participants (hash power) and thus profitability reduces accordingly.
It is clear from further analysis that the previous adjustments to lower the PoW subsidy did not go far enough to achieve that expected result as evidenced by noting that despite the expected drop in the hash power relative to the levels prior to the previous adjustment, the same degree of PoW centralization is still present.
Moreover, it is extremely unlikely that further lowering the PoW subsidy in isolation will be able to spur increased decentralization because the specialized hardware the existing monopoly uses to mine was paid off from mining income long ago. Additionally, a lower subsidy makes the creation of any new specialized hardware that would be needed to break up the monopoly even less likely.
Therefore, the best remaining reasonable option is to both change the PoW hashing algorithm in order to obsolete the existing specialized hardware (defined in DCP0011) and simultaneously lower the subsidy even further per this specification. These two modifications in tandem are intended to break up the mining cartel and avoid continuing to overpay for what PoW provides under the new PoW hashing algorithm.
This approach allows Decred to retain the positive parts of PoW, like it being an entropy source and providing unforgeable costliness and irreversibility.
This proposal will be deployed to mainnet using the standard Decred on-chain voting infrastructure as follows:
Name | Setting | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Deployment Version | 10 | ||||||||||||
Agenda ID | changesubsidysplitr2 | ||||||||||||
Agenda Description | Change block reward subsidy split to 1/89/10 as defined in DCP0012 | ||||||||||||
Start Time | 1682294400 (Apr 24th, 2023 00:00:00 +0000 UTC) | ||||||||||||
Expire Time | 1745452800 (Apr 24th, 2025 00:00:00 +0000 UTC) | ||||||||||||
Mask | 0x0060 (Bits 5 and 6) | ||||||||||||
Choices |
|
This proposal was approved by the stakeholder voting process and is now active.
Status | Block Hash | Block Height |
---|---|---|
Voting Started | 0000000000000000d608dc4ec7fcae5c650353db68a77f2954df74c25462f337 | 778240 |
Locked In | 0000000000000000896042b2b0536a4046e56ef505f20f7301ca7e042a5c218e | 786304 |
Active | 071683030010299ab13f139df59dc98d637957b766e47f8da6dd5ac762f1e8c7 | 794368 |
This is a hard-forking change to the Decred consensus. This means that once the agenda is voted in and becomes locked in, anybody running code that fully validates blocks must upgrade before the activation time or they will reject all blocks containing transactions with payouts that conform to the new subsidy split since they are invalid under the old rules.
Other software that performs full validation will need to modify their consensus enforcement rules accordingly and any software that creates coinbases or votes will need to be updated to handle the changes specified herein.
The following implementations are simplified versions intended to clearly illustrate the exact semantics of this specification with self-contained functions. See the linked pull request for the full implementations that include optimizations and the ability to selectively calculate both the legacy subsidy proportions as well as the new ones defined herein.
// calcBlockSubsidy returns the max potential subsidy for a block at the
// provided height. This value is reduced over time based on the height and
// then split proportionally between PoW, PoS, and the Treasury.
func calcBlockSubsidy(height int64) int64 {
// These parameters are ordinarily unique per chain and thus should be
// passed into the function via a chain parameters structure, however,
// they are defined as constants with the mainnet parameters here for the
// purposes of providing a self-contained function for the DCP.
const (
mainnetBlockOneSubsidy = 1680000 * 100000000
mainnetSubsidyReductionInterval = 6144
mainnetBaseSubsidy = 3119582664
mainnetSubsidyReductionMultiplier = 100
mainnetSubsidyReductionDivisor = 101
)
// Negative block heights are invalid and produce no subsidy.
// Block 0 is the genesis block and produces no subsidy.
// Block 1 subsidy is special as it is used for initial token distribution.
switch {
case height <= 0:
return 0
case height == 1:
return mainnetBlockOneSubsidy
}
// Calculate the subsidy by applying the appropriate number of reductions
// per the requested height.
reductions := height / mainnetSubsidyReductionInterval
subsidy := int64(mainnetBaseSubsidy)
for i := int64(0); i < reductions; i++ {
subsidy *= mainnetSubsidyReductionMultiplier
subsidy /= mainnetSubsidyReductionDivisor
// Stop once no further reduction is possible. This ensures a bounded
// computation for large requested intervals and that all future
// requests for intervals at or after the final reduction interval
// return 0 without recalculating.
if subsidy == 0 {
break
}
}
return subsidy
}
// calcWorkSubsidyDCP0012 returns the proof of work subsidy for a block at the
// provided height and given number of votes using the round 2 modified subsidy
// split.
func calcWorkSubsidyDCP0012(height int64, voters uint16) int64 {
// These parameters are ordinarily unique per chain and thus should be
// passed into the function via a chain parameters structure, however,
// they are defined as constants with the mainnet parameters here for the
// purposes of providing a self-contained function for the DCP.
const (
mainnetStakeValidationHeight = 4096
votesPerBlock = 5
minVotesRequired = 3 // aka (votesPerBlock / 2) + 1
)
// The first block has special subsidy rules.
if height == 1 {
return calcBlockSubsidy(height)
}
// The subsidy is zero if there are not enough voters once voting begins. A
// block without enough voters will fail to validate anyway.
if height >= mainnetStakeValidationHeight && voters < minVotesRequired {
return 0
}
// Calculate the full block subsidy and reduce it according to the PoW
// proportion.
const proportion = 1
const totalProportions = 100
subsidy := calcBlockSubsidy(height)
subsidy *= proportion
subsidy /= totalProportions
// Ignore any potential subsidy reductions due to the number of votes prior
// to the point voting begins.
if height < mainnetStakeValidationHeight {
return subsidy
}
// Adjust for the number of voters.
return (int64(voters) * subsidy) / votesPerBlock
}
// calcStakeVoteSubsidyDCP0012 returns the subsidy for a single stake vote for a
// block at the provided height using the round 2 modified subsidy split.
func calcStakeVoteSubsidyDCP0012(height int64) int64 {
// These parameters are ordinarily unique per chain and thus should be
// passed into the function via a chain parameters structure, however,
// they are defined as constants with the mainnet parameters here for the
// purposes of providing a self-contained function for the DCP.
const (
mainnetStakeValidationHeight = 4096
votesPerBlock = 5
)
// Votes have no subsidy prior to the point voting begins. The minus one
// accounts for the fact that vote subsidies are based on the height that is
// being voted on as opposed to the block in which they are included.
if height < mainnetStakeValidationHeight-1 {
return 0
}
// Calculate the full block subsidy and reduce it according to the stake
// proportion. Then divide it by the number of votes per block to arrive
// at the amount per vote.
const proportion = 89
const totalProportions = 100
subsidy := calcBlockSubsidy(height)
subsidy *= proportion
subsidy /= (totalProportions * votesPerBlock)
return subsidy
}
A reference implementation of the required consensus changes to enforce the new subsidy split is provided by pull request #3092.
A reference implementation of the required agenda definition is implemented by pull request #3090.
The following test vectors are provided in order to facilitate testing across
implementations. These are the expected values for mainnet
.
All subsidy values are in atoms.
Height | Num Votes | Full Subsidy | Work Subsidy | Vote Subsidy | Notes |
---|---|---|---|---|---|
-1 | 0 | 0 | 0 | 0 | negative height, invalid |
0 | 0 | 0 | 0 | 0 | genesis block |
1 | 0 | 168000000000000 | 168000000000000 | 0 | initial payouts |
2 | 0 | 3119582664 | 31195826 | 0 | first non-special block prior voting start |
4094 | 0 | 3119582664 | 31195826 | 0 | two blocks prior to voting start |
4095 | 0 | 3119582664 | 31195826 | 555285714 | final block prior to voting start |
4096 | 5 | 3119582664 | 31195826 | 555285714 | voting start, 5 votes |
4096 | 4 | 3119582664 | 24956660 | 555285714 | voting start, 4 votes |
4096 | 3 | 3119582664 | 18717495 | 555285714 | voting start, 3 votes |
4096 | 2 | 3119582664 | 0 | 555285714 | only 2 votes, invalid block |
6143 | 5 | 3119582664 | 31195826 | 555285714 | final block prior to 1st reduction |
6144 | 5 | 3088695706 | 30886957 | 549787835 | 1st block in 1st reduction, 5 votes |
6144 | 4 | 3088695706 | 24709565 | 549787835 | 1st block in 1st reduction, 4 votes |
12287 | 5 | 3088695706 | 30886957 | 549787835 | last block in 1st reduction |
12288 | 5 | 3058114560 | 30581145 | 544344391 | 1st block in 2nd reduction |
307200 | 5 | 1896827356 | 18968273 | 337635269 | 1st block in 50th reduction, 5 votes |
307200 | 3 | 1896827356 | 11380963 | 337635269 | 1st block in 50th reduction, 3 votes |
10401792 | 5 | 99 | 0 | 17 | first zero work subsidy 1693rd reduction |
10979328 | 5 | 5 | 0 | 0 | first zero vote subsidy 1787th reduction |
11010048 | 5 | 0 | 0 | 0 | first zero full subsidy 1792nd reduction |
Thanks to the following individuals who provided valuable feedback during the review process of this proposal (alphabetical order):
- Jamie Holdstock (@jholdstock)
- Josh Rickmar (@jrick)
- Matheus Degiovani (@matheusd)
- Politeia Proposal - Change PoW/PoS Subsidy Split to 1/89 and Change PoW Algorithm to BLAKE3
- Politeia Proposal - Change PoW/PoS Subsidy Split From 60/30 to 10/80
- The Suppressor Part 1: War of Attrition
- The Suppressor Part 2: On-Chain Analysis
This document is licensed under the CC0-1.0: Creative Commons CC0 1.0 Universal license.
The code is licensed under the ISC License.