Skip to content

Commit

Permalink
L1-294: Safeguards for the inflation parameters setter (#1822) (#1827)
Browse files Browse the repository at this point in the history
Cherry-pick of
[5bfb995](5bfb995)

---------

Co-authored-by: lesniak43 <[email protected]>
  • Loading branch information
Marcin-Radecki and lesniak43 authored Oct 8, 2024
1 parent b43d7fe commit 98cbe53
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 6 deletions.
11 changes: 10 additions & 1 deletion bin/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ use primitives::{
staking::MAX_NOMINATORS_REWARDED_PER_VALIDATOR, wrap_methods, ApiError as AlephApiError,
AuraId, AuthorityId as AlephId, Block as AlephBlock, BlockId as AlephBlockId,
BlockNumber as AlephBlockNumber, Header as AlephHeader, SessionAuthorityData, SessionCommittee,
SessionIndex, SessionInfoProvider, SessionValidatorError, Version as FinalityVersion,
SessionIndex, SessionInfoProvider, SessionValidatorError,
TotalIssuanceProvider as TotalIssuanceProviderT, Version as FinalityVersion,
ADDRESSES_ENCODING, DEFAULT_BAN_REASON_LENGTH, DEFAULT_MAX_WINNERS, DEFAULT_SESSIONS_PER_ERA,
DEFAULT_SESSION_PERIOD, MAX_BLOCK_SIZE, MILLISECS_PER_BLOCK, TOKEN,
};
Expand Down Expand Up @@ -335,6 +336,13 @@ impl SessionInfoProvider<AlephBlockNumber> for SessionInfoImpl {
}
}

pub struct TotalIssuanceProvider;
impl TotalIssuanceProviderT for TotalIssuanceProvider {
fn get() -> Balance {
pallet_balances::Pallet::<Runtime>::total_issuance()
}
}

impl pallet_aleph::Config for Runtime {
type AuthorityId = AlephId;
type RuntimeEvent = RuntimeEvent;
Expand All @@ -346,6 +354,7 @@ impl pallet_aleph::Config for Runtime {
Runtime,
>;
type NextSessionAuthorityProvider = Session;
type TotalIssuanceProvider = TotalIssuanceProvider;
}

#[cfg(feature = "liminal")]
Expand Down
79 changes: 75 additions & 4 deletions pallets/aleph/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub mod pallet {
pallet_prelude::{BlockNumberFor, OriginFor},
};
use pallet_session::SessionManager;
use primitives::SessionInfoProvider;
use primitives::{SessionInfoProvider, TotalIssuanceProvider};
use sp_std::collections::btree_set::BTreeSet;
#[cfg(feature = "std")]
use sp_std::marker::PhantomData;
Expand All @@ -48,6 +48,7 @@ pub mod pallet {
type SessionInfoProvider: SessionInfoProvider<BlockNumberFor<Self>>;
type SessionManager: SessionManager<<Self as frame_system::Config>::AccountId>;
type NextSessionAuthorityProvider: NextSessionAuthorityProvider<Self>;
type TotalIssuanceProvider: TotalIssuanceProvider;
}

#[pallet::event]
Expand Down Expand Up @@ -242,6 +243,64 @@ pub mod pallet {

Self::finality_version()
}

pub fn check_horizon_upper_bound(
new_horizon: u64,
current_horizon: u64,
) -> Result<(), &'static str> {
match new_horizon > current_horizon.saturating_mul(2).saturating_add(1) {
true => {
Err("Horizon too large, should be at most twice the current value plus one!")
}
false => Ok(()),
}
}

pub fn check_horizon_lower_bound(
new_horizon: u64,
current_horizon: u64,
) -> Result<(), &'static str> {
match new_horizon < current_horizon / 2 {
true => Err("Horizon too small, should be at least half the current value!"),
false => Ok(()),
}
}

