remove founders reward code (#3430)
* remove founders reward code * panic if a block before Canopy is validated for subsidy Co-Authored-By: Daira Hopwood <daira@jacaranda.org> Co-authored-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
parent
e5b5ea5889
commit
6821ba9791
|
@ -107,7 +107,7 @@ pub fn subsidy_is_valid(block: &Block, network: Network) -> Result<(), BlockErro
|
||||||
let height = block.coinbase_height().ok_or(SubsidyError::NoCoinbase)?;
|
let height = block.coinbase_height().ok_or(SubsidyError::NoCoinbase)?;
|
||||||
let coinbase = block.transactions.get(0).ok_or(SubsidyError::NoCoinbase)?;
|
let coinbase = block.transactions.get(0).ok_or(SubsidyError::NoCoinbase)?;
|
||||||
|
|
||||||
// Validate founders reward and funding streams
|
// Validate funding streams
|
||||||
let halving_div = subsidy::general::halving_divisor(height, network);
|
let halving_div = subsidy::general::halving_divisor(height, network);
|
||||||
let canopy_activation_height = NetworkUpgrade::Canopy
|
let canopy_activation_height = NetworkUpgrade::Canopy
|
||||||
.activation_height(network)
|
.activation_height(network)
|
||||||
|
@ -121,17 +121,9 @@ pub fn subsidy_is_valid(block: &Block, network: Network) -> Result<(), BlockErro
|
||||||
} else if halving_div.count_ones() != 1 {
|
} else if halving_div.count_ones() != 1 {
|
||||||
unreachable!("invalid halving divisor: the halving divisor must be a non-zero power of two")
|
unreachable!("invalid halving divisor: the halving divisor must be a non-zero power of two")
|
||||||
} else if height < canopy_activation_height {
|
} else if height < canopy_activation_height {
|
||||||
// Founders rewards are paid up to Canopy activation, on both mainnet and testnet
|
// Founders rewards are paid up to Canopy activation, on both mainnet and testnet.
|
||||||
let founders_reward = subsidy::founders_reward::founders_reward(height, network)
|
// But we checkpoint in Canopy so founders reward does not apply for Zebra.
|
||||||
.expect("invalid Amount: founders reward should be valid");
|
unreachable!("we cannot verify consensus rules before Canopy activation");
|
||||||
let matching_values = subsidy::general::find_output_with_amount(coinbase, founders_reward);
|
|
||||||
|
|
||||||
// TODO: the exact founders reward value must be sent as a single output to the correct address
|
|
||||||
if !matching_values.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(SubsidyError::FoundersRewardNotFound)?
|
|
||||||
}
|
|
||||||
} else if halving_div < 4 {
|
} else if halving_div < 4 {
|
||||||
// Funding streams are paid from Canopy activation to the second halving
|
// Funding streams are paid from Canopy activation to the second halving
|
||||||
// Note: Canopy activation is at the first halving on mainnet, but not on testnet
|
// Note: Canopy activation is at the first halving on mainnet, but not on testnet
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
//!
|
//!
|
||||||
//! [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies
|
//! [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies
|
||||||
|
|
||||||
/// Founders' Reward functions apply for blocks before Canopy.
|
|
||||||
pub mod founders_reward;
|
|
||||||
/// Funding Streams functions apply for blocks at and after Canopy.
|
/// Funding Streams functions apply for blocks at and after Canopy.
|
||||||
pub mod funding_streams;
|
pub mod funding_streams;
|
||||||
/// General subsidy functions apply for blocks after slow-start mining.
|
/// General subsidy functions apply for blocks after slow-start mining.
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
//! Founders' Reward calculations. - [§7.8][7.8]
|
|
||||||
//!
|
|
||||||
//! [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies
|
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
|
|
||||||
use zebra_chain::{
|
|
||||||
amount::{Amount, Error, NonNegative},
|
|
||||||
block::Height,
|
|
||||||
parameters::Network,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::block::subsidy::general::{block_subsidy, halving_divisor};
|
|
||||||
use crate::parameters::subsidy::FOUNDERS_FRACTION_DIVISOR;
|
|
||||||
|
|
||||||
/// `FoundersReward(height)` as described in [protocol specification §7.8][7.8]
|
|
||||||
///
|
|
||||||
/// [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies
|
|
||||||
pub fn founders_reward(height: Height, network: Network) -> Result<Amount<NonNegative>, Error> {
|
|
||||||
if halving_divisor(height, network) == 1 {
|
|
||||||
// this calculation is exact, because the block subsidy is divisible by
|
|
||||||
// the FOUNDERS_FRACTION_DIVISOR until long after the first halving
|
|
||||||
block_subsidy(height, network)? / FOUNDERS_FRACTION_DIVISOR
|
|
||||||
} else {
|
|
||||||
Amount::try_from(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use color_eyre::Report;
|
|
||||||
use zebra_chain::parameters::NetworkUpgrade::*;
|
|
||||||
#[test]
|
|
||||||
fn test_founders_reward() -> Result<(), Report> {
|
|
||||||
zebra_test::init();
|
|
||||||
|
|
||||||
let network = Network::Mainnet;
|
|
||||||
let blossom_height = Blossom.activation_height(network).unwrap();
|
|
||||||
let canopy_height = Canopy.activation_height(network).unwrap();
|
|
||||||
|
|
||||||
// Founders reward is 20% of the block subsidy
|
|
||||||
// https://z.cash/support/faq/#founders-reward-recipients
|
|
||||||
// Before Blossom this is 20*12.5/100 = 2.5 ZEC
|
|
||||||
assert_eq!(
|
|
||||||
Amount::try_from(250_000_000),
|
|
||||||
founders_reward((blossom_height - 1).unwrap(), network)
|
|
||||||
);
|
|
||||||
// Founders reward is still 20% of the block subsidy but the block reward is half what it was
|
|
||||||
// After Blossom this is 20*6.25/100 = 1.25 ZEC
|
|
||||||
// https://z.cash/upgrade/blossom/
|
|
||||||
assert_eq!(
|
|
||||||
Amount::try_from(125_000_000),
|
|
||||||
founders_reward(blossom_height, network)
|
|
||||||
);
|
|
||||||
|
|
||||||
// After first halving(coinciding with Canopy) founders reward will expire
|
|
||||||
// https://z.cash/support/faq/#does-the-founders-reward-expire
|
|
||||||
assert_eq!(Amount::try_from(0), founders_reward(canopy_height, network));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -119,7 +119,7 @@ pub fn funding_stream_address(
|
||||||
Address::from_str(address).expect("Address should deserialize")
|
Address::from_str(address).expect("Address should deserialize")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a founders reward address, create a script and check if it is the same
|
/// Given a funding stream address, create a script and check if it is the same
|
||||||
/// as the given lock_script as described in [protocol specification §7.10][7.10]
|
/// as the given lock_script as described in [protocol specification §7.10][7.10]
|
||||||
///
|
///
|
||||||
/// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams.
|
/// [7.10]: https://zips.z.cash/protocol/protocol.pdf#fundingstreams.
|
||||||
|
|
|
@ -9,7 +9,6 @@ use zebra_chain::{
|
||||||
block::Height,
|
block::Height,
|
||||||
parameters::{Network, NetworkUpgrade::*},
|
parameters::{Network, NetworkUpgrade::*},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
transparent,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::parameters::subsidy::*;
|
use crate::parameters::subsidy::*;
|
||||||
|
@ -69,41 +68,7 @@ pub fn block_subsidy(height: Height, network: Network) -> Result<Amount<NonNegat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `MinerSubsidy(height)` as described in [protocol specification §7.8][7.8]
|
|
||||||
///
|
|
||||||
/// [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies
|
|
||||||
///
|
|
||||||
/// `non_miner_reward` is the founders reward or funding stream value.
|
|
||||||
/// If all the rewards for a block go to the miner, use `None`.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn miner_subsidy(
|
|
||||||
height: Height,
|
|
||||||
network: Network,
|
|
||||||
non_miner_reward: Option<Amount<NonNegative>>,
|
|
||||||
) -> Result<Amount<NonNegative>, Error> {
|
|
||||||
if let Some(non_miner_reward) = non_miner_reward {
|
|
||||||
block_subsidy(height, network)? - non_miner_reward
|
|
||||||
} else {
|
|
||||||
block_subsidy(height, network)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a list of outputs in `Transaction`, which have a value equal to `Amount`.
|
|
||||||
pub fn find_output_with_amount(
|
|
||||||
transaction: &Transaction,
|
|
||||||
amount: Amount<NonNegative>,
|
|
||||||
) -> Vec<transparent::Output> {
|
|
||||||
// TODO: shielded coinbase - Heartwood
|
|
||||||
transaction
|
|
||||||
.outputs()
|
|
||||||
.iter()
|
|
||||||
.filter(|o| o.value == amount)
|
|
||||||
.cloned()
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns all output amounts in `Transaction`.
|
/// Returns all output amounts in `Transaction`.
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn output_amounts(transaction: &Transaction) -> HashSet<Amount<NonNegative>> {
|
pub fn output_amounts(transaction: &Transaction) -> HashSet<Amount<NonNegative>> {
|
||||||
transaction
|
transaction
|
||||||
.outputs()
|
.outputs()
|
||||||
|
@ -118,11 +83,6 @@ mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use color_eyre::Report;
|
use color_eyre::Report;
|
||||||
|
|
||||||
use crate::block::subsidy::{
|
|
||||||
founders_reward::founders_reward,
|
|
||||||
funding_streams::{funding_stream_values, height_for_first_halving},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn halving_test() -> Result<(), Report> {
|
fn halving_test() -> Result<(), Report> {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
@ -300,58 +260,4 @@ mod test {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn miner_subsidy_test() -> Result<(), Report> {
|
|
||||||
zebra_test::init();
|
|
||||||
|
|
||||||
miner_subsidy_for_network(Network::Mainnet)?;
|
|
||||||
miner_subsidy_for_network(Network::Testnet)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn miner_subsidy_for_network(network: Network) -> Result<(), Report> {
|
|
||||||
let blossom_height = Blossom.activation_height(network).unwrap();
|
|
||||||
let first_halving_height = height_for_first_halving(network);
|
|
||||||
|
|
||||||
// Miner reward before Blossom is 80% of the total block reward
|
|
||||||
// 80*12.5/100 = 10 ZEC
|
|
||||||
let founders_amount = founders_reward((blossom_height - 1).unwrap(), network)?;
|
|
||||||
assert_eq!(
|
|
||||||
Amount::try_from(1_000_000_000),
|
|
||||||
miner_subsidy(
|
|
||||||
(blossom_height - 1).unwrap(),
|
|
||||||
network,
|
|
||||||
Some(founders_amount)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// After blossom the total block reward is "halved", miner still get 80%
|
|
||||||
// 80*6.25/100 = 5 ZEC
|
|
||||||
let founders_amount = founders_reward(blossom_height, network)?;
|
|
||||||
assert_eq!(
|
|
||||||
Amount::try_from(500_000_000),
|
|
||||||
miner_subsidy(blossom_height, network, Some(founders_amount))
|
|
||||||
);
|
|
||||||
|
|
||||||
// After first halving, miner will get 2.5 ZEC per mined block (not counting fees)
|
|
||||||
let funding_stream_values = funding_stream_values(first_halving_height, network)?
|
|
||||||
.iter()
|
|
||||||
.map(|row| row.1)
|
|
||||||
.sum::<Result<Amount<NonNegative>, Error>>()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
Amount::try_from(250_000_000),
|
|
||||||
miner_subsidy(first_halving_height, network, Some(funding_stream_values))
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: After second halving, there will be no funding streams, and
|
|
||||||
// miners will get all the block reward
|
|
||||||
|
|
||||||
// TODO: also add some very large halvings
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,7 @@ use zebra_chain::{
|
||||||
use zebra_script::CachedFfiTransaction;
|
use zebra_script::CachedFfiTransaction;
|
||||||
use zebra_test::transcript::{ExpectedTranscriptError, Transcript};
|
use zebra_test::transcript::{ExpectedTranscriptError, Transcript};
|
||||||
|
|
||||||
use crate::{
|
use crate::{parameters::SLOW_START_SHIFT, script, transaction};
|
||||||
parameters::{SLOW_START_INTERVAL, SLOW_START_SHIFT},
|
|
||||||
script, transaction,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -294,8 +291,12 @@ fn subsidy_is_valid_for_network(network: Network) -> Result<(), Report> {
|
||||||
.zcash_deserialize_into::<Block>()
|
.zcash_deserialize_into::<Block>()
|
||||||
.expect("block is structurally valid");
|
.expect("block is structurally valid");
|
||||||
|
|
||||||
|
let canopy_activation_height = NetworkUpgrade::Canopy
|
||||||
|
.activation_height(network)
|
||||||
|
.expect("Canopy activation height is known");
|
||||||
|
|
||||||
// TODO: first halving, second halving, third halving, and very large halvings
|
// TODO: first halving, second halving, third halving, and very large halvings
|
||||||
if block::Height(height) > SLOW_START_INTERVAL {
|
if block::Height(height) >= canopy_activation_height {
|
||||||
check::subsidy_is_valid(&block, network).expect("subsidies should pass for this block");
|
check::subsidy_is_valid(&block, network).expect("subsidies should pass for this block");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,10 +309,10 @@ fn coinbase_validation_failure() -> Result<(), Report> {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
let network = Network::Mainnet;
|
let network = Network::Mainnet;
|
||||||
|
|
||||||
// Get a block in the mainnet that is inside the founders reward period,
|
// Get a block in the mainnet that is inside the funding stream period,
|
||||||
// and delete the coinbase transaction
|
// and delete the coinbase transaction
|
||||||
let block =
|
let block =
|
||||||
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..])
|
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1046400_BYTES[..])
|
||||||
.expect("block should deserialize");
|
.expect("block should deserialize");
|
||||||
let mut block = Arc::try_unwrap(block).expect("block should unwrap");
|
let mut block = Arc::try_unwrap(block).expect("block should unwrap");
|
||||||
|
|
||||||
|
@ -328,9 +329,9 @@ fn coinbase_validation_failure() -> Result<(), Report> {
|
||||||
let expected = BlockError::Transaction(TransactionError::Subsidy(SubsidyError::NoCoinbase));
|
let expected = BlockError::Transaction(TransactionError::Subsidy(SubsidyError::NoCoinbase));
|
||||||
assert_eq!(expected, result);
|
assert_eq!(expected, result);
|
||||||
|
|
||||||
// Get another founders reward block, and delete the coinbase transaction
|
// Get another funding stream block, and delete the coinbase transaction
|
||||||
let block =
|
let block =
|
||||||
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_434873_BYTES[..])
|
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1046401_BYTES[..])
|
||||||
.expect("block should deserialize");
|
.expect("block should deserialize");
|
||||||
let mut block = Arc::try_unwrap(block).expect("block should unwrap");
|
let mut block = Arc::try_unwrap(block).expect("block should unwrap");
|
||||||
|
|
||||||
|
@ -347,9 +348,9 @@ fn coinbase_validation_failure() -> Result<(), Report> {
|
||||||
let expected = BlockError::Transaction(TransactionError::Subsidy(SubsidyError::NoCoinbase));
|
let expected = BlockError::Transaction(TransactionError::Subsidy(SubsidyError::NoCoinbase));
|
||||||
assert_eq!(expected, result);
|
assert_eq!(expected, result);
|
||||||
|
|
||||||
// Get another founders reward block, and duplicate the coinbase transaction
|
// Get another funding stream, and duplicate the coinbase transaction
|
||||||
let block =
|
let block =
|
||||||
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_434873_BYTES[..])
|
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1180900_BYTES[..])
|
||||||
.expect("block should deserialize");
|
.expect("block should deserialize");
|
||||||
let mut block = Arc::try_unwrap(block).expect("block should unwrap");
|
let mut block = Arc::try_unwrap(block).expect("block should unwrap");
|
||||||
|
|
||||||
|
@ -374,51 +375,6 @@ fn coinbase_validation_failure() -> Result<(), Report> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn founders_reward_validation_failure() -> Result<(), Report> {
|
|
||||||
zebra_test::init();
|
|
||||||
let network = Network::Mainnet;
|
|
||||||
|
|
||||||
// Get a block in the mainnet that is inside the founders reward period.
|
|
||||||
let block =
|
|
||||||
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..])
|
|
||||||
.expect("block should deserialize");
|
|
||||||
|
|
||||||
// Build the new transaction with modified coinbase outputs
|
|
||||||
let tx = block
|
|
||||||
.transactions
|
|
||||||
.get(0)
|
|
||||||
.map(|transaction| {
|
|
||||||
let mut output = transaction.outputs()[0].clone();
|
|
||||||
output.value = Amount::try_from(i32::MAX).unwrap();
|
|
||||||
Transaction::V3 {
|
|
||||||
inputs: transaction.inputs().to_vec(),
|
|
||||||
outputs: vec![output],
|
|
||||||
lock_time: transaction.lock_time().unwrap_or_else(LockTime::unlocked),
|
|
||||||
expiry_height: Height(0),
|
|
||||||
joinsplit_data: None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Build new block
|
|
||||||
let transactions: Vec<Arc<zebra_chain::transaction::Transaction>> = vec![Arc::new(tx)];
|
|
||||||
let block = Block {
|
|
||||||
header: block.header,
|
|
||||||
transactions,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Validate it
|
|
||||||
let result = check::subsidy_is_valid(&block, network);
|
|
||||||
let expected = Err(BlockError::Transaction(TransactionError::Subsidy(
|
|
||||||
SubsidyError::FoundersRewardNotFound,
|
|
||||||
)));
|
|
||||||
|
|
||||||
assert_eq!(expected, result);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn funding_stream_validation() -> Result<(), Report> {
|
fn funding_stream_validation() -> Result<(), Report> {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
@ -435,8 +391,12 @@ fn funding_stream_validation_for_network(network: Network) -> Result<(), Report>
|
||||||
Network::Testnet => zebra_test::vectors::TESTNET_BLOCKS.iter(),
|
Network::Testnet => zebra_test::vectors::TESTNET_BLOCKS.iter(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let canopy_activation_height = NetworkUpgrade::Canopy
|
||||||
|
.activation_height(network)
|
||||||
|
.expect("Canopy activation height is known");
|
||||||
|
|
||||||
for (&height, block) in block_iter {
|
for (&height, block) in block_iter {
|
||||||
if Height(height) > SLOW_START_SHIFT {
|
if Height(height) >= canopy_activation_height {
|
||||||
let block = Block::zcash_deserialize(&block[..]).expect("block should deserialize");
|
let block = Block::zcash_deserialize(&block[..]).expect("block should deserialize");
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
|
|
|
@ -23,9 +23,6 @@ pub enum SubsidyError {
|
||||||
#[error("no coinbase transaction in block")]
|
#[error("no coinbase transaction in block")]
|
||||||
NoCoinbase,
|
NoCoinbase,
|
||||||
|
|
||||||
#[error("founders reward output not found")]
|
|
||||||
FoundersRewardNotFound,
|
|
||||||
|
|
||||||
#[error("funding stream expected output not found")]
|
#[error("funding stream expected output not found")]
|
||||||
FundingStreamNotFound,
|
FundingStreamNotFound,
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Constants for Block Subsidy, Funding Streams, and Founders' Reward
|
//! Constants for Block Subsidy and Funding Streams
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -38,13 +38,6 @@ pub const PRE_BLOSSOM_HALVING_INTERVAL: Height = Height(840_000);
|
||||||
pub const POST_BLOSSOM_HALVING_INTERVAL: Height =
|
pub const POST_BLOSSOM_HALVING_INTERVAL: Height =
|
||||||
Height((PRE_BLOSSOM_HALVING_INTERVAL.0 as u64 * BLOSSOM_POW_TARGET_SPACING_RATIO) as u32);
|
Height((PRE_BLOSSOM_HALVING_INTERVAL.0 as u64 * BLOSSOM_POW_TARGET_SPACING_RATIO) as u32);
|
||||||
|
|
||||||
/// The divisor used to calculate the FoundersFraction.
|
|
||||||
///
|
|
||||||
/// Derivation: FOUNDERS_FRACTION_DIVISOR = 1/FoundersFraction
|
|
||||||
///
|
|
||||||
/// Usage: founders_reward = block_subsidy / FOUNDERS_FRACTION_DIVISOR
|
|
||||||
pub const FOUNDERS_FRACTION_DIVISOR: u64 = 5;
|
|
||||||
|
|
||||||
/// The first halving height in the testnet is at block height `1_116_000`
|
/// The first halving height in the testnet is at block height `1_116_000`
|
||||||
/// as specified in [protocol specification §7.10.1][7.10.1]
|
/// as specified in [protocol specification §7.10.1][7.10.1]
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue