DCP: 0012
Title: Change PoW/PoS Subsidy Split To 1/89
Author: Dave Collins
Jake Yocom-Piatt
Status: Active
Created: 2023-04-13
License: CC0-1.0
License-Code: ISC
Requires: DCP0006
Replaces: DCP0010
==Abstract==
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%.
==Motivation==
This proposal is the result of continued analysis after the previous subsidy
split change made by [[../dcp-0010/dcp-0010.mediawiki|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 [[../dcp-0011/dcp-0011.mediawiki|DCP0011]], is intended break up
the mining cartel and further improve decentralization of the issuance process.
See the [[https://proposals.decred.org/record/a8501bc|Politeia proposal]]
for further details.
==Specification==
===Integer Math===
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.
===Full Block Subsidy Formula===
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)
===Modified Subsidy Split===
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)
Additionally, the resulting PoS subsidy MUST be split evenly between the maximum
number of votes per block, which, as of this specification, is 5 on all
networks.
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)
===Subsidy Enforcement===
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
====Coinbase Rules and DCP0006 Requirement====
The rule regarding the total of the output values of the coinbase transaction
takes into account that [[../dcp-0006/dcp-0006.mediawiki|DCP0006]] is already
active.
==Rationale==
As previously described in
[[../dcp-0010/dcp-0010.mediawiki#rationale|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
While PoW has worked well for almost all of these properties, unfortunately
extensive analysis has shown that the expected results of a fair coin
distribution has not been achieved.
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 [[../dcp-0011/dcp-0011.mediawiki|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.
==Deployment==
===Voting Agenda Parameters===
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||{|
!Choice!!English Description!!Bits
|-
|abstain||abstain voting for change||0x00
|-
|no||keep the existing consensus rules||0x0020 (Bit 5)
|-
|yes||change to the new consensus rules||0x0040 (Bit 6)
|}
|}
===Voting Results===
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
|}
==Compatibility==
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.
==Reference Implementation==
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.
===Full Block Subsidy Calculation===
// 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
}
===Work (PoW) Proportion Subsidy Calculation===
// 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
}
===Stake Vote (PoS) Proportion Subsidy Calculation===
// 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
}
===Pull Requests===
===Subsidy Enforcement===
A reference implementation of the required consensus changes to enforce the new
subsidy split is provided by
[[https://github.com/decred/dcrd/pull/3092|pull request #3092]].
====Deployment====
A reference implementation of the required agenda definition is implemented by
[[https://github.com/decred/dcrd/pull/3090|pull request #3090]].
==Test Vectors==
The following test vectors are provided in order to facilitate testing across
implementations. These are the expected values for mainnet.
===Subsidy Calculations===
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
|}
==Acknowledgements==
===Collaborators===
Thanks to the following individuals who provided valuable feedback during the
review process of this proposal (alphabetical order):
* Jamie Holdstock ([[https://github.com/jholdstock|@jholdstock]])
* Josh Rickmar ([[https://github.com/jrick|@jrick]])
* Matheus Degiovani ([[https://github.com/matheusd|@matheusd]])
==References==
===Additional References===
# [[https://proposals.decred.org/record/a8501bc|Politeia Proposal - Change PoW/PoS Subsidy Split to 1/89 and Change PoW Algorithm to BLAKE3]]
# [[https://proposals.decred.org/record/427e1d4|Politeia Proposal - Change PoW/PoS Subsidy Split From 60/30 to 10/80]]
# [[https://medium.com/@tacorevenge/the-suppressor-part-1-war-of-attrition-3081a61b202b|The Suppressor Part 1: War of Attrition]]
# [[https://medium.com/@tacorevenge/the-suppressor-part-2-on-chain-analysis-6561c5a478c4|The Suppressor Part 2: On-Chain Analysis]]
==Copyright==
This document is licensed under the
[https://creativecommons.org/publicdomain/zero/1.0 CC0-1.0: Creative Commons CC0 1.0 Universal]
license.
The code is licensed under the [https://opensource.org/licenses/ISC ISC License].