From bf98053e06436833447f61d653b208fc68b4337b Mon Sep 17 00:00:00 2001 From: Cayle Sharrock Date: Wed, 21 Feb 2024 09:37:16 +0000 Subject: [PATCH] Compiles. Tests fail chore: update formatting and comments in EmissionSchedule and test files chore: update tests for tail emission in schedule The tests for the tail emission in the schedule have been updated to include the faucet value in the supply calculations. This ensures that the total supply up to the tail emission is correct. Additionally, new tests have been added to cover the inflating tail emission. feat: update tail inflation calculation to use basis points The `EmissionSchedule` struct now includes a `inflation_bips` field, which represents the tail inflation rate in basis points (bips). The `new_tail_emission` method in the `Emission` implementation has been updated to calculate the `epoch_issuance` using the updated inflation rate. Additionally, the `as_u128` method has been added to convert the `MicroMinotari` value to a `u128` for more precise calculations. In the `consensus` module, the `inflation_bips` field in the `NetworkParams` struct has been updated to use basis points. The inflation rates for different networks have been adjusted accordingly. fix: update parameters for EmissionSchedule initialization --- .../minotari_app_grpc/proto/types.proto | 4 +- .../src/conversions/consensus_constants.rs | 6 +- .../core/src/consensus/consensus_constants.rs | 149 +++++---- .../core/src/consensus/consensus_manager.rs | 9 +- base_layer/core/src/consensus/emission.rs | 314 +++++++++++------- .../core/src/transactions/tari_amount.rs | 5 + .../core/src/validation/chain_balance.rs | 5 +- .../core/tests/helpers/sample_blockchains.rs | 16 +- base_layer/core/tests/helpers/sync.rs | 9 +- base_layer/core/tests/tests/mempool.rs | 14 +- base_layer/core/tests/tests/node_service.rs | 15 +- .../core/tests/tests/node_state_machine.rs | 11 +- 12 files changed, 323 insertions(+), 234 deletions(-) diff --git a/applications/minotari_app_grpc/proto/types.proto b/applications/minotari_app_grpc/proto/types.proto index 474e2bc3ab..c652dbd6bf 100644 --- a/applications/minotari_app_grpc/proto/types.proto +++ b/applications/minotari_app_grpc/proto/types.proto @@ -119,7 +119,7 @@ message ConsensusConstants { uint64 median_timestamp_count = 9; uint64 emission_initial = 10; repeated uint64 emission_decay = 11; - uint64 emission_tail = 12; + uint64 emission_tail = 12 [deprecated=true]; uint64 min_sha3x_pow_difficulty = 13; uint64 block_weight_inputs = 14; uint64 block_weight_outputs = 15; @@ -141,4 +141,6 @@ message ConsensusConstants { uint64 validator_node_registration_min_lock_height = 32; uint64 validator_node_registration_shuffle_interval_epoch = 33; repeated PermittedRangeProofs permitted_range_proof_types = 34; + uint64 inflation_bips = 35; + uint64 tail_epoch_length = 36; } diff --git a/applications/minotari_app_grpc/src/conversions/consensus_constants.rs b/applications/minotari_app_grpc/src/conversions/consensus_constants.rs index 80fac7416e..0195b1dd65 100644 --- a/applications/minotari_app_grpc/src/conversions/consensus_constants.rs +++ b/applications/minotari_app_grpc/src/conversions/consensus_constants.rs @@ -29,7 +29,7 @@ use crate::tari_rpc as grpc; impl From for grpc::ConsensusConstants { #[allow(clippy::too_many_lines)] fn from(cc: ConsensusConstants) -> Self { - let (emission_initial, emission_decay, emission_tail) = cc.emission_amounts(); + let (emission_initial, emission_decay, inflation_bips, tail_epoch_length) = cc.emission_amounts(); let weight_params = cc.transaction_weight_params().params(); let input_version_range = cc.input_version_range().clone().into_inner(); let input_version_range = grpc::Range { @@ -110,7 +110,9 @@ impl From for grpc::ConsensusConstants { median_timestamp_count: u64::try_from(cc.median_timestamp_count()).unwrap_or(0), emission_initial: emission_initial.into(), emission_decay: emission_decay.to_vec(), - emission_tail: emission_tail.into(), + emission_tail: 0, + inflation_bips, + tail_epoch_length, min_sha3x_pow_difficulty: cc.min_pow_difficulty(PowAlgorithm::Sha3x).into(), block_weight_inputs: weight_params.input_weight, block_weight_outputs: weight_params.output_weight, diff --git a/base_layer/core/src/consensus/consensus_constants.rs b/base_layer/core/src/consensus/consensus_constants.rs index d5729296ac..c5070e526e 100644 --- a/base_layer/core/src/consensus/consensus_constants.rs +++ b/base_layer/core/src/consensus/consensus_constants.rs @@ -36,7 +36,7 @@ use crate::{ consensus::network::NetworkConsensus, proof_of_work::{Difficulty, PowAlgorithm}, transactions::{ - tari_amount::{uT, MicroMinotari, T}, + tari_amount::{uT, MicroMinotari}, transaction_components::{ OutputFeatures, OutputFeaturesVersion, @@ -50,6 +50,8 @@ use crate::{ }, }; +const ANNUAL_BLOCKS: u64 = 30 /* blocks/hr */ * 24 /* hr /d */ * 366 /* days / yr */; + /// This is the inner struct used to control all consensus values. #[derive(Debug, Clone)] pub struct ConsensusConstants { @@ -77,8 +79,10 @@ pub struct ConsensusConstants { /// This is the emission curve decay factor as a sum of fraction powers of two. e.g. [1,2] would be 1/2 + 1/4. [2] /// would be 1/4 pub(in crate::consensus) emission_decay: &'static [u64], - /// This is the emission curve tail amount - pub(in crate::consensus) emission_tail: MicroMinotari, + /// The tail emission inflation rate in basis points (bips). 100 bips = 1 percentage_point + pub(in crate::consensus) inflation_bips: u64, + /// The length, in blocks of each tail emission epoch (where the reward is held constant) + pub(in crate::consensus) tail_epoch_length: u64, /// This is the maximum age a Monero merge mined seed can be reused /// Monero forces a change every height mod 2048 blocks max_randomx_seed_height: u64, @@ -165,9 +169,14 @@ impl ConsensusConstants { self.effective_from_height } - /// This gets the emission curve values as (initial, decay, tail) - pub fn emission_amounts(&self) -> (MicroMinotari, &'static [u64], MicroMinotari) { - (self.emission_initial, self.emission_decay, self.emission_tail) + /// This gets the emission curve values as (initial, decay, inflation_bips, epoch_length) + pub fn emission_amounts(&self) -> (MicroMinotari, &'static [u64], u64, u64) { + ( + self.emission_initial, + self.emission_decay, + self.inflation_bips, + self.tail_epoch_length, + ) } /// The min height maturity a coinbase utxo must have. @@ -380,7 +389,8 @@ impl ConsensusConstants { median_timestamp_count: 11, emission_initial: 18_462_816_327 * uT, emission_decay: &ESMERALDA_DECAY_PARAMS, - emission_tail: 800 * T, + inflation_bips: 1000, + tail_epoch_length: 100, max_randomx_seed_height: u64::MAX, max_extra_field_size: 200, proof_of_work: algos, @@ -443,7 +453,8 @@ impl ConsensusConstants { median_timestamp_count: 11, emission_initial: 5_538_846_115 * uT, emission_decay: &EMISSION_DECAY, - emission_tail: 100.into(), + inflation_bips: 100, + tail_epoch_length: ANNUAL_BLOCKS, max_randomx_seed_height: u64::MAX, max_extra_field_size: 200, proof_of_work: algos, @@ -499,7 +510,8 @@ impl ConsensusConstants { median_timestamp_count: 11, emission_initial: ESMERALDA_INITIAL_EMISSION, emission_decay: &ESMERALDA_DECAY_PARAMS, - emission_tail: 800 * T, + inflation_bips: 100, + tail_epoch_length: ANNUAL_BLOCKS, max_randomx_seed_height: 3000, max_extra_field_size: 200, proof_of_work: algos, @@ -554,7 +566,8 @@ impl ConsensusConstants { median_timestamp_count: 11, emission_initial: INITIAL_EMISSION, emission_decay: &EMISSION_DECAY, - emission_tail: 800 * T, + inflation_bips: 100, + tail_epoch_length: ANNUAL_BLOCKS, max_randomx_seed_height: 3000, max_extra_field_size: 200, proof_of_work: algos, @@ -603,7 +616,8 @@ impl ConsensusConstants { median_timestamp_count: 11, emission_initial: INITIAL_EMISSION, emission_decay: &EMISSION_DECAY, - emission_tail: 800 * T, + inflation_bips: 100, + tail_epoch_length: ANNUAL_BLOCKS, max_randomx_seed_height: 3000, max_extra_field_size: 200, proof_of_work: algos, @@ -654,7 +668,8 @@ impl ConsensusConstants { median_timestamp_count: 11, emission_initial: 10_000_000.into(), emission_decay: &EMISSION_DECAY, - emission_tail: 100.into(), + inflation_bips: 100, + tail_epoch_length: ANNUAL_BLOCKS, max_randomx_seed_height: u64::MAX, max_extra_field_size: 200, proof_of_work: algos, @@ -835,11 +850,13 @@ impl ConsensusConstantsBuilder { mut self, intial_amount: MicroMinotari, decay: &'static [u64], - tail_amount: MicroMinotari, + inflation_bips: u64, + epoch_length: u64, ) -> Self { self.consensus.emission_initial = intial_amount; self.consensus.emission_decay = decay; - self.consensus.emission_tail = tail_amount; + self.consensus.inflation_bips = inflation_bips; + self.consensus.tail_epoch_length = epoch_length; self } @@ -868,15 +885,13 @@ impl ConsensusConstantsBuilder { #[cfg(test)] mod test { - use std::convert::TryFrom; - use crate::{ consensus::{ emission::{Emission, EmissionSchedule}, ConsensusConstants, }, transactions::{ - tari_amount::{uT, MicroMinotari}, + tari_amount::{uT, MicroMinotari, T}, transaction_components::{OutputType, RangeProofType}, }, }; @@ -940,33 +955,41 @@ mod test { let schedule = EmissionSchedule::new( esmeralda[0].emission_initial, esmeralda[0].emission_decay, - esmeralda[0].emission_tail, + esmeralda[0].inflation_bips, + esmeralda[0].tail_epoch_length, + esmeralda[0].faucet_value(), ); // No genesis block coinbase assert_eq!(schedule.block_reward(0), MicroMinotari(0)); // Coinbases starts at block 1 let coinbase_offset = 1; let first_reward = schedule.block_reward(coinbase_offset); - assert_eq!(first_reward, esmeralda[0].emission_initial * uT); - assert_eq!(schedule.supply_at_block(coinbase_offset), first_reward); + assert_eq!(first_reward, esmeralda[0].emission_initial); + assert_eq!( + schedule.supply_at_block(coinbase_offset), + first_reward + esmeralda[0].faucet_value() + ); // 'half_life_block' at approximately '(total supply - faucet value) / 2' #[allow(clippy::cast_possible_truncation)] - let half_life_block = (365.0 * 24.0 * 30.0 * 2.76) as u64; + let half_life_block = 365 * 24 * 30 * 3; assert_eq!( schedule.supply_at_block(half_life_block + coinbase_offset), - 7_483_280_506_356_578 * uT + 7_935_818_494_624_306 * uT + esmeralda[0].faucet_value() ); - // Tail emission starts after block 3,255,552 + coinbase_offset - let mut rewards = schedule - .iter() - .skip(3255552 + usize::try_from(coinbase_offset).unwrap()); + // 21 billion + let mut rewards = schedule.iter().skip(3255552 + coinbase_offset as usize); let (block_num, reward, supply) = rewards.next().unwrap(); assert_eq!(block_num, 3255553 + coinbase_offset); assert_eq!(reward, 800_000_415 * uT); - let total_supply_up_to_tail_emission = supply + esmeralda[0].faucet_value; - assert_eq!(total_supply_up_to_tail_emission, 20_999_999_999_819_869 * uT); + assert_eq!(supply, 20_999_999_999_819_869 * uT); let (_, reward, _) = rewards.next().unwrap(); - assert_eq!(reward, esmeralda[0].emission_tail); + assert_eq!(reward, 799_999_715 * uT); + // Inflating tail emission + let mut rewards = schedule.iter().skip(3259845); + let (block_num, reward, supply) = rewards.next().unwrap(); + assert_eq!(block_num, 3259846); + assert_eq!(reward, 797 * T); + assert_eq!(supply, 21_003_427_156_818_122 * uT); } #[test] @@ -975,7 +998,9 @@ mod test { let schedule = EmissionSchedule::new( nextnet[0].emission_initial, nextnet[0].emission_decay, - nextnet[0].emission_tail, + nextnet[0].inflation_bips, + nextnet[0].tail_epoch_length, + nextnet[0].faucet_value(), ); // No genesis block coinbase assert_eq!(schedule.block_reward(0), MicroMinotari(0)); @@ -983,25 +1008,23 @@ mod test { let coinbase_offset = 1; let first_reward = schedule.block_reward(coinbase_offset); assert_eq!(first_reward, nextnet[0].emission_initial * uT); - assert_eq!(schedule.supply_at_block(coinbase_offset), first_reward); + assert_eq!( + schedule.supply_at_block(coinbase_offset), + first_reward + nextnet[0].faucet_value() + ); // 'half_life_block' at approximately '(total supply - faucet value) / 2' #[allow(clippy::cast_possible_truncation)] let half_life_block = (365.0 * 24.0 * 30.0 * 2.76) as u64; assert_eq!( schedule.supply_at_block(half_life_block + coinbase_offset), - 7_483_280_506_356_578 * uT + 7_483_280_506_356_578 * uT + nextnet[0].faucet_value() ); - // Tail emission starts after block 3,255,552 + coinbase_offset - let mut rewards = schedule - .iter() - .skip(3255552 + usize::try_from(coinbase_offset).unwrap()); + // Tail emission + let mut rewards = schedule.iter().skip(3259845); let (block_num, reward, supply) = rewards.next().unwrap(); - assert_eq!(block_num, 3255553 + coinbase_offset); - assert_eq!(reward, 800_000_415 * uT); - let total_supply_up_to_tail_emission = supply + nextnet[0].faucet_value; - assert_eq!(total_supply_up_to_tail_emission, 20_999_999_999_819_869 * uT); - let (_, reward, _) = rewards.next().unwrap(); - assert_eq!(reward, nextnet[0].emission_tail); + assert_eq!(block_num, 3259846); + assert_eq!(reward, 797 * T); + assert_eq!(supply, 21_003_427_156_818_122 * uT); } #[test] @@ -1010,7 +1033,9 @@ mod test { let schedule = EmissionSchedule::new( stagenet[0].emission_initial, stagenet[0].emission_decay, - stagenet[0].emission_tail, + stagenet[0].inflation_bips, + stagenet[0].tail_epoch_length, + stagenet[0].faucet_value(), ); // No genesis block coinbase assert_eq!(schedule.block_reward(0), MicroMinotari(0)); @@ -1018,31 +1043,35 @@ mod test { let coinbase_offset = 1; let first_reward = schedule.block_reward(coinbase_offset); assert_eq!(first_reward, stagenet[0].emission_initial * uT); - assert_eq!(schedule.supply_at_block(coinbase_offset), first_reward); + assert_eq!( + schedule.supply_at_block(coinbase_offset), + first_reward + stagenet[0].faucet_value() + ); // 'half_life_block' at approximately '(total supply - faucet value) / 2' #[allow(clippy::cast_possible_truncation)] let half_life_block = (365.0 * 24.0 * 30.0 * 2.76) as u64; assert_eq!( schedule.supply_at_block(half_life_block + coinbase_offset), - 7_483_280_506_356_578 * uT + 7_483_280_506_356_578 * uT + stagenet[0].faucet_value() ); - // Tail emission starts after block 3,255,552 + coinbase_offset - let mut rewards = schedule - .iter() - .skip(3255552 + usize::try_from(coinbase_offset).unwrap()); + // Tail emission + let mut rewards = schedule.iter().skip(3259845); let (block_num, reward, supply) = rewards.next().unwrap(); - assert_eq!(block_num, 3255553 + coinbase_offset); - assert_eq!(reward, 800_000_415 * uT); - let total_supply_up_to_tail_emission = supply + stagenet[0].faucet_value; - assert_eq!(total_supply_up_to_tail_emission, 20_999_999_999_819_869 * uT); - let (_, reward, _) = rewards.next().unwrap(); - assert_eq!(reward, stagenet[0].emission_tail); + assert_eq!(block_num, 3259846); + assert_eq!(reward, 797 * T); + assert_eq!(supply, 21_003_427_156_818_122 * uT); } #[test] fn igor_schedule() { let igor = ConsensusConstants::igor(); - let schedule = EmissionSchedule::new(igor[0].emission_initial, igor[0].emission_decay, igor[0].emission_tail); + let schedule = EmissionSchedule::new( + igor[0].emission_initial, + igor[0].emission_decay, + igor[0].inflation_bips, + igor[0].tail_epoch_length, + igor[0].faucet_value(), + ); // No genesis block coinbase assert_eq!(schedule.block_reward(0), MicroMinotari(0)); // Coinbases starts at block 1 @@ -1055,11 +1084,9 @@ mod test { let mut previous_reward = MicroMinotari(0); for (block_num, reward, supply) in rewards { if reward == previous_reward { - assert_eq!(block_num, 11_084_819 + 1); - assert_eq!(supply, MicroMinotari(6_326_198_792_915_738)); - // These set of constants does not result in a tail emission equal to the specified tail emission - assert_ne!(reward, igor[0].emission_tail); - assert_eq!(reward, MicroMinotari(2_097_151)); + assert_eq!(block_num, 11_084_796); + assert_eq!(supply, MicroMinotari(8_010_884_615_082_026)); + assert_eq!(reward, MicroMinotari(303_000_000)); break; } previous_reward = reward; diff --git a/base_layer/core/src/consensus/consensus_manager.rs b/base_layer/core/src/consensus/consensus_manager.rs index e315848c9f..4bb4c0814a 100644 --- a/base_layer/core/src/consensus/consensus_manager.rs +++ b/base_layer/core/src/consensus/consensus_manager.rs @@ -82,9 +82,7 @@ impl ConsensusManager { } } - /// Get a pointer to the emission schedule - /// The height provided here, decides the emission curve to use. It swaps to the integer curve upon reaching - /// 1_000_000_000 + /// Get a reference to the emission parameters pub fn emission_schedule(&self) -> &EmissionSchedule { &self.inner.emission } @@ -241,8 +239,11 @@ impl ConsensusManagerBuilder { let emission = EmissionSchedule::new( self.consensus_constants[0].emission_initial, self.consensus_constants[0].emission_decay, - self.consensus_constants[0].emission_tail, + self.consensus_constants[0].inflation_bips, + self.consensus_constants[0].tail_epoch_length, + self.consensus_constants[0].faucet_value(), ); + let inner = ConsensusManagerInner { consensus_constants: self.consensus_constants, network: self.network, diff --git a/base_layer/core/src/consensus/emission.rs b/base_layer/core/src/consensus/emission.rs index d6cfc671bc..09b7237f0b 100644 --- a/base_layer/core/src/consensus/emission.rs +++ b/base_layer/core/src/consensus/emission.rs @@ -20,8 +20,6 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::cmp; - use crate::transactions::tari_amount::MicroMinotari; pub trait Emission { @@ -29,32 +27,50 @@ pub trait Emission { fn supply_at_block(&self, height: u64) -> MicroMinotari; } -/// The Minotari emission schedule. The emission schedule determines how much Minotari is mined as a block reward at -/// every block. -/// -/// NB: We don't know what the final emission schedule will be on Minotari yet, so do not give any weight to values or -/// formulae provided in this file, they will almost certainly change ahead of main-net release. +/// The Minotari emission schedule with inflating tail emission. The emission schedule determines how much Minotari is +/// mined as a block reward at every block. #[derive(Debug, Clone)] pub struct EmissionSchedule { initial: MicroMinotari, decay: &'static [u64], - tail: MicroMinotari, + inflation_bips: u64, // Tail inflation in basis points. 100 bips = 1 percentage point + epoch_length: u64, // The number of blocks in an inflation epoch + initial_supply: MicroMinotari, // The supply at block 0, from faucets or premine } impl EmissionSchedule { /// Create a new emission schedule instance. /// - /// The Emission schedule follows a similar pattern to Monero; with an exponentially decaying emission rate with - /// a constant tail emission rate. + /// ## Primary emission schedule + /// + /// The Emission schedule follows a similar pattern to Monero; with an initially exponentially decaying emission + /// rate and a tail emission. + /// /// - /// The block reward is given by - /// $$ r_n = \mathrm{MAX}(\mathrm(intfloor(r_{n-1} * (1 - \epsilon)), t) n > 0 $$ + /// The decay portion is given by + /// $$ r_n = \lfloor r_{n-1} * (1 - \epsilon) \rfloor, n > 0 $$ /// $$ r_0 = A_0 $$ /// /// where /// * $$A_0$$ is the genesis block reward /// * $$1 - \epsilon$$ is the decay rate - /// * $$t$$ is the constant tail emission rate + /// + /// The decay parameters are determined as described in [#decay_parameters]. + /// + /// ## Tail emission + /// + /// If the feature `mainnet_emission` is not enabled, the tail emission is constant. It is triggered if the reward + /// would fall below the `tail` value. + /// + /// If the feature `mainnet_emission` is enabled, the tail emission is calculated as follows: + /// + /// At each block, the reward is multiplied by `EPOCH_LENGTH` (approximately a year's worth of blocks) to + /// calculate `annual_supply`. + /// If `annual_supply/current_supply` is less than `0.01*inflation_bips`% then we enter tail emission mode. + /// + /// Every `EPOCH_LENGTH` blocks, the inflation rate is recalculated based on the current supply. + /// + /// ## Decay parameters /// /// The `intfloor` function is an integer-math-based multiplication of an integer by a fraction that's very close /// to one (e.g. 0.998,987,123,432)` that @@ -97,12 +113,24 @@ impl EmissionSchedule { /// /// The shift right operation will overflow if shifting more than 63 bits. `new` will panic if any of the decay /// values are greater than or equal to 64. - pub fn new(initial: MicroMinotari, decay: &'static [u64], tail: MicroMinotari) -> EmissionSchedule { + pub fn new( + initial: MicroMinotari, + decay: &'static [u64], + inflation_bips: u64, + epoch_length: u64, + initial_supply: MicroMinotari, + ) -> EmissionSchedule { assert!( decay.iter().all(|i| *i < 64), "Decay value would overflow. All `decay` values must be less than 64" ); - EmissionSchedule { initial, decay, tail } + EmissionSchedule { + initial, + decay, + inflation_bips, + epoch_length, + initial_supply, + } } /// Utility function to calculate the decay parameters that are provided in [EmissionSchedule::new]. This function @@ -113,7 +141,7 @@ impl EmissionSchedule { /// /// Input : `k`: A string representing a floating point number of (nearly) arbitrary precision, and less than one. /// - /// Returns: An array of powers of negative two when when applied as a shift right and sum operation is very + /// Returns: An array of powers of negative two when applied as a shift right and sum operation is very /// close to (1-k)*n. /// /// None - If k is not a valid floating point number less than one. @@ -173,18 +201,6 @@ impl EmissionSchedule { /// the emission curve if you're interested in the supply as well as the reward. /// /// This is an infinite iterator, and each value returned is a tuple of (block number, reward, and total supply) - /// - /// ```edition2018 - /// use tari_core::{ - /// consensus::emission::EmissionSchedule, - /// transactions::tari_amount::MicroMinotari, - /// }; - /// // Print the reward and supply for first 100 blocks - /// let schedule = EmissionSchedule::new(10.into(), &[3], 1.into()); - /// for (n, reward, supply) in schedule.iter().take(100) { - /// println!("{:3} {:9} {:9}", n, reward, supply); - /// } - /// ``` pub fn iter(&self) -> EmissionRate { EmissionRate::new(self) } @@ -203,15 +219,19 @@ pub struct EmissionRate<'a> { supply: MicroMinotari, reward: MicroMinotari, schedule: &'a EmissionSchedule, + epoch: u64, + epoch_counter: u64, } impl<'a> EmissionRate<'a> { fn new(schedule: &'a EmissionSchedule) -> EmissionRate<'a> { EmissionRate { block_num: 0, - supply: MicroMinotari(0), + supply: schedule.initial_supply, reward: MicroMinotari(0), schedule, + epoch: 0, + epoch_counter: 0, } } @@ -227,21 +247,53 @@ impl<'a> EmissionRate<'a> { self.reward } + fn next_decay_reward(&self) -> MicroMinotari { + let r = self.reward.as_u64(); + self.schedule + .decay + .iter() + .fold(self.reward, |sum, i| sum - MicroMinotari::from(r >> *i)) + } + /// Calculates the next reward by multiplying the decay factor by the previous block reward using integer math. /// /// We write the decay factor, 1 - k, as a sum of fraction powers of two. e.g. if we wanted 0.25 as our k, then /// (1-k) would be 0.75 = 1/2 plus 1/4 (1/2^2). /// /// Then we calculate k.R = (1 - e).R = R - e.R = R - (0.5 * R + 0.25 * R) = R - R >> 1 - R >> 2 - fn next_reward(&self) -> MicroMinotari { - let r = self.reward.as_u64(); - let next = self - .schedule - .decay - .iter() - .fold(self.reward, |sum, i| sum - MicroMinotari::from(r >> *i)); + fn next_reward(&mut self) { + // Inflation phase + if self.epoch > 0 { + self.epoch_counter += 1; + if self.epoch_counter >= self.schedule.epoch_length { + self.epoch_counter = 0; + self.epoch += 1; + self.reward = self.new_tail_emission(); + } + } else { + // Decay phase + let cutoff = self.new_tail_emission(); + let next_decay_reward = self.next_decay_reward(); + if self.epoch == 0 && next_decay_reward > cutoff { + self.reward = next_decay_reward; + } else { + self.epoch = 1; + self.reward = cutoff; + } + } + } - cmp::max(next, self.schedule.tail) + fn new_tail_emission(&self) -> MicroMinotari { + // Remember: 100% = 10,000 bips + let epoch_issuance = self + .supply + .as_u128() + .saturating_mul(u128::from(self.schedule.inflation_bips)) / + 10_000u128; + #[allow(clippy::cast_possible_truncation)] + let epoch_issuance = epoch_issuance as u64; // intentionally allow rounding via truncation + let reward = epoch_issuance / self.schedule.epoch_length; // in uT + MicroMinotari::from((reward / 1_000_000) * 1_000_000) // truncate to nearest whole XTR } } @@ -252,11 +304,11 @@ impl Iterator for EmissionRate<'_> { self.block_num += 1; if self.block_num == 1 { self.reward = self.schedule.initial; - self.supply = self.schedule.initial; + self.supply = self.supply.checked_add(self.reward)?; return Some((self.block_num, self.reward, self.supply)); } - self.reward = self.next_reward(); - // Once we've reached max supply, the iterator is done + self.next_reward(); // Has side effect + // Once we've reached max supply, the iterator is done self.supply = self.supply.checked_add(self.reward)?; Some((self.block_num, self.reward, self.supply)) } @@ -280,25 +332,90 @@ impl Emission for EmissionSchedule { #[cfg(test)] mod test { + #[test] + fn calc_array() { + assert_eq!(EmissionSchedule::decay_params("1.00"), None); + assert_eq!(EmissionSchedule::decay_params("56345"), None); + assert_eq!(EmissionSchedule::decay_params("0.75").unwrap(), vec![2]); + assert_eq!(EmissionSchedule::decay_params("0.25").unwrap(), vec![1, 2]); + assert_eq!(EmissionSchedule::decay_params("0.5").unwrap(), vec![1]); + assert_eq!(EmissionSchedule::decay_params("0.875").unwrap(), vec![3]); + assert_eq!(EmissionSchedule::decay_params("0.125").unwrap(), vec![1, 2, 3]); + assert_eq!(EmissionSchedule::decay_params("0.64732").unwrap(), vec![ + 2, 4, 5, 7, 10, 13, 16, 19, 20, 21, 22, 25, 29, 32, 33, 34, 35, 36, 38, 45, 47, 51, 53, 58, 59, 60, 62, 63 + ]); + assert_eq!(EmissionSchedule::decay_params("0.9999991208182701").unwrap(), vec![ + 21, 22, 23, 25, 26, 37, 38, 39, 41, 45, 49, 50, 51, 52, 55, 57, 59, 60, 63 + ]); + assert_eq!(EmissionSchedule::decay_params("0.0").unwrap(), vec![0]); + } + use crate::{ consensus::emission::{Emission, EmissionSchedule}, - transactions::tari_amount::{uT, MicroMinotari, T}, + transactions::tari_amount::{MicroMinotari, T}, }; #[test] - fn schedule() { - let schedule = EmissionSchedule::new( - MicroMinotari::from(10_000_100), - &[22, 23, 24, 26, 27], - MicroMinotari::from(100), - ); - assert_eq!(schedule.block_reward(0), MicroMinotari::from(0)); - assert_eq!(schedule.supply_at_block(0), MicroMinotari::from(0)); - assert_eq!(schedule.block_reward(1), MicroMinotari::from(10_000_100)); - assert_eq!(schedule.supply_at_block(1), MicroMinotari::from(10_000_100)); - // These values have been independently calculated - assert_eq!(schedule.block_reward(100 + 1), MicroMinotari::from(9_999_800)); - assert_eq!(schedule.supply_at_block(100 + 1), MicroMinotari::from(1_009_994_950)); + #[allow(clippy::cast_possible_truncation)] + fn mainnet_emission() { + let epoch_length = 30 * 24 * 366; + let halflife = 3 * 30 * 24 * 365; + let a0 = MicroMinotari::from(12_923_971_428); + let decay = &[21u64, 22, 23, 25, 26, 37, 38, 40]; + let premine = 6_300_000_000 * T; + let schedule = EmissionSchedule::new(a0, decay, 100, epoch_length, premine); + let mut iter = schedule.iter(); + assert_eq!(iter.block_num, 0); + assert_eq!(iter.reward, MicroMinotari::from(0)); + assert_eq!(iter.supply, premine); + let (num, reward, supply) = iter.next().unwrap(); + // Block 1 + assert_eq!(num, 1); + assert_eq!(reward, MicroMinotari::from(12_923_971_428)); + assert_eq!(supply, MicroMinotari::from(6_300_012_923_971_428)); + // Block 2 + let (num, reward, supply) = iter.next().unwrap(); + assert_eq!(num, 2); + assert_eq!(reward, MicroMinotari::from(12_923_960_068)); + assert_eq!(supply, MicroMinotari::from(6_300_025_847_931_496)); + + // Block 788,400. 50% Mined + let mut iter = iter.skip_while(|(num, _, _)| *num < halflife); + let (num, reward, supply) = iter.next().unwrap(); + assert_eq!(num, halflife); + assert_eq!(reward.as_u64(), 6_463_480_936); + let total_supply = 21_000_000_000 * T - premine; + let residual = (supply - premine) * 2 - total_supply; + // Within 0.01% of mining half the total supply + assert!(residual < total_supply / 10000, "Residual: {}", residual); + // Head to tail emission + let mut iter = iter.skip_while(|(num, _, _)| *num < 3_220_980); + let (num, reward, supply) = iter.next().unwrap(); + assert_eq!(num, 3_220_980); + assert_eq!(reward, MicroMinotari::from(764_000_449)); + assert_eq!(supply, MicroMinotari::from(20_140_382_328_948_420)); + let (num, reward, _) = iter.next().unwrap(); + assert_eq!(num, 3_220_981); + assert_eq!(reward, 764 * T); + let (num, reward, _) = iter.next().unwrap(); + assert_eq!(num, 3_220_982); + assert_eq!(reward, 764 * T); + // Next boosting + let mut iter = iter.skip((epoch_length - 3) as usize); + let (num, reward, supply) = iter.next().unwrap(); + assert_eq!(num, 3_484_500); + assert_eq!(reward, 764 * T); + assert_eq!(supply, MicroMinotari::from(20_341_711_608_948_420)); + let (num, reward, _) = iter.next().unwrap(); + assert_eq!(num, 3_484_501); + assert_eq!(reward, 771 * T); + let (num, reward, supply) = iter.next().unwrap(); + assert_eq!(num, 3_484_502); + assert_eq!(reward, 771 * T); + // Check supply inflation. Because of rounding, it could be between 98 and 100 bips + let epoch_supply = 771 * T * epoch_length; + let inflation = (10000 * epoch_supply / supply).as_u64(); // 1 bip => 100 + assert!(inflation < 100 && inflation > 98, "Inflation: {} bips", inflation); } #[test] @@ -308,7 +425,9 @@ mod test { let schedule = EmissionSchedule::new( MicroMinotari::from(10000000u64), &[22, 23, 24, 26, 27], - MicroMinotari::from(100), + 0, + 100000, + MicroMinotari::from(0), ); // Slow but does not overflow assert_eq!(schedule.block_reward(height + 1), MicroMinotari::from(4_194_303)); @@ -320,83 +439,36 @@ mod test { let schedule = EmissionSchedule::new( MicroMinotari::from(INITIAL), &[2], // 0.25 decay - MicroMinotari::from(100), + 1000, + 10, + 100 * T, ); assert_eq!(schedule.block_reward(0), MicroMinotari(0)); - assert_eq!(schedule.supply_at_block(0), MicroMinotari(0)); + assert_eq!(schedule.supply_at_block(0), 100 * T); let values = schedule.iter().take(101).collect::>(); let (height, reward, supply) = values[0]; assert_eq!(height, 1); assert_eq!(reward, MicroMinotari::from(INITIAL)); - assert_eq!(supply, MicroMinotari::from(INITIAL)); + assert_eq!(supply, MicroMinotari::from(INITIAL) + 100 * T); let (height, reward, supply) = values[1]; assert_eq!(height, 2); assert_eq!(reward, MicroMinotari::from(7_500_075)); - assert_eq!(supply, MicroMinotari::from(17_500_175)); + assert_eq!(supply, MicroMinotari::from(117_500_175)); let (height, reward, supply) = values[2]; assert_eq!(height, 3); assert_eq!(reward, MicroMinotari::from(5_625_057)); - assert_eq!(supply, MicroMinotari::from(23_125_232)); - let (height, reward, supply) = values[10]; - assert_eq!(height, 11); - assert_eq!(reward, MicroMinotari::from(563_142)); - assert_eq!(supply, MicroMinotari::from(38_310_986)); - let (height, reward, supply) = values[41]; - assert_eq!(height, 42); - assert_eq!(reward, MicroMinotari::from(100)); - assert_eq!(supply, MicroMinotari::from(40_000_252)); - - let mut tot_supply = MicroMinotari::from(0); - for (_, reward, supply) in schedule.iter().take(1000) { - tot_supply += reward; - assert_eq!(tot_supply, supply); - } - } - - #[test] - #[allow(clippy::identity_op)] - fn emission() { - let emission = EmissionSchedule::new(1 * T, &[1, 2], 100 * uT); - let mut emission = emission.iter(); - // decay is 1 - 0.25 - 0.125 = 0.625 - assert_eq!(emission.block_height(), 0); - assert_eq!(emission.block_reward(), MicroMinotari(0)); - assert_eq!(emission.supply(), MicroMinotari(0)); - - assert_eq!(emission.next(), Some((1, 1_000_000 * uT, 1_000_000 * uT))); - assert_eq!(emission.next(), Some((2, 250_000 * uT, 1_250_000 * uT))); - assert_eq!(emission.next(), Some((3, 62_500 * uT, 1_312_500 * uT))); - assert_eq!(emission.next(), Some((4, 15_625 * uT, 1_328_125 * uT))); - assert_eq!(emission.next(), Some((5, 3_907 * uT, 1_332_032 * uT))); - assert_eq!(emission.next(), Some((6, 978 * uT, 1_333_010 * uT))); - assert_eq!(emission.next(), Some((7, 245 * uT, 1_333_255 * uT))); - // Tail emission kicks in - assert_eq!(emission.next(), Some((8, 100 * uT, 1_333_355 * uT))); - assert_eq!(emission.next(), Some((9, 100 * uT, 1_333_455 * uT))); - - assert_eq!(emission.block_height(), 9); - assert_eq!(emission.block_reward(), 100 * uT); - assert_eq!(emission.supply(), 1333455 * uT); - let schedule = EmissionSchedule::new(1 * T, &[1, 2], 100 * uT); - assert_eq!(emission.block_reward(), schedule.block_reward(9)); - assert_eq!(emission.supply(), schedule.supply_at_block(9)) - } - - #[test] - fn calc_array() { - assert_eq!(EmissionSchedule::decay_params("1.00"), None); - assert_eq!(EmissionSchedule::decay_params("56345"), None); - assert_eq!(EmissionSchedule::decay_params("0.75").unwrap(), vec![2]); - assert_eq!(EmissionSchedule::decay_params("0.25").unwrap(), vec![1, 2]); - assert_eq!(EmissionSchedule::decay_params("0.5").unwrap(), vec![1]); - assert_eq!(EmissionSchedule::decay_params("0.875").unwrap(), vec![3]); - assert_eq!(EmissionSchedule::decay_params("0.125").unwrap(), vec![1, 2, 3]); - assert_eq!(EmissionSchedule::decay_params("0.64732").unwrap(), vec![ - 2, 4, 5, 7, 10, 13, 16, 19, 20, 21, 22, 25, 29, 32, 33, 34, 35, 36, 38, 45, 47, 51, 53, 58, 59, 60, 62, 63 - ]); - assert_eq!(EmissionSchedule::decay_params("0.9999991208182701").unwrap(), vec![ - 21, 22, 23, 25, 26, 37, 38, 39, 41, 45, 49, 50, 51, 52, 55, 57, 59, 60, 63 - ]); - assert_eq!(EmissionSchedule::decay_params("0.0").unwrap(), vec![0]); + assert_eq!(supply, MicroMinotari::from(123_125_232)); + let (height, reward, supply) = values[8]; + assert_eq!(height, 9); + assert_eq!(reward, MicroMinotari::from(1_001_140)); + assert_eq!(supply, MicroMinotari::from(136_996_989)); + let (height, reward, supply) = values[9]; + assert_eq!(height, 10); + assert_eq!(reward, MicroMinotari::from(1_000_000)); + assert_eq!(supply, MicroMinotari::from(137_996_989)); + let (height, reward, supply) = values[99]; + assert_eq!(height, 100); + assert_eq!(reward, MicroMinotari::from(2_000_000)); + assert_eq!(supply, MicroMinotari::from(248_996_989)); } } diff --git a/base_layer/core/src/transactions/tari_amount.rs b/base_layer/core/src/transactions/tari_amount.rs index f679664e81..edb5e9c32f 100644 --- a/base_layer/core/src/transactions/tari_amount.rs +++ b/base_layer/core/src/transactions/tari_amount.rs @@ -148,6 +148,11 @@ impl MicroMinotari { self.0 } + #[inline] + pub fn as_u128(&self) -> u128 { + u128::from(self.0) + } + pub fn to_currency_string(&self, sep: char) -> String { format!("{} µT", format_currency(&self.as_u64().to_string(), sep)) } diff --git a/base_layer/core/src/validation/chain_balance.rs b/base_layer/core/src/validation/chain_balance.rs index ff69eb2e60..c7153d7d21 100644 --- a/base_layer/core/src/validation/chain_balance.rs +++ b/base_layer/core/src/validation/chain_balance.rs @@ -92,8 +92,9 @@ impl ChainBalanceValidator { } fn get_emission_commitment_at(&self, height: u64) -> Commitment { - let total_supply = - self.rules.get_total_emission_at(height) + self.rules.consensus_constants(height).faucet_value(); + // With inflating tail emission, we **must** know the value of the premine as part of the supply calc in order + // to determine the correct inflation curve. Therefore, the premine is already included in the supply + let total_supply = self.rules.get_total_emission_at(height); debug!( target: LOG_TARGET, "Expected emission at height {} is {}", height, total_supply diff --git a/base_layer/core/tests/helpers/sample_blockchains.rs b/base_layer/core/tests/helpers/sample_blockchains.rs index a958186ec3..40c82fb429 100644 --- a/base_layer/core/tests/helpers/sample_blockchains.rs +++ b/base_layer/core/tests/helpers/sample_blockchains.rs @@ -170,6 +170,12 @@ pub async fn create_blockchain_db_no_cut_through() -> ( (db, blocks, outputs, consensus_manager, key_manager) } +pub fn consensus_constants(network: Network) -> ConsensusConstantsBuilder { + ConsensusConstantsBuilder::new(network) + .with_emission_amounts(100_000_000.into(), &EMISSION, 10, 1000) + .with_coinbase_lockheight(1) +} + /// Create a new blockchain database containing only the Genesis block #[allow(dead_code)] pub async fn create_new_blockchain( @@ -182,10 +188,7 @@ pub async fn create_new_blockchain( MemoryDbKeyManager, ) { let key_manager = create_memory_db_key_manager(); - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .with_coinbase_lockheight(1) - .build(); + let consensus_constants = consensus_constants(network).build(); let (block0, output) = create_genesis_block(&consensus_constants, &key_manager).await; let consensus_manager = ConsensusManagerBuilder::new(network) .add_consensus_constants(consensus_constants) @@ -243,10 +246,7 @@ pub async fn create_new_blockchain_lmdb( MemoryDbKeyManager, ) { let key_manager = create_memory_db_key_manager(); - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .with_coinbase_lockheight(1) - .build(); + let consensus_constants = consensus_constants(network).build(); let (block0, output) = create_genesis_block(&consensus_constants, &key_manager).await; let consensus_manager = ConsensusManagerBuilder::new(network) .add_consensus_constants(consensus_constants) diff --git a/base_layer/core/tests/helpers/sync.rs b/base_layer/core/tests/helpers/sync.rs index a15cf7981f..93a77d1fbc 100644 --- a/base_layer/core/tests/helpers/sync.rs +++ b/base_layer/core/tests/helpers/sync.rs @@ -43,7 +43,7 @@ use tari_core::{ }, blocks::ChainBlock, chain_storage::{BlockchainDatabaseConfig, DbTransaction}, - consensus::{ConsensusConstantsBuilder, ConsensusManager, ConsensusManagerBuilder}, + consensus::{ConsensusManager, ConsensusManagerBuilder}, mempool::MempoolServiceConfig, proof_of_work::{randomx_factory::RandomXFactory, Difficulty}, test_helpers::blockchain::TempDatabase, @@ -64,10 +64,9 @@ use tokio::sync::{broadcast, watch}; use crate::helpers::{ block_builders::{append_block, create_genesis_block}, nodes::{create_network_with_multiple_base_nodes_with_config, NodeInterfaces}, + sample_blockchains, }; -static EMISSION: [u64; 2] = [10, 10]; - /// Helper function to initialize header sync with a single peer pub fn initialize_sync_headers_with_ping_pong_data( local_node_interfaces: &NodeInterfaces, @@ -152,9 +151,7 @@ pub async fn create_network_with_multiple_nodes( let network = Network::LocalNet; let temp_dir = tempdir().unwrap(); let key_manager = create_memory_db_key_manager(); - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .build(); + let consensus_constants = sample_blockchains::consensus_constants(network).build(); let (initial_block, coinbase_wallet_output) = create_genesis_block(&consensus_constants, &key_manager).await; let consensus_manager = ConsensusManagerBuilder::new(network) .add_consensus_constants(consensus_constants) diff --git a/base_layer/core/tests/tests/mempool.rs b/base_layer/core/tests/tests/mempool.rs index 8601ea4c95..9feb7c180f 100644 --- a/base_layer/core/tests/tests/mempool.rs +++ b/base_layer/core/tests/tests/mempool.rs @@ -1036,16 +1036,14 @@ async fn test_reorg() { mempool.process_reorg(vec![], vec![reorg_block4.into()]).await.unwrap(); } -static EMISSION: [u64; 2] = [10, 10]; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] #[allow(clippy::too_many_lines)] #[allow(clippy::identity_op)] async fn receive_and_propagate_transaction() { let temp_dir = tempdir().unwrap(); let network = Network::LocalNet; - let consensus_constants = ConsensusConstantsBuilder::new(network) + let consensus_constants = crate::helpers::sample_blockchains::consensus_constants(network) .with_coinbase_lockheight(100) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) .build(); let key_manager = create_memory_db_key_manager(); let (block0, utxo) = create_genesis_block(&consensus_constants, &key_manager).await; @@ -1171,10 +1169,8 @@ async fn receive_and_propagate_transaction() { #[allow(clippy::too_many_lines)] async fn consensus_validation_large_tx() { let network = Network::LocalNet; - // We dont want to compute the 19500 limit of local net, so we create smaller blocks - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .with_coinbase_lockheight(1) + // We don't want to compute the 19500 limit of local net, so we create smaller blocks + let consensus_constants = crate::helpers::sample_blockchains::consensus_constants(network) .with_max_block_transaction_weight(500) .build(); let (mut store, mut blocks, mut outputs, consensus_manager, key_manager) = @@ -1357,9 +1353,7 @@ async fn consensus_validation_large_tx() { async fn validation_reject_min_fee() { let network = Network::LocalNet; // We dont want to compute the 19500 limit of local net, so we create smaller blocks - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .with_coinbase_lockheight(1) + let consensus_constants = crate::helpers::sample_blockchains::consensus_constants(network) .with_max_block_transaction_weight(500) .build(); let (mut store, mut blocks, mut outputs, consensus_manager, key_manager) = diff --git a/base_layer/core/tests/tests/node_service.rs b/base_layer/core/tests/tests/node_service.rs index c03a0d7b23..cc36517d53 100644 --- a/base_layer/core/tests/tests/node_service.rs +++ b/base_layer/core/tests/tests/node_service.rs @@ -32,7 +32,7 @@ use tari_core::{ }, blocks::{ChainBlock, NewBlock}, chain_storage::BlockchainDatabaseConfig, - consensus::{ConsensusConstantsBuilder, ConsensusManager, ConsensusManagerBuilder, NetworkConsensus}, + consensus::{ConsensusManager, ConsensusManagerBuilder, NetworkConsensus}, mempool::TxStorageResponse, proof_of_work::{randomx_factory::RandomXFactory, Difficulty, PowAlgorithm}, transactions::{ @@ -88,9 +88,7 @@ async fn propagate_and_forward_many_valid_blocks() { let carol_node_identity = random_node_identity(); let dan_node_identity = random_node_identity(); let network = Network::LocalNet; - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .build(); + let consensus_constants = crate::helpers::sample_blockchains::consensus_constants(network).build(); let (block0, outputs) = create_genesis_block_with_utxos(&[T, T], &consensus_constants, &key_manager).await; let (tx01, _tx01_out) = spend_utxos( @@ -222,7 +220,6 @@ async fn propagate_and_forward_many_valid_blocks() { dan_node.shutdown().await; } -static EMISSION: [u64; 2] = [10, 10]; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] #[allow(clippy::too_many_lines)] async fn propagate_and_forward_invalid_block_hash() { @@ -237,9 +234,7 @@ async fn propagate_and_forward_invalid_block_hash() { let carol_node_identity = random_node_identity(); let network = Network::LocalNet; let key_manager = create_memory_db_key_manager(); - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .build(); + let consensus_constants = crate::helpers::sample_blockchains::consensus_constants(network).build(); let (block0, genesis_coinbase) = create_genesis_block(&consensus_constants, &key_manager).await; let rules = ConsensusManager::builder(network) .add_consensus_constants(consensus_constants) @@ -370,9 +365,7 @@ async fn propagate_and_forward_invalid_block() { let dan_node_identity = random_node_identity(); let key_manager = create_memory_db_key_manager(); let network = Network::LocalNet; - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .build(); + let consensus_constants = crate::helpers::sample_blockchains::consensus_constants(network).build(); let (block0, _) = create_genesis_block(&consensus_constants, &key_manager).await; let rules = ConsensusManager::builder(network) .add_consensus_constants(consensus_constants) diff --git a/base_layer/core/tests/tests/node_state_machine.rs b/base_layer/core/tests/tests/node_state_machine.rs index aef35ca56c..62c2f7770c 100644 --- a/base_layer/core/tests/tests/node_state_machine.rs +++ b/base_layer/core/tests/tests/node_state_machine.rs @@ -37,7 +37,7 @@ use tari_core::{ SyncValidators, }, chain_storage::BlockchainDatabaseConfig, - consensus::{ConsensusConstantsBuilder, ConsensusManagerBuilder}, + consensus::ConsensusManagerBuilder, mempool::MempoolServiceConfig, proof_of_work::{randomx_factory::RandomXFactory, Difficulty}, test_helpers::blockchain::create_test_blockchain_db, @@ -66,15 +66,12 @@ use crate::helpers::{ }, }; -static EMISSION: [u64; 2] = [10, 10]; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_listening_lagging() { let network = Network::LocalNet; let temp_dir = tempdir().unwrap(); let key_manager = create_memory_db_key_manager(); - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .build(); + let consensus_constants = crate::helpers::sample_blockchains::consensus_constants(network).build(); let (prev_block, _) = create_genesis_block(&consensus_constants, &key_manager).await; let consensus_manager = ConsensusManagerBuilder::new(network) .add_consensus_constants(consensus_constants) @@ -158,9 +155,7 @@ async fn test_listening_initial_fallen_behind() { let network = Network::LocalNet; let temp_dir = tempdir().unwrap(); let key_manager = create_memory_db_key_manager(); - let consensus_constants = ConsensusConstantsBuilder::new(network) - .with_emission_amounts(100_000_000.into(), &EMISSION, 100.into()) - .build(); + let consensus_constants = crate::helpers::sample_blockchains::consensus_constants(network).build(); let (gen_block, _) = create_genesis_block(&consensus_constants, &key_manager).await; let consensus_manager = ConsensusManagerBuilder::new(network) .add_consensus_constants(consensus_constants)