Skip to content

Commit

Permalink
Refactor function related to issuing (#1371)
Browse files Browse the repository at this point in the history
* Rename

* Refactor inflation

* Refactor

* Doc

* Correct doc

---------

Co-authored-by: fisher <hackfisher@gmail.com>
  • Loading branch information
aurexav and hackfisher authored Jan 4, 2024
1 parent d12b775 commit 0f667c8
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 113 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ jobs:
runs-on: ubuntu-latest
needs: [build-nodes, build-runtimes, publish-docker-image]
steps:
- name: Fetch template
- name: Fetch note template
uses: actions/checkout@v4
- name: Download nodes and runtimes
uses: actions/download-artifact@v4
Expand Down
147 changes: 113 additions & 34 deletions core/inflation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,50 +28,129 @@ mod test;
// crates.io
use primitive_types::U256;
// darwinia
use dc_types::{Balance, Moment, UNIT};
use dc_types::{Balance, Moment};
// github
use substrate_fixed::{
transcendental,
types::{I95F33, U94F34},
};

/// Inflation's upper limit.
pub const TOTAL_SUPPLY: Balance = 10_000_000_000 * UNIT;
use substrate_fixed::types::U94F34;

/// Milliseconds per year.
pub const MILLISECS_PER_YEAR: Balance = (366 * 24 * 60 * 60) * 1000;

/// Compute the inflation of a period.
/// Issuing maps for ages 1 to 100 years.
pub const ISSUING_MAP: [Balance; 100] = [
80000000000000000000000000,
111773286000000000000000000,
134746987000000000000000000,
152702244000000000000000000,
167131169000000000000000000,
178823309000000000000000000,
188269287000000000000000000,
195807995000000000000000000,
201691935000000000000000000,
206120192000000000000000000,
209256584000000000000000000,
211240393000000000000000000,
212192983000000000000000000,
212222105000000000000000000,
211424760000000000000000000,
209889162000000000000000000,
207696140000000000000000000,
204920129000000000000000000,
201629917000000000000000000,
197889213000000000000000000,
193757076000000000000000000,
189288266000000000000000000,
184533528000000000000000000,
179539841000000000000000000,
174350616000000000000000000,
169005897000000000000000000,
163542519000000000000000000,
157994277000000000000000000,
152392074000000000000000000,
146764063000000000000000000,
141135790000000000000000000,
135530328000000000000000000,
129968413000000000000000000,
124468570000000000000000000,
119047241000000000000000000,
113718915000000000000000000,
108496242000000000000000000,
103390155000000000000000000,
98409990000000000000000000,
93563591000000000000000000,
88857424000000000000000000,
84296682000000000000000000,
79885385000000000000000000,
75626479000000000000000000,
71521926000000000000000000,
67572800000000000000000000,
63779363000000000000000000,
60141155000000000000000000,
56657064000000000000000000,
53325400000000000000000000,
50143962000000000000000000,
47110103000000000000000000,
44220789000000000000000000,
41472652000000000000000000,
38862045000000000000000000,
36385086000000000000000000,
34037705000000000000000000,
31815679000000000000000000,
29714676000000000000000000,
27730281000000000000000000,
25858032000000000000000000,
24093442000000000000000000,
22432030000000000000000000,
20869335000000000000000000,
19400942000000000000000000,
18022495000000000000000000,
16729714000000000000000000,
15518406000000000000000000,
14384477000000000000000000,
13323941000000000000000000,
12332926000000000000000000,
11407684000000000000000000,
10544591000000000000000000,
9740153000000000000000000,
8991010000000000000000000,
8293934000000000000000000,
7645831000000000000000000,
7043743000000000000000000,
6484844000000000000000000,
5966438000000000000000000,
5485963000000000000000000,
5040980000000000000000000,
4629177000000000000000000,
4248363000000000000000000,
3896462000000000000000000,
3571515000000000000000000,
3271673000000000000000000,
2995191000000000000000000,
2740429000000000000000000,
2505842000000000000000000,
2289982000000000000000000,
2091489000000000000000000,
1909087000000000000000000,
1741584000000000000000000,
1587865000000000000000000,
1446887000000000000000000,
1317679000000000000000000,
1199333000000000000000000,
1091005000000000000000000,
991910000000000000000000,
];

/// Calculate the issuing of a period.
///
/// Use `U94F34` here, because `2^94 > TOTAL_SUPPLY * 10^18`.
pub fn in_period(unminted: Balance, period: Moment, elapsed: Moment) -> Option<Balance> {
let unminted_per_millisecs = U94F34::checked_from_num(unminted)? / MILLISECS_PER_YEAR;
let x =
(unminted_per_millisecs.checked_mul(U94F34::checked_from_num(period)?)?).floor().to_num();
let years = (elapsed / MILLISECS_PER_YEAR + 1) as _;

inflate(x, years)
}

// Compute the inflation.
//
// Formula:
// ```
// x * (1 - (99 / 100) ^ sqrt(years));
// ```
//
// Use `I95F33` here, because `2^94 > TOTAL_SUPPLY * 10^18`.
fn inflate(x: Balance, years: u8) -> Option<Balance> {
let sqrt = transcendental::sqrt::<I95F33, I95F33>(years.into()).ok()?;
let ninety_nine = I95F33::from_num(99_u8) / 100_i128;
let pow = transcendental::pow::<I95F33, I95F33>(ninety_nine, sqrt).ok()?;
let ratio = I95F33::from_num(1_u8) - pow;
let inflation = I95F33::checked_from_num(x)? * ratio;
pub fn issuing_in_period(period: Moment, elapsed: Moment) -> Option<Balance> {
let years = (elapsed / MILLISECS_PER_YEAR) as usize;
let to_issue = ISSUING_MAP[years];
let to_issue_per_millisecs = U94F34::checked_from_num(to_issue)? / MILLISECS_PER_YEAR;

Some(inflation.floor().to_num())
Some(to_issue_per_millisecs.checked_mul(U94F34::checked_from_num(period)?)?.floor().to_num())
}

/// Compute the reward of a deposit.
/// Calculate the reward of a deposit.
///
/// Reference(s):
/// - <https://github.com/evolutionlandorg/bank/blob/master/contracts/GringottsBank.sol#L280>
Expand Down
52 changes: 42 additions & 10 deletions core/inflation/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,43 @@

// darwinia
use crate::*;
use dc_types::UNIT;
// github
use substrate_fixed::{transcendental, types::I95F33};

// Generate the issuing map.
//
// Formula:
// ```
// unissued * (1 - (99 / 100) ^ sqrt(years));
// ```
//
// Use `I95F33` here, because `2^94 > TOTAL_SUPPLY * 10^18`.
fn issuing_map() -> Vec<Balance> {
let ninety_nine = I95F33::from_num(99_u8) / 100_i128;
let max = 10_000_000_000_u128;
let mut supply = 2_000_000_000_u128;

(1_u8..=100)
.map(|years| {
let sqrt = transcendental::sqrt::<I95F33, I95F33>(years.into()).unwrap();
let pow = transcendental::pow::<I95F33, I95F33>(ninety_nine, sqrt).unwrap();
let ratio = I95F33::from_num(1_u8) - pow;
let unissued = max - supply;
let to_issue =
(I95F33::checked_from_num(unissued).unwrap() * ratio).floor().to_num::<Balance>();

supply += to_issue;

to_issue * UNIT
})
.collect()
}

#[test]
fn inflate_should_work() {
fn issuing_map_should_work() {
assert_eq!(issuing_map(), ISSUING_MAP);

let max = 10_000_000_000_u128 * UNIT;
let init = 2_000_000_000_u128 * UNIT;
#[allow(clippy::approx_constant)]
Expand All @@ -33,21 +67,19 @@ fn inflate_should_work() {
0.08, 0.07, 0.07, 0.06, 0.06, 0.05, 0.05, 0.04, 0.04, 0.04, 0.03, 0.03, 0.03, 0.03, 0.02,
0.02, 0.02, 0.02, 0.02, 0.01, 0.01, 0.01, 0.01, 0.01,
];
let mut unminted = max - init;
let mut unissued = max - init;

for (&rate, years) in rates.iter().zip(1..) {
let inflation =
in_period(unminted, MILLISECS_PER_YEAR, (years - 1) as u128 * MILLISECS_PER_YEAR)
.unwrap();
rates.iter().zip(0..).for_each(|(rate, years)| {
let issued = issuing_in_period(MILLISECS_PER_YEAR, years * MILLISECS_PER_YEAR).unwrap();

sp_arithmetic::assert_eq_error_rate!(
inflation as f64 / (max - unminted) as f64,
rate / 100_f64,
issued as f64 / (max - unissued) as f64,
*rate / 100_f64,
0.0001_f64
);

unminted -= inflation;
}
unissued -= issued;
});
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion pallet/account-migration/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ impl darwinia_deposit::Config for Runtime {
impl darwinia_staking::Config for Runtime {
type Currency = Balances;
type Deposit = Deposit;
type InflationManager = ();
type IssuingManager = ();
type Kton = Dummy;
type MaxDeposits = ();
type MaxUnstakings = ();
Expand Down
18 changes: 9 additions & 9 deletions pallet/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ pub mod pallet {
type Currency: Currency<Self::AccountId>;

/// Inflation and reward manager.
type InflationManager: InflationManager<Self>;
type IssuingManager: IssuingManager<Self>;

/// Pass [`pallet_session::Config::ShouldEndSession`]'s result to here.
type ShouldEndSession: Get<bool>;
Expand Down Expand Up @@ -902,7 +902,7 @@ pub mod pallet {
<PendingRewards<T>>::mutate(&c, |u| *u = u.map(|u| u + r).or(Some(r)));

// TODO: merge into one call
if T::InflationManager::reward(&staking_pot, r).is_ok() {
if T::IssuingManager::reward(&staking_pot, r).is_ok() {
actual_reward += r;
} else {
unpaid += r;
Expand Down Expand Up @@ -936,14 +936,14 @@ pub mod pallet {
// If the collator nominated themselves.

c_payout += n_payout;
} else if T::InflationManager::reward(&n_exposure.who, n_payout).is_ok() {
} else if T::IssuingManager::reward(&n_exposure.who, n_payout).is_ok() {
Self::deposit_event(Event::Payout { staker: n_exposure.who, amount: n_payout });
} else {
Self::deposit_event(Event::Unpaid { staker: n_exposure.who, amount: n_payout });
}
}

if T::InflationManager::reward(&collator, c_payout).is_ok() {
if T::IssuingManager::reward(&collator, c_payout).is_ok() {
Self::deposit_event(Event::Payout { staker: collator, amount: c_payout });
} else {
Self::deposit_event(Event::Unpaid { staker: collator, amount: c_payout });
Expand Down Expand Up @@ -1055,8 +1055,8 @@ type Vote = u32;

type DepositId<T> = <<T as Config>::Deposit as Stake>::Item;

/// Inflation and reward manager.
pub trait InflationManager<T>
/// Issuing and reward manager.
pub trait IssuingManager<T>
where
T: Config,
{
Expand All @@ -1077,15 +1077,15 @@ where
}

/// Calculate the reward.
fn calculate_reward(inflation: Balance) -> Balance;
fn calculate_reward(issued: Balance) -> Balance;

/// The reward function.
fn reward(who: &T::AccountId, amount: Balance) -> DispatchResult;

/// Clear the remaining inflation.
fn clear(_remaining: Balance) {}
}
impl<T> InflationManager<T> for ()
impl<T> IssuingManager<T> for ()
where
T: Config,
{
Expand Down Expand Up @@ -1191,7 +1191,7 @@ where
T: Config,
{
fn end_session(_: u32) {
T::InflationManager::on_session_end();
T::IssuingManager::on_session_end();
}

fn start_session(_: u32) {}
Expand Down
22 changes: 10 additions & 12 deletions pallet/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ impl darwinia_staking::Stake for KtonStaking {
}
}
pub enum StatedOnSessionEnd {}
impl darwinia_staking::InflationManager<Runtime> for StatedOnSessionEnd {
impl darwinia_staking::IssuingManager<Runtime> for StatedOnSessionEnd {
fn inflate() -> Balance {
if INFLATION_TYPE.with(|v| *v.borrow()) == 0 {
OnDarwiniaSessionEnd::inflate()
Expand All @@ -267,11 +267,11 @@ impl darwinia_staking::InflationManager<Runtime> for StatedOnSessionEnd {
}
}

fn calculate_reward(inflation: Balance) -> Balance {
fn calculate_reward(issued: Balance) -> Balance {
if INFLATION_TYPE.with(|v| *v.borrow()) == 0 {
OnDarwiniaSessionEnd::calculate_reward(inflation)
OnDarwiniaSessionEnd::calculate_reward(issued)
} else {
OnCrabSessionEnd::calculate_reward(inflation)
OnCrabSessionEnd::calculate_reward(issued)
}
}

Expand All @@ -292,7 +292,7 @@ impl darwinia_staking::InflationManager<Runtime> for StatedOnSessionEnd {
}
}
pub enum OnDarwiniaSessionEnd {}
impl darwinia_staking::InflationManager<Runtime> for OnDarwiniaSessionEnd {
impl darwinia_staking::IssuingManager<Runtime> for OnDarwiniaSessionEnd {
fn inflate() -> Balance {
let now = Timestamp::now();
let session_duration = now - <darwinia_staking::SessionStartTime<Runtime>>::get();
Expand All @@ -304,13 +304,11 @@ impl darwinia_staking::InflationManager<Runtime> for OnDarwiniaSessionEnd {

<darwinia_staking::SessionStartTime<Runtime>>::put(now);

let unminted = dc_inflation::TOTAL_SUPPLY.saturating_sub(Balances::total_issuance());

dc_inflation::in_period(unminted, session_duration, elapsed_time).unwrap_or_default()
dc_inflation::issuing_in_period(session_duration, elapsed_time).unwrap_or_default()
}

fn calculate_reward(inflation: Balance) -> Balance {
PayoutFraction::get() * inflation
fn calculate_reward(issued: Balance) -> Balance {
PayoutFraction::get() * issued
}

fn reward(who: &AccountId, amount: Balance) -> sp_runtime::DispatchResult {
Expand All @@ -324,7 +322,7 @@ impl darwinia_staking::InflationManager<Runtime> for OnDarwiniaSessionEnd {
}
}
pub enum OnCrabSessionEnd {}
impl darwinia_staking::InflationManager<Runtime> for OnCrabSessionEnd {
impl darwinia_staking::IssuingManager<Runtime> for OnCrabSessionEnd {
fn calculate_reward(_inflation: Balance) -> Balance {
10_000 * UNIT
}
Expand Down Expand Up @@ -352,7 +350,7 @@ impl frame_support::traits::Get<bool> for ShouldEndSession {
impl darwinia_staking::Config for Runtime {
type Currency = Balances;
type Deposit = Deposit;
type InflationManager = StatedOnSessionEnd;
type IssuingManager = StatedOnSessionEnd;
type Kton = KtonStaking;
type MaxDeposits = <Self as darwinia_deposit::Config>::MaxDeposits;
type MaxUnstakings = frame_support::traits::ConstU32<16>;
Expand Down
Loading

0 comments on commit 0f667c8

Please sign in to comment.