Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pallet_staking: Introduce Additional Account for Inflation Distribution Alongside PBR #2976

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
07768a4
new impl
TarekkMA Sep 25, 2024
2c21935
fix benchs
TarekkMA Sep 25, 2024
fc626b9
fix tests
TarekkMA Sep 25, 2024
e3e191e
fix bench
TarekkMA Sep 25, 2024
1de4b2c
fix tests and gen typescripts
TarekkMA Sep 26, 2024
7832629
fix test
TarekkMA Sep 26, 2024
9fc0c38
Merge remote-tracking branch 'origin/master' into tarekkma/staking-ad…
TarekkMA Sep 26, 2024
12274aa
lock
TarekkMA Sep 26, 2024
9c2a597
prettier
TarekkMA Sep 26, 2024
9918ecf
fmt
TarekkMA Sep 27, 2024
3efc74e
Merge remote-tracking branch 'origin/master' into tarekkma/staking-ad…
TarekkMA Sep 30, 2024
6374b7f
wrap arr
TarekkMA Sep 30, 2024
9328e12
fix ts types
TarekkMA Sep 30, 2024
fcbe8c5
Merge remote-tracking branch 'origin/master' into tarekkma/staking-ad…
TarekkMA Sep 30, 2024
f95bd72
upgrades
TarekkMA Oct 1, 2024
c2efffb
link
TarekkMA Oct 1, 2024
92bd1e8
fix
TarekkMA Oct 1, 2024
cfb8356
Merge remote-tracking branch 'origin/master' into tarekkma/staking-ad…
TarekkMA Oct 1, 2024
e570f3c
fix
TarekkMA Oct 1, 2024
f299c79
fmt
TarekkMA Oct 1, 2024
3a17246
fix
TarekkMA Oct 1, 2024
243ea71
fix fmt
TarekkMA Oct 1, 2024
53d633c
fix
TarekkMA Oct 1, 2024
5657b20
add tests
TarekkMA Oct 2, 2024
1cb3f13
add bench
TarekkMA Oct 2, 2024
6eefbb2
fix
TarekkMA Oct 2, 2024
0416a88
fix
TarekkMA Oct 2, 2024
9fa6969
fix docs
TarekkMA Oct 2, 2024
bbd5639
fix test
TarekkMA Oct 2, 2024
8eb0b83
fix smoke
TarekkMA Oct 2, 2024
64fcf63
Merge remote-tracking branch 'origin/master' into tarekkma/staking-ad…
TarekkMA Oct 2, 2024
beb8121
fix merge
TarekkMA Oct 2, 2024
fdae04b
test-tmp
TarekkMA Oct 3, 2024
b8eb6c4
Merge remote-tracking branch 'origin/master' into tarekkma/staking-ad…
TarekkMA Oct 3, 2024
b4105f8
fix
TarekkMA Oct 3, 2024
e0e37c0
fix
TarekkMA Oct 3, 2024
da2b751
Merge remote-tracking branch 'origin/master' into tarekkma/staking-ad…
TarekkMA Oct 3, 2024
8aaa408
fix
TarekkMA Oct 3, 2024
0712e30
fix
TarekkMA Oct 3, 2024
7265438
dummy
TarekkMA Oct 3, 2024
caed8bd
fix
TarekkMA Oct 3, 2024
aa5b89d
add test "Staking - Rewards - Bond + Treasury"
TarekkMA Oct 4, 2024
daae46c
fix
TarekkMA Oct 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 48 additions & 7 deletions pallets/parachain-staking/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
//! Benchmarking
use crate::{
AwardedPts, BalanceOf, BottomDelegations, Call, CandidateBondLessRequest, Config,
DelegationAction, EnableMarkingOffline, Pallet, ParachainBondConfig, ParachainBondInfo, Points,
Range, RewardPayment, Round, ScheduledRequest, TopDelegations,
DelegationAction, EnableMarkingOffline, InflationDistributionAccount,
InflationDistributionConfig, InflationDistributionInfo, Pallet, Points, Range, RewardPayment,
Round, ScheduledRequest, TopDelegations,
};
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite};
use frame_support::traits::{Currency, Get, OnFinalize, OnInitialize};
Expand Down Expand Up @@ -280,13 +281,43 @@ benchmarks! {
let parachain_bond_account: T::AccountId = account("TEST", 0u32, USER_SEED);
}: _(RawOrigin::Root, parachain_bond_account.clone())
verify {
assert_eq!(Pallet::<T>::parachain_bond_info().account, parachain_bond_account);
assert_eq!(Pallet::<T>::inflation_distribution_info().0[0].account, parachain_bond_account);
}

