From 41073bfee9a9e8cc80c8e3e27121de3b74a721ba Mon Sep 17 00:00:00 2001 From: Herr Seppia Date: Thu, 5 Sep 2024 22:28:35 +0200 Subject: [PATCH 1/3] rusk: adapt emission schedule to emit 500M dusk --- rusk/src/lib/node.rs | 69 +++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/rusk/src/lib/node.rs b/rusk/src/lib/node.rs index df4daeba3d..4800d3b74a 100644 --- a/rusk/src/lib/node.rs +++ b/rusk/src/lib/node.rs @@ -237,8 +237,8 @@ const fn coinbase_value( /// The emission schedule works as follows: /// - the emission follows a Bitcoin-like halving function -/// - a total 499_782_528 Dusk will be emitted over 36 years divided in 9 -/// periods of 4 years each +/// - a total 500.000.000,256000 Dusk will be emitted over 36 years divided in +/// 9 periods of 4 years each /// /// Considering the target block rate of 10 seconds, we assume a production of /// 8640 blocks per day, which corresponds to 12_614_400 blocks per period. @@ -248,19 +248,28 @@ const BLOCKS_PER_DAY: u64 = 8640; // Target block production per 4-year period const BLOCKS_PER_PERIOD: u64 = BLOCKS_PER_DAY * 365 * 4; // Block emission for each period, following the halving function -const BLOCK_EMISSIONS: [f64; 9] = - [19.86, 9.93, 4.96, 2.48, 1.24, 0.62, 0.31, 0.15, 0.07]; +const BLOCK_EMISSIONS: [u64; 9] = [ + dusk(19.8574), + dusk(9.9287), + dusk(4.96435), + dusk(2.48218), + dusk(1.24109), + dusk(0.62054), + dusk(0.31027), + dusk(0.15514), + dusk(0.07757), +]; // Returns the block emission for a certain height pub const fn emission_amount(block_height: u64) -> Dusk { if block_height == 0 { - return dusk(0.0); + return 0; } let period = (block_height - 1) / BLOCKS_PER_PERIOD; match period { - 0..=8 => dusk(BLOCK_EMISSIONS[period as usize]), - _ => dusk(0.0), + 0..=8 => BLOCK_EMISSIONS[period as usize], + _ => 0, } } @@ -281,16 +290,17 @@ mod tests { // Block range and expected emission for each period let test_cases = vec![ - (1, 12_614_400, dusk(19.86)), // Period 1 - (12_614_401, 25_228_800, dusk(9.93)), // Period 2 - (25_228_801, 37_843_200, dusk(4.96)), // Period 3 - (37_843_201, 50_457_600, dusk(2.48)), // Period 4 - (50_457_601, 63_072_000, dusk(1.24)), // Period 5 - (63_072_001, 75_686_400, dusk(0.62)), // Period 6 - (75_686_401, 88_300_800, dusk(0.31)), // Period 7 - (88_300_801, 100_915_200, dusk(0.15)), // Period 8 - (100_915_201, 113_529_600, dusk(0.07)), // Period 9 - (113_529_601, u64::MAX, dusk(0.0)), // Beyond period 9 + (0, 0, dusk(0.0)), // Genesis + (1, 12_614_400, dusk(19.8574)), // Period 1 + (12_614_401, 25_228_800, dusk(9.9287)), // Period 2 + (25_228_801, 37_843_200, dusk(4.96435)), // Period 3 + (37_843_201, 50_457_600, dusk(2.48218)), // Period 4 + (50_457_601, 63_072_000, dusk(1.24109)), // Period 5 + (63_072_001, 75_686_400, dusk(0.62054)), // Period 6 + (75_686_401, 88_300_800, dusk(0.31027)), // Period 7 + (88_300_801, 100_915_200, dusk(0.15514)), // Period 8 + (100_915_201, 113_529_600, dusk(0.07757)), // Period 9 + (113_529_601, u64::MAX, dusk(0.0)), // Beyond period 9 ]; // Test emission periods @@ -314,15 +324,15 @@ mod tests { } const EXPECTED_PERIOD_EMISSIONS: [u64; 9] = [ - 250_521_984, // Period 1 - 125_260_992, // Period 2 - 62_567_424, // Period 3 - 31_283_712, // Period 4 - 15_641_856, // Period 5 - 7_820_928, // Period 6 - 3_910_464, // Period 7 - 1_892_160, // Period 8 - 883_008, // Period 9 + dusk(250_489_186.56), // Period 1 + dusk(125_244_593.28), // Period 2 + dusk(62_622_296.64), // Period 3 + dusk(31_311_211.392), // Period 4 + dusk(15_655_605.696), // Period 5 + dusk(7_827_739.776), // Period 6 + dusk(3_913_869.888), // Period 7 + dusk(1_956_998.016), // Period 8 + dusk(978_499.008), // Period 9 ]; #[test] @@ -330,8 +340,7 @@ mod tests { // Check each period emission corresponds to the expected value for (i, &expected) in EXPECTED_PERIOD_EMISSIONS.iter().enumerate() { let block_emission = BLOCK_EMISSIONS[i]; - let period_emission = - (block_emission * BLOCKS_PER_PERIOD as f64) as u64; + let period_emission = block_emission * BLOCKS_PER_PERIOD; assert_eq!( period_emission, expected, @@ -346,12 +355,12 @@ mod tests { #[test] fn test_total_emission() { // Expected total emission based on the schedule - let expected_total = 499_782_528u64; + let expected_total = dusk(500_000_000.256); // Loop through each block emission and calculate the total emission let mut total_emission = 0u64; for &be in BLOCK_EMISSIONS.iter() { - total_emission += (be * BLOCKS_PER_PERIOD as f64) as u64; + total_emission += be * BLOCKS_PER_PERIOD; } // Ensure the calculated total matches the expected total From fec13fd907a56cce431a38bf2c5f41fd860c086a Mon Sep 17 00:00:00 2001 From: Herr Seppia Date: Fri, 6 Sep 2024 13:47:03 +0200 Subject: [PATCH 2/3] rusk: change emission to be exactly 500M dusk --- rusk/src/lib/node.rs | 121 +++++++++++++------------------------------ 1 file changed, 37 insertions(+), 84 deletions(-) diff --git a/rusk/src/lib/node.rs b/rusk/src/lib/node.rs index 4800d3b74a..a409947786 100644 --- a/rusk/src/lib/node.rs +++ b/rusk/src/lib/node.rs @@ -237,38 +237,27 @@ const fn coinbase_value( /// The emission schedule works as follows: /// - the emission follows a Bitcoin-like halving function -/// - a total 500.000.000,256000 Dusk will be emitted over 36 years divided in -/// 9 periods of 4 years each +/// - a total 500.000.000 Dusk will be emitted over 36 years divided in 9 +/// periods of 4 years each /// /// Considering the target block rate of 10 seconds, we assume a production of /// 8640 blocks per day, which corresponds to 12_614_400 blocks per period. -// Target block production per day, assuming a block rate of 10 seconds -const BLOCKS_PER_DAY: u64 = 8640; -// Target block production per 4-year period -const BLOCKS_PER_PERIOD: u64 = BLOCKS_PER_DAY * 365 * 4; -// Block emission for each period, following the halving function -const BLOCK_EMISSIONS: [u64; 9] = [ - dusk(19.8574), - dusk(9.9287), - dusk(4.96435), - dusk(2.48218), - dusk(1.24109), - dusk(0.62054), - dusk(0.31027), - dusk(0.15514), - dusk(0.07757), -]; - -// Returns the block emission for a certain height +// Returns the block emission for a certain height, following the halving +// function pub const fn emission_amount(block_height: u64) -> Dusk { - if block_height == 0 { - return 0; - } - - let period = (block_height - 1) / BLOCKS_PER_PERIOD; - match period { - 0..=8 => BLOCK_EMISSIONS[period as usize], + match block_height { + 0 => 0, // Genesis + 1..=12_614_400 => dusk(19.8574), // Period 1 + 12_614_401..=25_228_800 => dusk(9.9287), // Period 2 + 25_228_801..=37_843_200 => dusk(4.96435), // Period 3 + 37_843_201..=50_457_600 => dusk(2.48218), // Period 4 + 50_457_601..=63_072_000 => dusk(1.24109), // Period 5 + 63_072_001..=75_686_400 => dusk(0.62054), // Period 6 + 75_686_401..=88_300_800 => dusk(0.31027), // Period 7 + 88_300_801..=100_915_200 => dusk(0.15514), // Period 8 + 100_915_201..=113_529_596 => dusk(0.07757), // Period 9 + 113_529_597 => dusk(0.05428), // Last mint _ => 0, } } @@ -277,53 +266,12 @@ pub const fn emission_amount(block_height: u64) -> Dusk { mod tests { use super::*; - #[test] - fn test_emission_amount() { - // Test genesis block - let genesis_emission = emission_amount(0); - assert_eq!( - genesis_emission, - dusk(0.0), - "For genesis block expected emission 0.0, but got {}", - genesis_emission - ); - - // Block range and expected emission for each period - let test_cases = vec![ - (0, 0, dusk(0.0)), // Genesis - (1, 12_614_400, dusk(19.8574)), // Period 1 - (12_614_401, 25_228_800, dusk(9.9287)), // Period 2 - (25_228_801, 37_843_200, dusk(4.96435)), // Period 3 - (37_843_201, 50_457_600, dusk(2.48218)), // Period 4 - (50_457_601, 63_072_000, dusk(1.24109)), // Period 5 - (63_072_001, 75_686_400, dusk(0.62054)), // Period 6 - (75_686_401, 88_300_800, dusk(0.31027)), // Period 7 - (88_300_801, 100_915_200, dusk(0.15514)), // Period 8 - (100_915_201, 113_529_600, dusk(0.07757)), // Period 9 - (113_529_601, u64::MAX, dusk(0.0)), // Beyond period 9 - ]; - - // Test emission periods - for (start_block, end_block, expected_emission) in test_cases { - // Test the first block in the range - let emission_start = emission_amount(start_block); - assert_eq!( - emission_start, expected_emission, - "For block height {} expected emission {}, but got {}", - start_block, expected_emission, emission_start - ); - - // Test the last block in the range - let emission_end = emission_amount(end_block); - assert_eq!( - emission_end, expected_emission, - "For block height {} expected emission {}, but got {}", - end_block, expected_emission, emission_end - ); - } - } + // Target block production per day, assuming a block rate of 10 seconds + const BLOCKS_PER_DAY: u64 = 8640; + // Target block production per 4-year period + const BLOCKS_PER_PERIOD: u64 = BLOCKS_PER_DAY * 365 * 4; - const EXPECTED_PERIOD_EMISSIONS: [u64; 9] = [ + const EXPECTED_PERIOD_EMISSIONS: [u64; 10] = [ dusk(250_489_186.56), // Period 1 dusk(125_244_593.28), // Period 2 dusk(62_622_296.64), // Period 3 @@ -332,20 +280,26 @@ mod tests { dusk(7_827_739.776), // Period 6 dusk(3_913_869.888), // Period 7 dusk(1_956_998.016), // Period 8 - dusk(978_499.008), // Period 9 + dusk(978_498.752), // Period 9 + dusk(0.0), // Period 9 ]; #[test] fn test_period_emissions() { // Check each period emission corresponds to the expected value - for (i, &expected) in EXPECTED_PERIOD_EMISSIONS.iter().enumerate() { - let block_emission = BLOCK_EMISSIONS[i]; - let period_emission = block_emission * BLOCKS_PER_PERIOD; + for (period, &expected) in EXPECTED_PERIOD_EMISSIONS.iter().enumerate() + { + let start_block = (period as u64 * BLOCKS_PER_PERIOD) + 1; + let end_block = start_block + BLOCKS_PER_PERIOD; + let mut period_emission = 0; + for height in start_block..end_block { + period_emission += emission_amount(height); + } assert_eq!( period_emission, expected, "Emission for period {} did not match: expected {}, got {}", - i + 1, + period + 1, expected, period_emission ); @@ -354,14 +308,13 @@ mod tests { #[test] fn test_total_emission() { - // Expected total emission based on the schedule - let expected_total = dusk(500_000_000.256); - - // Loop through each block emission and calculate the total emission let mut total_emission = 0u64; - for &be in BLOCK_EMISSIONS.iter() { - total_emission += be * BLOCKS_PER_PERIOD; + // Loop through each block emission and calculate the total emission + for h in 0..=BLOCKS_PER_PERIOD * 10 { + total_emission += emission_amount(h) } + // Expected total emission based on the schedule + let expected_total = dusk(500_000_000.0); // Ensure the calculated total matches the expected total assert_eq!( From 614c3adc646ce20cd697fb7bab015ed7742ebda2 Mon Sep 17 00:00:00 2001 From: "Mr. Seppia" Date: Fri, 6 Sep 2024 14:50:25 +0200 Subject: [PATCH 3/3] rusk: fix comment Co-authored-by: Federico Franzoni <8609060+fed-franz@users.noreply.github.com> --- rusk/src/lib/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rusk/src/lib/node.rs b/rusk/src/lib/node.rs index a409947786..00748870db 100644 --- a/rusk/src/lib/node.rs +++ b/rusk/src/lib/node.rs @@ -281,7 +281,7 @@ mod tests { dusk(3_913_869.888), // Period 7 dusk(1_956_998.016), // Period 8 dusk(978_498.752), // Period 9 - dusk(0.0), // Period 9 + dusk(0.0), // After Period 9 ]; #[test]