Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions substrate/frame/staking-async/ahm-test/src/ah/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,10 @@ pub fn roll_until_matches(criteria: impl Fn() -> bool, with_rc: bool) {
/// Use the given `end_index` as the first session report, and increment as per needed.
pub(crate) fn roll_until_next_active(mut end_index: SessionIndex) -> Vec<AccountId> {
// receive enough session reports, such that we plan a new era
let planned_era = pallet_staking_async::session_rotation::Rotator::<Runtime>::planning_era();
let planned_era = pallet_staking_async::session_rotation::Rotator::<Runtime>::planned_era();
let active_era = pallet_staking_async::session_rotation::Rotator::<Runtime>::active_era();

while pallet_staking_async::session_rotation::Rotator::<Runtime>::planning_era() == planned_era
{
while pallet_staking_async::session_rotation::Rotator::<Runtime>::planned_era() == planned_era {
let report = SessionReport {
end_index,
activation_timestamp: None,
Expand Down Expand Up @@ -342,6 +341,7 @@ impl pallet_staking_async::Config for Runtime {
type RewardRemainder = ();
type Slash = ();
type SlashDeferDuration = SlashDeferredDuration;
type MaxEraDuration = ();

type HistoryDepth = ConstU32<7>;
type MaxControllersInDeprecationBatch = ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ parameter_types! {
// of nominators.
pub const MaxControllersInDeprecationBatch: u32 = 751;
pub const MaxNominations: u32 = <NposCompactSolution16 as frame_election_provider_support::NposSolution>::LIMIT as u32;
// Note: In WAH, this should be set closer to the ideal era duration to trigger capping more
// frequently. On Kusama and Polkadot, a higher value like 7 × ideal_era_duration is more
// appropriate.
pub const MaxEraDuration: u64 = RelaySessionDuration::get() as u64 * RELAY_CHAIN_SLOT_DURATION_MILLIS as u64 * SessionsPerEra::get() as u64;
}

impl pallet_staking_async::Config for Runtime {
Expand Down Expand Up @@ -273,6 +277,7 @@ impl pallet_staking_async::Config for Runtime {
type EventListeners = (NominationPools, DelegatedStaking);
type WeightInfo = weights::pallet_staking_async::WeightInfo<Runtime>;
type MaxInvulnerables = frame_support::traits::ConstU32<20>;
type MaxEraDuration = MaxEraDuration;
type MaxDisabledValidators = ConstU32<100>;
type PlanningEraOffset =
pallet_staking_async::PlanningEraOffsetOf<Self, RelaySessionDuration, ConstU32<10>>;
Expand Down
27 changes: 13 additions & 14 deletions substrate/frame/staking-async/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ mod benchmarks {
// clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get().max(asset::existential_deposit::<T>());
let origin_weight = Staking::<T>::min_nominator_bond();

// setup the worst case list scenario.

Expand Down Expand Up @@ -318,7 +318,7 @@ mod benchmarks {
// clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get().max(asset::existential_deposit::<T>());
let origin_weight = Staking::<T>::min_nominator_bond();

// setup a worst case list scenario. Note that we don't care about the setup of the
// destination position because we are doing a removal from the list but no insert.
Expand Down Expand Up @@ -442,7 +442,7 @@ mod benchmarks {
// clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get().max(asset::existential_deposit::<T>());
let origin_weight = Staking::<T>::min_nominator_bond();

// setup a worst case list scenario. Note we don't care about the destination position,
// because we are just doing an insert into the origin position.
Expand Down Expand Up @@ -475,7 +475,7 @@ mod benchmarks {
// clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get().max(asset::existential_deposit::<T>());
let origin_weight = Staking::<T>::min_nominator_bond();

// setup a worst case list scenario. Note that we don't care about the setup of the
// destination position because we are doing a removal from the list but no insert.
Expand Down Expand Up @@ -633,7 +633,7 @@ mod benchmarks {
// Clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get().max(asset::existential_deposit::<T>());
let origin_weight = Staking::<T>::min_nominator_bond();

// setup a worst case list scenario. Note that we don't care about the setup of the
// destination position because we are doing a removal from the list but no insert.
Expand Down Expand Up @@ -734,8 +734,7 @@ mod benchmarks {
// clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get()
.max(asset::existential_deposit::<T>())
let origin_weight = Pallet::<T>::min_nominator_bond()
// we use 100 to play friendly with the list threshold values in the mock
.max(100u32.into());

Expand Down Expand Up @@ -781,7 +780,7 @@ mod benchmarks {
// clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get().max(asset::existential_deposit::<T>());
let origin_weight = Staking::<T>::min_nominator_bond();

// setup a worst case list scenario. Note that we don't care about the setup of the
// destination position because we are doing a removal from the list but no insert.
Expand Down Expand Up @@ -858,7 +857,7 @@ mod benchmarks {
// clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get().max(asset::existential_deposit::<T>());
let origin_weight = Staking::<T>::min_nominator_bond();

// setup a worst case list scenario. Note that we don't care about the setup of the
// destination position because we are doing a removal from the list but no insert.
Expand Down Expand Up @@ -1024,14 +1023,14 @@ mod benchmarks {
let _new_validators = Rotator::<T>::legacy_insta_plan_era();
// activate the previous one
Rotator::<T>::start_era(
crate::ActiveEraInfo { index: Rotator::<T>::planning_era() - 1, start: Some(1) },
crate::ActiveEraInfo { index: Rotator::<T>::planned_era() - 1, start: Some(1) },
42, // start session index doesn't really matter,
2, // timestamp doesn't really matter
);

// ensure our offender has at least a full exposure page
let offender_exposure =
Eras::<T>::get_full_exposure(Rotator::<T>::planning_era(), &offender);
Eras::<T>::get_full_exposure(Rotator::<T>::planned_era(), &offender);
ensure!(
offender_exposure.others.len() as u32 == 2 * T::MaxExposurePageSize::get(),
"exposure not created"
Expand Down Expand Up @@ -1073,7 +1072,7 @@ mod benchmarks {
fn rc_on_offence(
v: Linear<2, { T::MaxValidatorSet::get() / 2 }>,
) -> Result<(), BenchmarkError> {
let initial_era = Rotator::<T>::planning_era();
let initial_era = Rotator::<T>::planned_era();
let _ = crate::testing_utils::create_validators_with_nominators_for_era::<T>(
2 * v,
// number of nominators is irrelevant here, so we hardcode these
Expand All @@ -1085,7 +1084,7 @@ mod benchmarks {

// plan new era
let new_validators = Rotator::<T>::legacy_insta_plan_era();
ensure!(Rotator::<T>::planning_era() == initial_era + 1, "era should be incremented");
ensure!(Rotator::<T>::planned_era() == initial_era + 1, "era should be incremented");
// activate the previous one
Rotator::<T>::start_era(
crate::ActiveEraInfo { index: initial_era, start: Some(1) },
Expand Down Expand Up @@ -1135,7 +1134,7 @@ mod benchmarks {

#[benchmark]
fn rc_on_session_report() -> Result<(), BenchmarkError> {
let initial_planned_era = Rotator::<T>::planning_era();
let initial_planned_era = Rotator::<T>::planned_era();
let initial_active_era = Rotator::<T>::active_era();

// create a small, arbitrary number of stakers. This is just for sanity of the era planning,
Expand Down
21 changes: 18 additions & 3 deletions substrate/frame/staking-async/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,16 +312,29 @@ pub mod session_mock {
if QueuedBufferSessions::get() == 0 {
// buffer time has passed
Active::set(q);
Rotator::<Test>::end_session(ending, Some((Timestamp::get(), id)));
<Staking as rc_client::AHStakingInterface>::on_relay_session_report(
rc_client::SessionReport::new_terminal(
ending,
// TODO: currently we use `Eras::reward_active_era()` to set validator
// points in our tests. We should improve this and find a good way to
// set this value instead.
vec![],
Some((Timestamp::get(), id)),
),
);
Queued::reset();
QueuedId::reset();
} else {
QueuedBufferSessions::mutate(|s| *s -= 1);
Rotator::<Test>::end_session(ending, None);
<Staking as rc_client::AHStakingInterface>::on_relay_session_report(
rc_client::SessionReport::new_terminal(ending, vec![], None),
);
}
} else {
// just end the session.
Rotator::<Test>::end_session(ending, None);
<Staking as rc_client::AHStakingInterface>::on_relay_session_report(
rc_client::SessionReport::new_terminal(ending, vec![], None),
);
}
CurrentIndex::set(ending + 1);
}
Expand Down Expand Up @@ -385,6 +398,7 @@ ord_parameter_types! {

parameter_types! {
pub static RemainderRatio: Perbill = Perbill::from_percent(50);
pub static MaxEraDuration: u64 = time_per_era() * 7;
}
pub struct OneTokenPerMillisecond;
impl EraPayout<Balance> for OneTokenPerMillisecond {
Expand Down Expand Up @@ -423,6 +437,7 @@ impl crate::pallet::pallet::Config for Test {
type EventListeners = EventListenerMock;
type MaxInvulnerables = ConstU32<20>;
type MaxDisabledValidators = ConstU32<100>;
type MaxEraDuration = MaxEraDuration;
type PlanningEraOffset = PlanningEraOffset;
type Filter = MockedRestrictList;
type RcClientInterface = session_mock::Session;
Expand Down
64 changes: 44 additions & 20 deletions substrate/frame/staking-async/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,30 @@ use sp_runtime::TryRuntimeError;
const NPOS_MAX_ITERATIONS_COEFFICIENT: u32 = 2;

impl<T: Config> Pallet<T> {
/// Returns the minimum required bond for participation, considering nominators,
/// and the chain’s existential deposit.
///
/// This function computes the smallest allowed bond among `MinValidatorBond` and
/// `MinNominatorBond`, but ensures it is not below the existential deposit required to keep an
/// account alive.
pub(crate) fn min_chilled_bond() -> BalanceOf<T> {
MinValidatorBond::<T>::get()
.min(MinNominatorBond::<T>::get())
.max(asset::existential_deposit::<T>())
}

/// Returns the minimum required bond for validators, defaulting to `MinNominatorBond` if not
/// set or less than `MinNominatorBond`.
pub(crate) fn min_validator_bond() -> BalanceOf<T> {
MinValidatorBond::<T>::get().max(Self::min_nominator_bond())
}

/// Returns the minimum required bond for nominators, considering the chain’s existential
/// deposit.
pub(crate) fn min_nominator_bond() -> BalanceOf<T> {
MinNominatorBond::<T>::get().max(asset::existential_deposit::<T>())
}

/// Fetches the ledger associated with a controller or stash account, if any.
pub fn ledger(account: StakingAccount<T::AccountId>) -> Result<StakingLedger<T>, Error<T>> {
StakingLedger::<T>::get(account)
Expand Down Expand Up @@ -169,8 +193,8 @@ impl<T: Config> Pallet<T> {

ledger.total = ledger.total.checked_add(&extra).ok_or(ArithmeticError::Overflow)?;
ledger.active = ledger.active.checked_add(&extra).ok_or(ArithmeticError::Overflow)?;
// last check: the new active amount of ledger must be more than ED.
ensure!(ledger.active >= asset::existential_deposit::<T>(), Error::<T>::InsufficientBond);
// last check: the new active amount of ledger must be more than min bond.
ensure!(ledger.active >= Self::min_chilled_bond(), Error::<T>::InsufficientBond);

// NOTE: ledger must be updated prior to calling `Self::weight_of`.
ledger.update()?;
Expand All @@ -193,22 +217,22 @@ impl<T: Config> Pallet<T> {
}
let new_total = ledger.total;

let ed = asset::existential_deposit::<T>();
let used_weight =
if ledger.unlocking.is_empty() && (ledger.active < ed || ledger.active.is_zero()) {
// This account must have called `unbond()` with some value that caused the active
// portion to fall below existential deposit + will have no more unlocking chunks
// left. We can now safely remove all staking-related information.
Self::kill_stash(&ledger.stash)?;
let used_weight = if ledger.unlocking.is_empty() &&
(ledger.active < Self::min_chilled_bond() || ledger.active.is_zero())
{
// This account must have called `unbond()` with some value that caused the active
// portion to fall below existential deposit + will have no more unlocking chunks
// left. We can now safely remove all staking-related information.
Self::kill_stash(&ledger.stash)?;

T::WeightInfo::withdraw_unbonded_kill()
} else {
// This was the consequence of a partial unbond. just update the ledger and move on.
ledger.update()?;
T::WeightInfo::withdraw_unbonded_kill()
} else {
// This was the consequence of a partial unbond. just update the ledger and move on.
ledger.update()?;

// This is only an update, so we use less overall weight.
T::WeightInfo::withdraw_unbonded_update()
};
// This is only an update, so we use less overall weight.
T::WeightInfo::withdraw_unbonded_update()
};

// `old_total` should never be less than the new total because
// `consolidate_unlocked` strictly subtracts balance.
Expand Down Expand Up @@ -972,7 +996,7 @@ impl<T: Config> ElectionDataProvider for Pallet<T> {

#[cfg(feature = "runtime-benchmarks")]
fn add_target(target: T::AccountId) {
let stake = (MinValidatorBond::<T>::get() + 1u32.into()) * 100u32.into();
let stake = (Self::min_validator_bond() + 1u32.into()) * 100u32.into();
<Bonded<T>>::insert(target.clone(), target.clone());
<Ledger<T>>::insert(target.clone(), StakingLedger::<T>::new(target.clone(), stake));
Self::do_add_validator(
Expand Down Expand Up @@ -1004,7 +1028,7 @@ impl<T: Config> ElectionDataProvider for Pallet<T> {
targets.into_iter().for_each(|v| {
let stake: BalanceOf<T> = target_stake
.and_then(|w| <BalanceOf<T>>::try_from(w).ok())
.unwrap_or_else(|| MinNominatorBond::<T>::get() * 100u32.into());
.unwrap_or_else(|| Self::min_nominator_bond() * 100u32.into());
<Bonded<T>>::insert(v.clone(), v.clone());
<Ledger<T>>::insert(v.clone(), StakingLedger::<T>::new(v.clone(), stake));
Self::do_add_validator(
Expand Down Expand Up @@ -1425,11 +1449,11 @@ impl<T: Config> StakingInterface for Pallet<T> {
type CurrencyToVote = T::CurrencyToVote;

fn minimum_nominator_bond() -> Self::Balance {
MinNominatorBond::<T>::get()
Self::min_nominator_bond()
}

fn minimum_validator_bond() -> Self::Balance {
MinValidatorBond::<T>::get()
Self::min_validator_bond()
}

fn stash_by_ctrl(controller: &Self::AccountId) -> Result<Self::AccountId, DispatchError> {
Expand Down
Loading
Loading