set_parachain_bond_reserve_percent {
}: _(RawOrigin::Root, Percent::from_percent(33))
verify {
assert_eq!(Pallet::<T>::parachain_bond_info().percent, Percent::from_percent(33));
assert_eq!(Pallet::<T>::inflation_distribution_info().0[0].percent, Percent::from_percent(33));
}

set_inflation_distribution_config {
}: _(RawOrigin::Root, [
InflationDistributionAccount {
account: account("TEST1", 0u32, USER_SEED),
percent: Percent::from_percent(33),
},
InflationDistributionAccount {
account: account("TEST2", 1u32, USER_SEED),
percent: Percent::from_percent(22),
},
].into())
verify {
assert_eq!(
Pallet::<T>::inflation_distribution_info().0[0].account,
account("TEST1", 0u32, USER_SEED)
);
assert_eq!(
Pallet::<T>::inflation_distribution_info().0[0].percent,
Percent::from_percent(33)
);
assert_eq!(
Pallet::<T>::inflation_distribution_info().0[1].account,
account("TEST2", 1u32, USER_SEED)
);
assert_eq!(
Pallet::<T>::inflation_distribution_info().0[1].percent,
Percent::from_percent(22)
);
}

// ROOT DISPATCHABLES
Expand Down Expand Up @@ -1554,7 +1585,7 @@ benchmarks! {
let payout_round = round.current - reward_delay;
// may need:
// <Points<T>>
// <ParachainBondInfo<T>>
// <InflationDistributionInfo<T>>
// ensure parachain bond account exists so that deposit_into_existing succeeds
<Points<T>>::insert(payout_round, 100);

Expand All @@ -1564,10 +1595,13 @@ benchmarks! {
0,
min_candidate_stk::<T>(),
).0;
<ParachainBondInfo<T>>::put(ParachainBondConfig {
<InflationDistributionInfo<T>>::put::<InflationDistributionConfig<T::AccountId>>([
InflationDistributionAccount {
account,
percent: Percent::from_percent(50),
});
},
Default::default(),
].into());

}: { Pallet::<T>::prepare_staking_payouts(round, current_slot); }
verify {
Expand Down Expand Up @@ -2345,6 +2379,13 @@ mod tests {
});
}

#[test]
fn bench_set_inflation_distribution_config() {
new_test_ext().execute_with(|| {
assert_ok!(Pallet::<Test>::test_benchmark_set_inflation_distribution_config());
});
}

