mirror of https://github.com/zcash/zips.git
317 lines
13 KiB
ReStructuredText
317 lines
13 KiB
ReStructuredText
::
|
|
|
|
ZIP: 207
|
|
Title: Split Founders' Reward
|
|
Author: Jack Grigg <jack@z.cash>
|
|
Category: Consensus
|
|
Created: 2019-01-04
|
|
License: MIT
|
|
|
|
|
|
Terminology
|
|
===========
|
|
|
|
The key words "MUST", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in
|
|
RFC 2119. [#RFC2119]_
|
|
|
|
|
|
Abstract
|
|
========
|
|
|
|
This proposal defines how the consensus rules are altered to split the original Founders' Reward across three
|
|
recipient addresses per block instead of one, corresponding to the three funding streams contained within it.
|
|
|
|
|
|
Motivation
|
|
==========
|
|
|
|
Since the launch of the Zcash network, the consensus rules have required that until the first block reward
|
|
halving (at block 850,000), each block must send 20% of the block subsidy to a hard-coded transparent address.
|
|
[#block-subsidy]_ This funding stream is referred to as the Founders' Reward.
|
|
|
|
This stream of 2.5-ZEC outputs (the value after the mining slow-start was completed) can be split into three
|
|
logical funding streams: [#continued-funding]_
|
|
|
|
- (73.7%) The Zerocoin Electric Coin Company Equity Fund stream
|
|
- (14.4%) The Zcash Foundation Endowment stream
|
|
- (11.9%) The Zerocoin Electric Coin Company Strategic Reserve stream
|
|
|
|
Modifying the consensus rules to allocate the 2.5 ZEC across three separate recipient addresses decouples
|
|
these three funding streams organizationally, legally, and operationally. It further reinforces transparency
|
|
as to the structure of the original Founders' Reward.
|
|
|
|
|
|
Specification
|
|
=============
|
|
|
|
Funding streams
|
|
---------------
|
|
|
|
A funding stream is defined by a block reward fraction (represented as a numerator and a denominator), a start
|
|
height (inclusive), and an end height (exclusive).
|
|
|
|
By defining the issuance as a proportion of the total block issuance, rather than absolute zatoshis, this ZIP
|
|
dovetails with any changes to both block target times and issuance-per-block rates while maintaining an
|
|
unchanged target-time-based issuance schedule. We anticipate such target-time / issuance rate changes in other
|
|
ZIPs.
|
|
|
|
The value of a funding stream at a given block height is defined as::
|
|
|
|
FundingStream.Value(height) =
|
|
floor((BlockReward(height) * FundingStream.ValueNumerator) / FundingStream.ValueDenominator)
|
|
|
|
An active funding stream at a given block height is defined as a funding stream for which the block height is
|
|
less than its end height, but not less than its start height.
|
|
|
|
Each funding stream has an associated set of recipient addresses. Each address is used for at most 1/48th of a
|
|
halving interval, creating a roughly-monthly sequence of funding periods. The address to be used for a given
|
|
block height is defined as follows (using ``HalvingInterval`` as-defined in [#protocol-constants]_)::
|
|
|
|
AddressChangeInterval = HalvingInterval / 48
|
|
FundingStream.AddressIndex(height) =
|
|
floor((height - FundingStream.StartHeight) / AddressChangeInterval)
|
|
Address(height) = FundingStream.Addresses[FundingStream.AddressIndex(height)]
|
|
|
|
Consensus rules
|
|
---------------
|
|
|
|
Prior to activation of the Blossom network upgrade, the existing consensus rule for payment of the original
|
|
Founders' Reward is enforced. [#original-fr-consensus-rule]_
|
|
|
|
Once the Blossom network upgrade activates:
|
|
|
|
- The existing consensus rule [#original-fr-consensus-rule]_ is no longer active.
|
|
- The coinbase transaction in each block MUST contain at least one output per active funding stream that pays
|
|
the stream's value to the stream's recipient address for the block's height.
|
|
|
|
Stream definitions
|
|
------------------
|
|
|
|
The three consensus-defined funding streams described above each start at the Blossom activation height, and
|
|
end at the first block reward halving. They are defined as follows (using ``SlowStartShift`` and
|
|
``HalvingInterval`` as-defined in [#protocol-constants]_):
|
|
|
|
======== =============== ================= ================== ================================
|
|
Stream Value numerator Value denominator Start height End height
|
|
======== =============== ================= ================== ================================
|
|
ZECC EF 737 1000 Blossom activation SlowStartShift + HalvingInterval
|
|
ZF E 144 1000 Blossom activation SlowStartShift + HalvingInterval
|
|
ZECC SR 119 1000 Blossom activation SlowStartShift + HalvingInterval
|
|
======== =============== ================= ================== ================================
|
|
|
|
- To-do: specify the correct values.
|
|
- To-do: specify the correct start height.
|
|
|
|
The sets of recipient addresses are defined as follows:
|
|
|
|
.. code:: cpp
|
|
|
|
FS_ADDRESSES_ZECC_EF = [
|
|
];
|
|
|
|
FS_ADDRESSES_ZF_E = [
|
|
];
|
|
|
|
FS_ADDRESSES_ZECC_SR = [
|
|
];
|
|
|
|
- To-do: specify the sets of FR addresses.
|
|
- To-do: require that the three FR address sets are PGP-signed with appropriate keys.
|
|
|
|
Example implementation
|
|
----------------------
|
|
|
|
.. code:: cpp
|
|
|
|
struct FundingPeriod {
|
|
std::vector<std::string> addresses,
|
|
uint64_t valueNumerator,
|
|
uint64_t valueDenominator,
|
|
int startHeight,
|
|
int endHeight,
|
|
};
|
|
|
|
enum FundingStream {
|
|
FS_ZECC_EF,
|
|
FS_ZF_E,
|
|
FS_ZECC_SR,
|
|
MAX_FUNDING_STREAMS,
|
|
};
|
|
|
|
struct Params {
|
|
...
|
|
int nFundingPeriodLength;
|
|
FundingPeriod vFundingPeriods[MAX_FUNDING_STREAMS];
|
|
...
|
|
}
|
|
|
|
CMainParams() {
|
|
...
|
|
|
|
consensus.nFundingPeriodLength = consensus.nSubsidyHalvingInterval / 48;
|
|
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_EF].addresses = FS_ADDRESSES_ZECC_EF;
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_EF].valueNumerator = 737;
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_EF].valueDenominator = 1000;
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_EF].startHeight =
|
|
consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_EF].endHeight =
|
|
(consensus.nSubsidySlowStartInterval / 2) + consensus.nSubsidyHalvingInterval;
|
|
assert(consensus.vFundingPeriods[Consensus::FS_ZECC_EF].valueNumerator <
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_EF].valueDenominator);
|
|
assert(consensus.vFundingPeriods[Consensus::FS_ZECC_EF].startHeight <
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_EF].endHeight);
|
|
|
|
consensus.vFundingPeriods[Consensus::FS_ZF_E].addresses = FS_ADDRESSES_ZF_E;
|
|
consensus.vFundingPeriods[Consensus::FS_ZF_E].valueNumerator = 144;
|
|
consensus.vFundingPeriods[Consensus::FS_ZF_E].valueDenominator = 1000;
|
|
consensus.vFundingPeriods[Consensus::FS_ZF_E].startHeight =
|
|
consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
|
|
consensus.vFundingPeriods[Consensus::FS_ZF_E].endHeight =
|
|
(consensus.nSubsidySlowStartInterval / 2) + consensus.nSubsidyHalvingInterval;
|
|
assert(consensus.vFundingPeriods[Consensus::FS_ZF_E].valueNumerator <
|
|
consensus.vFundingPeriods[Consensus::FS_ZF_E].valueDenominator);
|
|
assert(consensus.vFundingPeriods[Consensus::FS_ZF_E].startHeight <
|
|
consensus.vFundingPeriods[Consensus::FS_ZF_E].endHeight);
|
|
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_SR].addresses = FS_ADDRESSES_ZECC_SR;
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_SR].valueNumerator = 119;
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_SR].valueDenominator = 1000;
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_SR].startHeight =
|
|
consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_SR].endHeight =
|
|
(consensus.nSubsidySlowStartInterval / 2) + consensus.nSubsidyHalvingInterval;
|
|
assert(consensus.vFundingPeriods[Consensus::FS_ZECC_SR].valueNumerator <
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_SR].valueDenominator);
|
|
assert(consensus.vFundingPeriods[Consensus::FS_ZECC_SR].startHeight <
|
|
consensus.vFundingPeriods[Consensus::FS_ZECC_SR].endHeight);
|
|
|
|
...
|
|
}
|
|
|
|
CScript FundingStreamRecipientAddress(
|
|
int nHeight,
|
|
const Consensus::Params& params,
|
|
Consensus::FundingStream idx)
|
|
{
|
|
// Integer division is floor division in C++
|
|
auto addressIndex = (
|
|
nHeight - params.vFundingPeriods[idx].startHeight
|
|
) / params.nFundingPeriodLength;
|
|
return params.vFundingPeriods[idx].addresses[addressIndex];
|
|
};
|
|
|
|
CAmount FundingStreamValue(
|
|
int nHeight,
|
|
const Consensus::Params& params,
|
|
Consensus::FundingStream idx)
|
|
{
|
|
// Integer division is floor division in C++
|
|
return CAmount((
|
|
GetBlockSubsidy(nHeight, params) * params.vFundingPeriods[idx].valueNumerator
|
|
) / params.vFundingPeriods[idx].valueDenominator);
|
|
}
|
|
|
|
std::set<std::pair<CScript, CAmount>> GetActiveFundingStreams(
|
|
int nHeight,
|
|
const Consensus::Params& params)
|
|
{
|
|
std::set<std::pair<CScript, CAmount>> requiredStreams;
|
|
for (int idx = Consensus::FS_FOUNDERS_REWARD; idx < Consensus::MAX_FUNDING_STREAMS; idx++) {
|
|
// Funding period is [startHeight, endHeight)
|
|
if (nHeight >= params.vFundingPeriods[idx].startHeight &&
|
|
nHeight < params.vFundingPeriods[idx].endHeight)
|
|
{
|
|
requiredStreams.insert(std::make_pair(
|
|
FundingStreamRecipientAddress(nHeight, params, idx),
|
|
FundingStreamValue(nHeight, params, idx));
|
|
}
|
|
}
|
|
return requiredStreams;
|
|
};
|
|
|
|
bool ContextualCheckBlock(...)
|
|
{
|
|
...
|
|
|
|
if (NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_BLOSSOM)) {
|
|
// Coinbase transaction must include outputs corresponding to the consensus
|
|
// funding streams active at the current block height.
|
|
auto requiredStreams = GetActiveFundingStreams(nHeight, consensusParams);
|
|
|
|
for (const CTxOut& output : block.vtx[0].vout) {
|
|
for (auto it = requiredStreams.begin(); it != requiredStreams.end(); ++it) {
|
|
if (output.scriptPubKey == it->first && output.nValue == it->second) {
|
|
requiredStreams.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!requiredStreams.empty()) {
|
|
return state.DoS(100, error("%s: funding stream missing", __func__), REJECT_INVALID, "cb-funding-stream-missing");
|
|
}
|
|
} else {
|
|
// Coinbase transaction must include an output sending 20% of
|
|
// the block reward to a founders reward script, until the last founders
|
|
// reward block is reached, with exception of the genesis block.
|
|
// The last founders reward block is defined as the block just before the
|
|
// first subsidy halving block, which occurs at halving_interval + slow_start_shift
|
|
if ((nHeight > 0) && (nHeight <= consensusParams.GetLastFoundersRewardBlockHeight())) {
|
|
bool found = false;
|
|
|
|
for (const CTxOut& output : block.vtx[0].vout) {
|
|
if (output.scriptPubKey == Params().GetFoundersRewardScriptAtHeight(nHeight)) {
|
|
if (output.nValue == (GetBlockSubsidy(nHeight, consensusParams) / 5)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
return state.DoS(100, error("%s: founders reward missing", __func__), REJECT_INVALID, "cb-no-founders-reward");
|
|
}
|
|
}
|
|
}
|
|
|
|
...
|
|
}
|
|
|
|
|
|
Deployment
|
|
==========
|
|
|
|
This proposal will be deployed with the Blossom network upgrade. [#zip-0XXX]_
|
|
|
|
|
|
Backward compatibility
|
|
======================
|
|
|
|
This proposal intentionally creates what is known as a "bilateral consensus rule change". Use of this
|
|
mechanism requires that all network participants upgrade their software to a compatible version within the
|
|
upgrade window. Older software will treat post-upgrade blocks as invalid, and will follow any pre-upgrade
|
|
branch that persists.
|
|
|
|
This proposal is designed with the explicit requirement of not altering the overall issuance schedule (based
|
|
on time), nor does it alter the proportion or timeline of the overall Founders' Reward. As a result, no users
|
|
outside of the Zerocoin Electric Coin Company and Zcash Foundation should experience any UX or economic change
|
|
outside of the upgrade due to this proposal itself.
|
|
|
|
|
|
Reference Implementation
|
|
========================
|
|
|
|
TBC
|
|
|
|
|
|
References
|
|
==========
|
|
|
|
.. [#RFC2119] `Key words for use in RFCs to Indicate Requirement Levels <https://tools.ietf.org/html/rfc2119>`_
|
|
.. [#block-subsidy] `Section 7.7: Calculation of Block Subsidy and Founders' Reward. Zcash Protocol Specification, Version 2018.0-beta-33 or later [Overwinter+Sapling] <https://github.com/zcash/zips/blob/master/protocol/protocol.pdf>`_
|
|
.. [#continued-funding] `Continued Funding and Transparency <https://z.cash/blog/continued-funding-and-transparency>`_
|
|
.. [#protocol-constants] `Section 5.3: Constants. Zcash Protocol Specification, Version 2018.0-beta-33 or later [Overwinter+Sapling] <https://github.com/zcash/zips/blob/master/protocol/protocol.pdf>`_
|
|
.. [#original-fr-consensus-rule] `Section 7.8: Payment of Founders' Reward. Zcash Protocol Specification, Version 2018.0-beta-33 or later [Overwinter+Sapling] <https://github.com/zcash/zips/blob/master/protocol/protocol.pdf>`_
|
|
.. [#zip-0XXX] `ZIP XXX: Blossom Network Upgrade <https://github.com/zcash/zips/blob/master/zip-0XXX.rst>`_
|