Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

staking/election: prolonged era and emergency mode for governance submission. #8912

Merged
19 commits merged into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from 8 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
4 changes: 2 additions & 2 deletions bin/node/cli/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,8 @@ pub fn testnet_genesis(
))
}).collect::<Vec<_>>(),
},
pallet_staking: StakingConfig {
validator_count: (initial_authorities.len() * 2) as u32, // TODO: just for testing, revert at last.
staking: StakingConfig {
validator_count: initial_authorities.len() as u32,
minimum_validator_count: initial_authorities.len() as u32,
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
slash_reward_fraction: Perbill::from_percent(10),
Expand Down
2 changes: 1 addition & 1 deletion bin/node/runtime/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub mod time {

// NOTE: Currently it is not possible to change the epoch duration after the chain has started.
// Attempting to do so will brick block production.
pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * MINUTES; // TODO: just for testing, revert at last.
pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES;
pub const EPOCH_DURATION_IN_SLOTS: u64 = {
const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64;

Expand Down
2 changes: 1 addition & 1 deletion bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ pallet_staking_reward_curve::build! {
}

parameter_types! {
pub const SessionsPerEra: sp_staking::SessionIndex = 1; // TODO: just for testing, revert at last.
pub const SessionsPerEra: sp_staking::SessionIndex = 6;
pub const BondingDuration: pallet_staking::EraIndex = 24 * 28;
pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration.
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
Expand Down
109 changes: 54 additions & 55 deletions frame/election-provider-multi-phase/src/lib.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions frame/session/src/historical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl<T: Config, I: SessionManager<T::ValidatorId, T::FullIdentification>> NoteHi
} else {
<I as SessionManager<_, _>>::new_session(new_index)
};
let new_validators = new_validators_and_id
let new_validators_opt = new_validators_and_id
.as_ref()
.map(|new_validators| new_validators.iter().map(|(v, _id)| v.clone()).collect());

Expand All @@ -174,7 +174,7 @@ impl<T: Config, I: SessionManager<T::ValidatorId, T::FullIdentification>> NoteHi
}
}

new_validators
new_validators_opt
}
}

