From ec40923b7c9654dfae673bb9496de3c56c927978 Mon Sep 17 00:00:00 2001 From: lesniak43 Date: Fri, 4 Oct 2024 13:58:06 +0200 Subject: [PATCH 1/3] L1-292: `era_payout` unit tests (#1818) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Unit tests for `era_payout`. ## Type of change - New feature (non-breaking change which adds functionality) # Checklist: - I have added tests --------- Co-authored-by: Damian Leśniak --- bin/runtime/src/lib.rs | 165 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/bin/runtime/src/lib.rs b/bin/runtime/src/lib.rs index 1a4e2a3c64..0ac8abd130 100644 --- a/bin/runtime/src/lib.rs +++ b/bin/runtime/src/lib.rs @@ -1356,6 +1356,7 @@ impl_runtime_apis! { #[cfg(test)] mod tests { use frame_support::traits::Get; + use pallet_staking::EraPayout; use primitives::HEAP_PAGES; use smallvec::Array; @@ -1571,4 +1572,168 @@ mod tests { assert!(lhs < rhs); } + + /// `EraPayout::era_payout` ignores the first argument, we set it to zero. + const DUMMY_TOTAL_STAKED: Balance = 0; + const MILLISECS_PER_DAY: u64 = 24 * 60 * 60 * 1000; + + struct EraPayoutInputs { + azero_cap: Balance, + horizon: u64, + total_issuance: Balance, + era_duration_millis: u64, + } + + struct EraPayoutOutputs { + validators_payout: Balance, + rest: Balance, + } + + fn assert_era_payout(inputs: EraPayoutInputs, outputs: EraPayoutOutputs) { + use sp_io::TestExternalities; + TestExternalities::default().execute_with(|| { + pallet_aleph::AzeroCap::::put(inputs.azero_cap); + pallet_aleph::ExponentialInflationHorizon::::put(inputs.horizon); + let (validators_payout, rest) = + ::EraPayout::era_payout( + DUMMY_TOTAL_STAKED, + inputs.total_issuance, + inputs.era_duration_millis, + ); + assert_eq!(validators_payout, outputs.validators_payout); + assert_eq!(rest, outputs.rest); + }); + } + + fn era_payout_multiple_eras( + inputs: EraPayoutInputs, + n_eras: usize, + ) -> (Vec, Balance) { + use sp_io::TestExternalities; + let mut outputs = vec![]; + let mut total_issuance = inputs.total_issuance; + for _ in 0..n_eras { + TestExternalities::default().execute_with(|| { + pallet_aleph::AzeroCap::::put(inputs.azero_cap); + pallet_aleph::ExponentialInflationHorizon::::put(inputs.horizon); + let (validators_payout, rest) = + ::EraPayout::era_payout( + DUMMY_TOTAL_STAKED, + total_issuance, + inputs.era_duration_millis, + ); + outputs.push(EraPayoutOutputs { + validators_payout, + rest, + }); + total_issuance += validators_payout + rest; + }); + } + (outputs, total_issuance) + } + + #[test] + fn era_payout_standard_case() { + assert_era_payout( + EraPayoutInputs { + azero_cap: 100_000_000 * TOKEN, + horizon: 365 * MILLISECS_PER_DAY, + total_issuance: 50_000_000 * TOKEN, + era_duration_millis: MILLISECS_PER_DAY, + }, + EraPayoutOutputs { + validators_payout: 123_118 * TOKEN + 920_000_000_000, + rest: 13_679 * TOKEN + 880_000_000_000, + }, + ); + } + + #[test] + /// Simulate long run by calling `era_payout` multiple times, + /// and keeping track of `total_issuance` between calls. + /// After 3 * horizon milliseconds the gap should be reduced by ~95%. + fn era_payout_long_run() { + let (_, total_issuance) = era_payout_multiple_eras( + EraPayoutInputs { + azero_cap: 150_000_000 * TOKEN, + horizon: 365 * MILLISECS_PER_DAY, + total_issuance: 50_000_000 * TOKEN, + era_duration_millis: MILLISECS_PER_DAY, + }, + 3 * 365, + ); + assert_eq!(total_issuance, 145_021_290 * TOKEN + 959_387_724_274); + } + + #[test] + /// Era longer than horizon. + /// Perbill will saturate, (era_duration_millis / horizon) == 1, + /// even if horizon == 0. + /// The actual values do not matter, only the ratio is used. + /// We expect the gap to be reduced by ~63%. + fn era_payout_horizon_too_short() { + assert_era_payout( + EraPayoutInputs { + azero_cap: 100_000_000 * TOKEN, + horizon: 0, + total_issuance: 50_000_000 * TOKEN, + era_duration_millis: MILLISECS_PER_DAY, + }, + EraPayoutOutputs { + validators_payout: 28_499_999 * TOKEN + 985_000_000_000, + rest: 3_166_666 * TOKEN + 665_000_000_000, + }, + ); + } + + #[test] + /// AZERO cap equal to total issuance, we expect no payout. + fn era_payout_cap_reached() { + assert_era_payout( + EraPayoutInputs { + azero_cap: 100_000_000 * TOKEN, + horizon: 365 * MILLISECS_PER_DAY, + total_issuance: 100_000_000 * TOKEN, + era_duration_millis: MILLISECS_PER_DAY, + }, + EraPayoutOutputs { + validators_payout: 0, + rest: 0, + }, + ); + } + + #[test] + /// Total issuance larger than AZERO cap, we expect no payout. + fn era_payout_cap_exceeded() { + assert_era_payout( + EraPayoutInputs { + azero_cap: 50_000_000 * TOKEN, + horizon: 365 * MILLISECS_PER_DAY, + total_issuance: 100_000_000 * TOKEN, + era_duration_millis: MILLISECS_PER_DAY, + }, + EraPayoutOutputs { + validators_payout: 0, + rest: 0, + }, + ); + } + + #[test] + /// Zero-length era, we expect no payout (as it depends on era lenght). + fn era_payout_zero_lenght_era() { + assert_era_payout( + EraPayoutInputs { + azero_cap: 100_000_000 * TOKEN, + horizon: 365 * MILLISECS_PER_DAY, + total_issuance: 50_000_000 * TOKEN, + era_duration_millis: 0, + }, + EraPayoutOutputs { + validators_payout: 0, + rest: 0, + }, + ); + } } From f7af9c7a173c3c6d27b503cd803a6b20a75c1923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Le=C5=9Bniak?= Date: Tue, 8 Oct 2024 13:05:12 +0200 Subject: [PATCH 2/3] fix --- bin/runtime/src/lib.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/bin/runtime/src/lib.rs b/bin/runtime/src/lib.rs index 31bbc34b7c..bff0dd14d1 100644 --- a/bin/runtime/src/lib.rs +++ b/bin/runtime/src/lib.rs @@ -1606,8 +1606,6 @@ mod tests { assert!(lhs < rhs); } - /// `EraPayout::era_payout` ignores the first argument, we set it to zero. - const DUMMY_TOTAL_STAKED: Balance = 0; const MILLISECS_PER_DAY: u64 = 24 * 60 * 60 * 1000; struct EraPayoutInputs { @@ -1628,11 +1626,7 @@ mod tests { pallet_aleph::AzeroCap::::put(inputs.azero_cap); pallet_aleph::ExponentialInflationHorizon::::put(inputs.horizon); let (validators_payout, rest) = - ::EraPayout::era_payout( - DUMMY_TOTAL_STAKED, - inputs.total_issuance, - inputs.era_duration_millis, - ); + ExponentialEraPayout::era_payout(inputs.total_issuance, inputs.era_duration_millis); assert_eq!(validators_payout, outputs.validators_payout); assert_eq!(rest, outputs.rest); }); @@ -1650,11 +1644,7 @@ mod tests { pallet_aleph::AzeroCap::::put(inputs.azero_cap); pallet_aleph::ExponentialInflationHorizon::::put(inputs.horizon); let (validators_payout, rest) = - ::EraPayout::era_payout( - DUMMY_TOTAL_STAKED, - total_issuance, - inputs.era_duration_millis, - ); + ExponentialEraPayout::era_payout(total_issuance, inputs.era_duration_millis); outputs.push(EraPayoutOutputs { validators_payout, rest, From e7793487db2ded30e80818315c807b0d618e3eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Le=C5=9Bniak?= Date: Tue, 8 Oct 2024 13:26:13 +0200 Subject: [PATCH 3/3] fix --- bin/runtime/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/runtime/src/lib.rs b/bin/runtime/src/lib.rs index bff0dd14d1..2494a79614 100644 --- a/bin/runtime/src/lib.rs +++ b/bin/runtime/src/lib.rs @@ -1389,7 +1389,6 @@ impl_runtime_apis! { #[cfg(test)] mod tests { use frame_support::traits::Get; - use pallet_staking::EraPayout; use primitives::HEAP_PAGES; use smallvec::Array;