pub fn check_azero_cap_upper_bound(
new_cap: Balance,
current_cap: Balance,
total_issuance: Balance,
) -> Result<(), &'static str> {
let current_gap = current_cap.saturating_sub(total_issuance);
let new_gap = match new_cap.checked_sub(total_issuance) {
Some(new_gap) => new_gap,
None => return Err("AZERO Cap cannot be lower than the current total issuance!"),
};
match (new_gap > current_gap.saturating_mul(2).saturating_add(1))
&& (new_gap > total_issuance / 128)
{
true => Err("Future issuance too large, should be at most the current total issuance divided by 128, or at most twice the current value plus one!"),
false => Ok(()),
}
}

pub fn check_azero_cap_lower_bound(
new_cap: Balance,
current_cap: Balance,
total_issuance: Balance,
) -> Result<(), &'static str> {
let current_gap = current_cap.saturating_sub(total_issuance);
let new_gap = match new_cap.checked_sub(total_issuance) {
Some(new_gap) => new_gap,
None => return Err("AZERO Cap cannot be lower than the current total issuance!"),
};
match new_gap < current_gap / 2 {
true => {
Err("Future issuance too small, should be at least half the current value!")
}
false => Ok(()),
}
}
}

#[pallet::call]
Expand Down Expand Up @@ -298,9 +357,21 @@ pub mod pallet {
) -> DispatchResult {
ensure_root(origin)?;

let azero_cap = azero_cap.unwrap_or_else(AzeroCap::<T>::get);
let horizon_millisecs =
horizon_millisecs.unwrap_or_else(ExponentialInflationHorizon::<T>::get);
let current_azero_cap = AzeroCap::<T>::get();
let current_horizon_millisecs = ExponentialInflationHorizon::<T>::get();
let total_issuance = T::TotalIssuanceProvider::get();

let azero_cap = azero_cap.unwrap_or(current_azero_cap);
let horizon_millisecs = horizon_millisecs.unwrap_or(current_horizon_millisecs);

Self::check_horizon_lower_bound(horizon_millisecs, current_horizon_millisecs)
.map_err(DispatchError::Other)?;
Self::check_horizon_upper_bound(horizon_millisecs, current_horizon_millisecs)
.map_err(DispatchError::Other)?;
Self::check_azero_cap_upper_bound(azero_cap, current_azero_cap, total_issuance)
.map_err(DispatchError::Other)?;
Self::check_azero_cap_lower_bound(azero_cap, current_azero_cap, total_issuance)
.map_err(DispatchError::Other)?;

AzeroCap::<T>::put(azero_cap);
ExponentialInflationHorizon::<T>::put(horizon_millisecs);
Expand Down
12 changes: 11 additions & 1 deletion pallets/aleph/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use frame_support::{
weights::{RuntimeDbWeight, Weight},
};
use frame_system::pallet_prelude::BlockNumberFor;
use primitives::{AuthorityId, SessionInfoProvider};
use primitives::{
AuthorityId, SessionInfoProvider, TotalIssuanceProvider as TotalIssuanceProviderT,
};
use sp_core::H256;
use sp_runtime::{
impl_opaque_keys,
Expand Down Expand Up @@ -147,12 +149,20 @@ impl pallet_timestamp::Config for Test {
type WeightInfo = ();
}

pub struct TotalIssuanceProvider;
impl TotalIssuanceProviderT for TotalIssuanceProvider {
fn get() -> Balance {
pallet_balances::Pallet::<Test>::total_issuance()
}
}

impl Config for Test {
type AuthorityId = AuthorityId;
type RuntimeEvent = RuntimeEvent;
type SessionInfoProvider = SessionInfoImpl;
type SessionManager = ();
type NextSessionAuthorityProvider = Session;
type TotalIssuanceProvider = TotalIssuanceProvider;
}

pub fn to_authority(id: &u64) -> AuthorityId {
Expand Down
6 changes: 6 additions & 0 deletions primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,12 @@ pub trait EraManager {
fn on_new_era(era: EraIndex);
}

/// Provides the current total issuance.
pub trait TotalIssuanceProvider {
/// Get the current total issuance.
fn get() -> Balance;
}

pub mod staking {
use crate::TOKEN;

Expand Down

0 comments on commit 98cbe53

Please sign in to comment.