Skip to content

Commit

Permalink
Merge pull request #2283 from dusk-network/emission-schedule
Browse files Browse the repository at this point in the history
rusk: adapt emission schedule to emit 500M dusk
  • Loading branch information
herr-seppia authored Sep 6, 2024
2 parents 267c094 + 614c3ad commit 7e64c14
Showing 1 changed file with 46 additions and 84 deletions.
130 changes: 46 additions & 84 deletions rusk/src/lib/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,106 +237,69 @@ 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
/// - 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: [f64; 9] =
[19.86, 9.93, 4.96, 2.48, 1.24, 0.62, 0.31, 0.15, 0.07];

// 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 dusk(0.0);
}

let period = (block_height - 1) / BLOCKS_PER_PERIOD;
match period {
0..=8 => dusk(BLOCK_EMISSIONS[period as usize]),
_ => dusk(0.0),
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,
}
}

#[cfg(test)]
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![
(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
];

// 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
);
}
}

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
// 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; 10] = [
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_498.752), // Period 9
dusk(0.0), // After 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 as f64) as u64;
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
);
Expand All @@ -345,14 +308,13 @@ mod tests {

#[test]
fn test_total_emission() {
// Expected total emission based on the schedule
let expected_total = 499_782_528u64;

// 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;
// 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!(
Expand Down

0 comments on commit 7e64c14

Please sign in to comment.