#[test]
fn bench_set_total_selected() {
new_test_ext().execute_with(|| {
Expand Down
135 changes: 86 additions & 49 deletions pallets/parachain-staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ pub mod pallet {
CannotSetBelowMin,
RoundLengthMustBeGreaterThanTotalSelectedCollators,
NoWritingSameValue,
TotalInflationDistributionPercentExceeds100,
TooLowCandidateCountWeightHintJoinCandidates,
TooLowCandidateCountWeightHintCancelLeaveCandidates,
TooLowCandidateCountToLeaveCandidates,
Expand Down Expand Up @@ -400,17 +401,15 @@ pub mod pallet {
rewards: BalanceOf<T>,
},
/// Transferred to account which holds funds reserved for parachain bond.
ReservedForParachainBond {
InflationDistributed {
index: u32,
account: T::AccountId,
value: BalanceOf<T>,
},
/// Account (re)set for parachain bond treasury.
ParachainBondAccountSet {
old: T::AccountId,
new: T::AccountId,
InflationDistributionConfigUpdated {
old: InflationDistributionConfig<T::AccountId>,
new: InflationDistributionConfig<T::AccountId>,
},
/// Percent of inflation reserved for parachain bond (re)set.
ParachainBondReservePercentSet { old: Percent, new: Percent },
/// Annual inflation input (first 3) was used to derive new per-round inflation (last 3)
InflationSet {
annual_min: Perbill,
Expand Down Expand Up @@ -518,10 +517,15 @@ pub mod pallet {
pub(crate) type TotalSelected<T: Config> = StorageValue<_, u32, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn parachain_bond_info)]
/// Parachain bond config info { account, percent_of_inflation }
pub(crate) type ParachainBondInfo<T: Config> =
StorageValue<_, ParachainBondConfig<T::AccountId>, ValueQuery>;
#[pallet::getter(fn inflation_distribution_info)]
/// Inflation distribution configuration, including accounts that should receive inflation
/// before it is distributed to collators and delegators.
///
/// The sum of the distribution percents must be less than or equal to 100.
///
/// The first config is related to the parachain bond account, the second to the treasury account.
pub(crate) type InflationDistributionInfo<T: Config> =
StorageValue<_, InflationDistributionConfig<T::AccountId>, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn round)]
Expand Down Expand Up @@ -787,12 +791,20 @@ pub mod pallet {
// Set collator commission to default config
<CollatorCommission<T>>::put(self.collator_commission);
// Set parachain bond config to default config
<ParachainBondInfo<T>>::put(ParachainBondConfig {
let pbr = InflationDistributionAccount {
// must be set soon; if not => due inflation will be sent to collators/delegators
account: T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes())
.expect("infinite length input; no invalid inputs for type; qed"),
percent: self.parachain_bond_reserve_percent,
});
};
let treasury = InflationDistributionAccount {
account: T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes())
.expect("infinite length input; no invalid inputs for type; qed"),
percent: Percent::zero(),
};
<InflationDistributionInfo<T>>::put::<InflationDistributionConfig<T::AccountId>>(
[pbr, treasury].into(),
);
// Set total selected candidates to value from config
assert!(
self.num_selected_candidates >= T::MinSelectedCandidates::get(),
Expand Down Expand Up @@ -872,46 +884,40 @@ pub mod pallet {
Ok(().into())
}

/// Set the account that will hold funds set aside for parachain bond
/// Deprecated: please use `set_inflation_distribution_config` instead.
///
/// Set the account that will hold funds set aside for parachain bond
#[pallet::call_index(2)]
#[pallet::weight(<T as Config>::WeightInfo::set_parachain_bond_account())]
pub fn set_parachain_bond_account(
origin: OriginFor<T>,
new: T::AccountId,
) -> DispatchResultWithPostInfo {
T::MonetaryGovernanceOrigin::ensure_origin(origin)?;
let ParachainBondConfig {
account: old,
percent,
} = <ParachainBondInfo<T>>::get();
ensure!(old != new, Error::<T>::NoWritingSameValue);
<ParachainBondInfo<T>>::put(ParachainBondConfig {
account: new.clone(),
percent,
});
Self::deposit_event(Event::ParachainBondAccountSet { old, new });
Ok(().into())
T::MonetaryGovernanceOrigin::ensure_origin(origin.clone())?;
let old = <InflationDistributionInfo<T>>::get().0;
let new = InflationDistributionAccount {
account: new,
percent: old[0].percent.clone(),
};
Pallet::<T>::set_inflation_distribution_config(origin, [new, old[1].clone()].into())
}

/// Deprecated: please use `set_inflation_distribution_config` instead.
///
/// Set the percent of inflation set aside for parachain bond
#[pallet::call_index(3)]
#[pallet::weight(<T as Config>::WeightInfo::set_parachain_bond_reserve_percent())]
pub fn set_parachain_bond_reserve_percent(
origin: OriginFor<T>,
new: Percent,
) -> DispatchResultWithPostInfo {
T::MonetaryGovernanceOrigin::ensure_origin(origin)?;
let ParachainBondConfig {
account,
percent: old,
} = <ParachainBondInfo<T>>::get();
ensure!(old != new, Error::<T>::NoWritingSameValue);
<ParachainBondInfo<T>>::put(ParachainBondConfig {
account,
T::MonetaryGovernanceOrigin::ensure_origin(origin.clone())?;
let old = <InflationDistributionInfo<T>>::get().0;
let new = InflationDistributionAccount {
account: old[0].account.clone(),
percent: new,
});
Self::deposit_event(Event::ParachainBondReservePercentSet { old, new });
Ok(().into())
};
Pallet::<T>::set_inflation_distribution_config(origin, [new, old[1].clone()].into())
}

/// Set the total number of collator candidates selected per round
Expand Down Expand Up @@ -1465,6 +1471,33 @@ pub mod pallet {
T::MonetaryGovernanceOrigin::ensure_origin(origin.clone())?;
Self::join_candidates_inner(account, bond, candidate_count)
}

/// Set the inflation distribution configuration for both PBR parachain bond reserve account
/// and the treasury account.
#[pallet::call_index(32)]
#[pallet::weight(<T as Config>::WeightInfo::set_inflation_distribution_config())]
pub fn set_inflation_distribution_config(
origin: OriginFor<T>,
new: InflationDistributionConfig<T::AccountId>,
) -> DispatchResultWithPostInfo {
T::MonetaryGovernanceOrigin::ensure_origin(origin)?;
let old = <InflationDistributionInfo<T>>::get().0;
let new = new.0;
ensure!(old != new, Error::<T>::NoWritingSameValue);
let total_percent = new.iter().fold(0, |acc, x| acc + x.percent.deconstruct());
ensure!(
total_percent <= 100,
Error::<T>::TotalInflationDistributionPercentExceeds100,
);
<InflationDistributionInfo<T>>::put::<InflationDistributionConfig<T::AccountId>>(
new.clone().into(),
);
Self::deposit_event(Event::InflationDistributionConfigUpdated {
old: old.into(),
new: new.into(),
});
Ok(().into())
}
}

/// Represents a payout made via `pay_one_collator_reward`.
Expand Down Expand Up @@ -1836,20 +1869,24 @@ pub mod pallet {

// Compute total issuance based on round duration
let total_issuance = Self::compute_issuance(round_duration, round_length);

// reserve portion of issuance for parachain bond account
let mut left_issuance = total_issuance;
let bond_config = <ParachainBondInfo<T>>::get();
let parachain_bond_reserve = bond_config.percent * total_issuance;
if let Ok(imb) =
T::Currency::deposit_into_existing(&bond_config.account, parachain_bond_reserve)
{
// update round issuance if transfer succeeds
left_issuance = left_issuance.saturating_sub(imb.peek());
Self::deposit_event(Event::ReservedForParachainBond {
account: bond_config.account,
value: imb.peek(),
});

let configs = <InflationDistributionInfo<T>>::get().0;
for (index, config) in configs.iter().enumerate() {
if config.percent.is_zero() {
continue;
}
let reserve = config.percent * total_issuance;
if let Ok(imb) = T::Currency::deposit_into_existing(&config.account, reserve) {
// update round issuance if transfer succeeds
left_issuance = left_issuance.saturating_sub(imb.peek());
Self::deposit_event(Event::InflationDistributed {
index: index as u32,
account: config.account.clone(),
value: imb.peek(),
});
}
}

let payout = DelayedPayout {
Expand Down
87 changes: 87 additions & 0 deletions pallets/parachain-staking/src/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,90 @@

// You should have received a copy of the GNU General Public License
// along with Moonbeam. If not, see <http://www.gnu.org/licenses/>.

use frame_support::{traits::OnRuntimeUpgrade, weights::Weight};

use crate::*;

#[derive(
Clone,
PartialEq,
Eq,
parity_scale_codec::Decode,
parity_scale_codec::Encode,
sp_runtime::RuntimeDebug,
)]
/// Reserve information { account, percent_of_inflation }
pub struct OldParachainBondConfig<AccountId> {
/// Account which receives funds intended for parachain bond
pub account: AccountId,
/// Percent of inflation set aside for parachain bond account
pub percent: sp_runtime::Percent,
}

pub struct MigrateParachainBondConfig<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateParachainBondConfig<T> {
fn on_runtime_upgrade() -> Weight {
let (account, percent) = if let Some(config) =
frame_support::storage::migration::get_storage_value::<
OldParachainBondConfig<T::AccountId>,
>(b"ParachainStaking", b"ParachainBondInfo", &[])
{
(config.account, config.percent)
} else {
return Weight::default();
};

let pbr = InflationDistributionAccount { account, percent };
let treasury = InflationDistributionAccount::<T::AccountId>::default();
let configs: InflationDistributionConfig<T::AccountId> = [pbr, treasury].into();

//***** Start mutate storage *****//

InflationDistributionInfo::<T>::put(configs);

// Remove storage value AssetManager::SupportedFeePaymentAssets
frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix(
b"ParachainStaking",
b"ParachainBondInfo",
));

Weight::default()
}

#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::DispatchError> {
use frame_support::ensure;
use parity_scale_codec::Encode;

let state = frame_support::storage::migration::get_storage_value::<
OldParachainBondConfig<T::AccountId>,
>(b"ParachainStaking", b"ParachainBondInfo", &[]);

ensure!(state.is_some(), "State not found");

Ok(state.unwrap().encode())
}

#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::DispatchError> {
use frame_support::ensure;

let old_state: OldParachainBondConfig<T::AccountId> =
parity_scale_codec::Decode::decode(&mut &state[..])
.map_err(|_| sp_runtime::DispatchError::Other("Failed to decode old state"))?;

let new_state = InflationDistributionInfo::<T>::get();

let pbr = InflationDistributionAccount {
account: old_state.account,
percent: old_state.percent,
};
let treasury = InflationDistributionAccount::<T::AccountId>::default();
let expected_new_state: InflationDistributionConfig<T::AccountId> = [pbr, treasury].into();

ensure!(new_state == expected_new_state, "State migration failed");

Ok(())
}
}
Loading
Loading