Expand Down
2 changes: 1 addition & 1 deletion frame/session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ pub trait SessionManager<ValidatorId> {
/// Because the session pallet can queue validator set the ending session can be lower than the
/// last new session index.
fn end_session(end_index: SessionIndex);
/// Start an already planned the session.
/// Start an already planned session.
///
/// The session start to be used for validation.
fn start_session(start_index: SessionIndex);
Expand Down
72 changes: 36 additions & 36 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ impl<AccountId, Balance> StakingLedger<AccountId, Balance> where
if !slash_from_target.is_zero() {
*target -= slash_from_target;

// don't leave a dust balance in the staking system.
// Don't leave a dust balance in the staking system.
if *target <= minimum_balance {
slash_from_target += *target;
*value += sp_std::mem::replace(target, Zero::zero());
Expand All @@ -561,10 +561,10 @@ impl<AccountId, Balance> StakingLedger<AccountId, Balance> where
slash_out_of(total, &mut chunk.value, &mut value);
chunk.value
})
.take_while(|value| value.is_zero()) // take all fully-consumed chunks out.
.take_while(|value| value.is_zero()) // Take all fully-consumed chunks out.
.count();

// kill all drained chunks.
// Kill all drained chunks.
let _ = self.unlocking.drain(..i);

pre_total.saturating_sub(*total)
Expand Down Expand Up @@ -734,7 +734,7 @@ pub trait Config: frame_system::Config + SendTransactionTypes<Call<Self>> {
type ElectionProvider: frame_election_provider_support::ElectionProvider<
Self::AccountId,
Self::BlockNumber,
// we only accept an election provider that has staking as data provider.
// We only accept an election provider that has staking as data provider.
DataProvider = Module<Self>,
>;

Expand Down Expand Up @@ -1055,12 +1055,12 @@ pub mod migrations {

/// check to execute prior to migration.
pub fn pre_migrate<T: Config>() -> Result<(), &'static str> {
// these may or may not exist.
// These may or may not exist.
log!(info, "SnapshotValidators.exits()? {:?}", SnapshotValidators::exists());
log!(info, "SnapshotNominators.exits()? {:?}", SnapshotNominators::exists());
log!(info, "QueuedElected.exits()? {:?}", QueuedElected::exists());
log!(info, "QueuedScore.exits()? {:?}", QueuedScore::exists());
// these must exist.
// These must exist.
assert!(IsCurrentSessionFinal::exists(), "IsCurrentSessionFinal storage item not found!");
assert!(EraElectionStatus::exists(), "EraElectionStatus storage item not found!");
Ok(())
Expand Down Expand Up @@ -1200,7 +1200,7 @@ decl_module! {
}

fn on_initialize(_now: T::BlockNumber) -> Weight {
// just return the weight of the on_finalize.
// Just return the weight of the on_finalize.
T::DbWeight::get().reads(1)
}

Expand Down Expand Up @@ -1268,7 +1268,7 @@ decl_module! {
Err(Error::<T>::AlreadyPaired)?
}

// reject a bond which is considered to be _dust_.
// Reject a bond which is considered to be _dust_.
if value < T::Currency::minimum_balance() {
Err(Error::<T>::InsufficientValue)?
}
Expand Down Expand Up @@ -1330,7 +1330,7 @@ decl_module! {
let extra = extra.min(max_additional);
ledger.total += extra;
ledger.active += extra;
// last check: the new active amount of ledger must be more than ED.
// Last check: the new active amount of ledger must be more than ED.
ensure!(ledger.active >= T::Currency::minimum_balance(), Error::<T>::InsufficientValue);

Self::deposit_event(RawEvent::Bonded(stash, extra));
Expand Down Expand Up @@ -1443,7 +1443,7 @@ decl_module! {
// 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(&stash, num_slashing_spans)?;
// remove the lock.
// Remove the lock.
T::Currency::remove_lock(STAKING_ID, &stash);
// This is worst case scenario, so we use the full weight and return None
None
Expand Down Expand Up @@ -1532,7 +1532,7 @@ decl_module! {

let nominations = Nominations {
targets,
// initial nominations are considered submitted at era 0. See `Nominations` doc
// Initial nominations are considered submitted at era 0. See `Nominations` doc
submitted_in: Self::current_era().unwrap_or(0),
suppressed: false,
};
Expand Down Expand Up @@ -1667,9 +1667,9 @@ decl_module! {
///
/// # Warning
///
/// The election process start multiple block before the end of the era.
/// Thus the election process may have started when this is called. In this case the
/// election will be ongoing until the next era is triggered.
/// The election process starts multiple blocks before the end of the era.
/// Thus the election process may be ongoing when this is called. In this case the
/// election will continue until the next era is triggered.
///
emostov marked this conversation as resolved.
Show resolved Hide resolved
/// # <weight>
/// - No arguments.
Expand All @@ -1689,9 +1689,9 @@ decl_module! {
///
/// # Warning
///
/// The election process start multiple block before the end of the era.
/// The election process starts multiple blocks before the end of the era.
/// If this is called just before a new era is triggered, the election process may not
/// have enough block to get a result.
/// have enough blocks to get a result.
///
/// # <weight>
/// - No arguments.
Expand Down Expand Up @@ -1732,10 +1732,10 @@ decl_module! {
fn force_unstake(origin, stash: T::AccountId, num_slashing_spans: u32) {
ensure_root(origin)?;

// remove all staking-related information.
// Remove all staking-related information.
Self::kill_stash(&stash, num_slashing_spans)?;

// remove the lock.
// Remove the lock.
T::Currency::remove_lock(STAKING_ID, &stash);
}

Expand All @@ -1745,9 +1745,9 @@ decl_module! {
///
/// # Warning
///
/// The election process start multiple block before the end of the era.
/// The election process starts multiple blocks before the end of the era.
/// If this is called just before a new era is triggered, the election process may not
/// have enough block to get a result.
/// have enough blocks to get a result.
///
/// # <weight>
/// - Weight: O(1)
Expand Down Expand Up @@ -1846,7 +1846,7 @@ decl_module! {
ensure!(!ledger.unlocking.is_empty(), Error::<T>::NoUnlockChunk);

let ledger = ledger.rebond(value);
// last check: the new active amount of ledger must be more than ED.
// Last check: the new active amount of ledger must be more than ED.
ensure!(ledger.active >= T::Currency::minimum_balance(), Error::<T>::InsufficientValue);

Self::deposit_event(RawEvent::Bonded(ledger.stash.clone(), value));
Expand Down Expand Up @@ -2167,7 +2167,7 @@ impl<T: Config> Module<T> {
// Only go to `try_trigger_new_era` if deadline reached.
Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (),
_ => {
// either `Forcing::ForceNone`,
// Either `Forcing::ForceNone`,
// or `Forcing::NotForcing if era_length >= T::SessionsPerEra::get()`.
return None
},
Expand Down Expand Up @@ -2242,12 +2242,12 @@ impl<T: Config> Module<T> {
if active_era > bonding_duration {
let first_kept = active_era - bonding_duration;

// prune out everything that's from before the first-kept index.
// Prune out everything that's from before the first-kept index.
let n_to_prune = bonded.iter()
.take_while(|&&(era_idx, _)| era_idx < first_kept)
.count();

// kill slashing metadata.
// Kill slashing metadata.
for (pruned_era, _) in bonded.drain(..n_to_prune) {
slashing::clear_era_metadata::<T>(pruned_era);
}
Expand Down Expand Up @@ -2392,7 +2392,7 @@ impl<T: Config> Module<T> {
// Insert current era staking information
<ErasTotalStake<T>>::insert(&new_planned_era, total_stake);

// collect the pref of all winners
// Collect the pref of all winners
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
for stash in &elected_stashes {
let pref = Self::validators(stash);
<ErasValidatorPrefs<T>>::insert(&new_planned_era, stash, pref);
Expand Down Expand Up @@ -2423,7 +2423,7 @@ impl<T: Config> Module<T> {
supports
.into_iter()
.map(|(validator, support)| {
// build `struct exposure` from `support`
// Build `struct exposure` from `support`
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
let mut others = Vec::with_capacity(support.voters.len());
let mut own: BalanceOf<T> = Zero::zero();
let mut total: BalanceOf<T> = Zero::zero();
Expand Down Expand Up @@ -2558,12 +2558,12 @@ impl<T: Config> Module<T> {
let mut all_voters = Vec::new();

for (validator, _) in <Validators<T>>::iter() {
// append self vote
// Append self vote
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
let self_vote = (validator.clone(), weight_of(&validator), vec![validator.clone()]);
all_voters.push(self_vote);
}

// collect all slashing spans into a BTreeMap for further queries.
// Collect all slashing spans into a BTreeMap for further queries.
let slashing_spans = <SlashingSpans<T>>::iter().collect::<BTreeMap<_, _>>();

for (nominator, nominations) in <Nominators<T>>::iter() {
Expand Down Expand Up @@ -2655,7 +2655,7 @@ impl<T: Config> frame_election_provider_support::ElectionDataProvider<T::Account
Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => Zero::zero(),
emostov marked this conversation as resolved.
Show resolved Hide resolved
Forcing::NotForcing => T::SessionsPerEra::get()
.saturating_sub(era_length)
// one session is computed in this_session_end.
// One session is computed in this_session_end.
.saturating_sub(1)
.into(),
};
Expand Down Expand Up @@ -2861,7 +2861,7 @@ where
let active_era = Self::active_era();
add_db_reads_writes(1, 0);
if active_era.is_none() {
// this offence need not be re-submitted.
// This offence need not be re-submitted.
return consumed_weight
}
active_era.expect("value checked not to be `None`; qed").index
Expand All @@ -2875,18 +2875,18 @@ where

let window_start = active_era.saturating_sub(T::BondingDuration::get());

// fast path for active-era report - most likely.
// Fast path for active-era report - most likely.
// `slash_session` cannot be in a future active era. It must be in `active_era` or before.
let slash_era = if slash_session >= active_era_start_session_index {
active_era
} else {
let eras = BondedEras::get();
add_db_reads_writes(1, 0);

// reverse because it's more likely to find reports from recent eras.
// Reverse because it's more likely to find reports from recent eras.
match eras.iter().rev().filter(|&&(_, ref sesh)| sesh <= &slash_session).next() {
Some(&(ref slash_era, _)) => *slash_era,
// before bonding period. defensive - should be filtered out.
// Before bonding period. defensive - should be filtered out.
None => return consumed_weight,
}
};
Expand Down Expand Up @@ -2932,7 +2932,7 @@ where
}
unapplied.reporters = details.reporters.clone();
if slash_defer_duration == 0 {
// apply right away.
// Apply right away.
slashing::apply_slash::<T>(unapplied);
{
let slash_cost = (6, 5);
Expand All @@ -2943,7 +2943,7 @@ where
);
}
} else {
// defer to end of some `slash_defer_duration` from now.
// Defer to end of some `slash_defer_duration` from now.
<Self as Store>::UnappliedSlashes::mutate(
active_era,
move |for_later| for_later.push(unapplied),
Expand Down Expand Up @@ -2972,7 +2972,7 @@ where
O: Offence<Offender>,
{
fn report_offence(reporters: Vec<Reporter>, offence: O) -> Result<(), OffenceError> {
// disallow any slashing from before the current bonding period.
// Disallow any slashing from before the current bonding period.
let offence_session = offence.session_index();
let bonded_eras = BondedEras::get();

Expand Down
7 changes: 7 additions & 0 deletions frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ fn no_candidate_emergency_condition() {
assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]);
// The chill is still pending.
assert!(!<Staking as crate::Store>::Validators::contains_key(11));
emostov marked this conversation as resolved.
Show resolved Hide resolved
// No new era is created
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(current_era, CurrentEra::get());
});
}

Expand Down Expand Up @@ -3996,6 +3998,9 @@ mod election_data_provider {
run_to_block(50);
// Election: failed, next session is a new election
assert_eq!(Staking::next_election_prediction(System::block_number()), 50 + 5);
// The new era is still forced until a new era is planned
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(ForceEra::get(), Forcing::ForceNew);

MinimumValidatorCount::put(2);
run_to_block(55);
assert_eq!(Staking::next_election_prediction(System::block_number()), 55 + 25);
Expand All @@ -4004,6 +4009,8 @@ mod election_data_provider {
*staking_events().last().unwrap(),
RawEvent::StakingElection
);
// The new era has been planned, forcing is changed from `ForceNew` to `NotForcing`
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(ForceEra::get(), Forcing::NotForcing);
})
}
}