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 3 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: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 53 additions & 11 deletions frame/election-provider-multi-phase/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,13 @@ pub enum Phase<Bn> {
/// advising validators not to bother running the unsigned offchain worker.
///
/// As validator nodes are free to edit their OCW code, they could simply ignore this advisory
/// and always compute their own solution. However, by default, when the unsigned phase is passive,
/// the offchain workers will not bother running.
/// and always compute their own solution. However, by default, when the unsigned phase is
/// passive, the offchain workers will not bother running.
Unsigned((bool, Bn)),
/// The emergency phase. This is enabled upon a failing call to `T::ElectionProvider::elect`.
/// After that, the only way to leave this phase is through a successful
/// `T::ElectionProvider::elect`.
Emergency,
}

impl<Bn> Default for Phase<Bn> {
Expand All @@ -323,6 +327,11 @@ impl<Bn> Default for Phase<Bn> {
}

impl<Bn: PartialEq + Eq> Phase<Bn> {
/// Whether the phase is emergency or not.
pub fn is_emergency(&self) -> bool {
matches!(self, Phase::Emergency)
}

/// Whether the phase is signed or not.
pub fn is_signed(&self) -> bool {
matches!(self, Phase::Signed)
Expand Down Expand Up @@ -581,7 +590,7 @@ pub mod pallet {
/// Configuration for the fallback
type Fallback: Get<FallbackStrategy>;

/// Origin that can set the minimum score.
/// Origin that can control this pallet.
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
type ForceOrigin: EnsureOrigin<Self::Origin>;

/// The configuration of benchmarking.
Expand Down Expand Up @@ -793,6 +802,29 @@ pub mod pallet {
<MinimumUntrustedScore<T>>::set(maybe_next_score);
Ok(())
}

/// Set a solution in the queue, to be handed out to the client of this pallet in the next
/// call to `ElectionProvider::elect`.
///
/// This can only be set by `T::ForceOrigin`, and only when the phase is `Emergency`.
///
/// The solution is not checked for any feasibility and is assumed to be trustworthy, as any
/// feasibility check itself can in principle cause the election process to fail (due to
/// memory/weight constrains).
#[pallet::weight(T::DbWeight::get().reads_writes(1, 1))]
fn set_emergency_election_result(
origin: OriginFor<T>,
solution: ReadySolution<T::AccountId>,
) -> DispatchResult {
T::ForceOrigin::ensure_origin(origin)?;
ensure!(Self::current_phase().is_emergency(), <Error<T>>::CallNotAllowed);

// Note: we don't `rotate_round` at this point; the next call to
// `ElectionProvider::elect` will not succeed and take care of that.
gui1117 marked this conversation as resolved.
Show resolved Hide resolved

<QueuedSolution<T>>::put(solution);
emostov marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}
}

#[pallet::event]
Expand Down Expand Up @@ -828,6 +860,8 @@ pub mod pallet {
PreDispatchWeakSubmission,
/// OCW submitted solution for wrong round
OcwCallWrongEra,
/// The call is now allowed at this point.
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
CallNotAllowed,
}

#[pallet::origin]
Expand Down Expand Up @@ -1162,14 +1196,14 @@ impl<T: Config> Pallet<T> {
/// 1. Increment round.
/// 2. Change phase to [`Phase::Off`]
/// 3. Clear all snapshot data.
fn post_elect() {
// inc round
fn rotate_round() {
// inc round.
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
<Round<T>>::mutate(|r| *r = *r + 1);

// change phase
// phase is off now.
<CurrentPhase<T>>::put(Phase::Off);

// kill snapshots
// kill snapshots.
Self::kill_snapshot();
}

Expand Down Expand Up @@ -1219,10 +1253,18 @@ impl<T: Config> ElectionProvider<T::AccountId, T::BlockNumber> for Pallet<T> {
type DataProvider = T::DataProvider;

fn elect() -> Result<(Supports<T::AccountId>, Weight), Self::Error> {
let outcome_and_weight = Self::do_elect();
// IMPORTANT: regardless of if election was `Ok` or `Err`, we shall do some cleanup.
Self::post_elect();
outcome_and_weight
match Self::do_elect() {
Ok((supports, weight)) => {
// all went okay, put sign to be Off, clean snapshot, etc.
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
Self::rotate_round();
Ok((supports, weight))
},
Err(why) => {
log!(error, "Entering emergency mode.");
gui1117 marked this conversation as resolved.
Show resolved Hide resolved
<CurrentPhase<T>>::put(Phase::Emergency);
Err(why)
}
}
}
}

Expand Down
7 changes: 4 additions & 3 deletions frame/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub fn create_validator_with_nominators<T: Config>(
ValidatorCount::put(1);

// Start a new Era
let new_validators = Staking::<T>::new_era(SessionIndex::one()).unwrap();
let new_validators = Staking::<T>::try_trigger_new_era(SessionIndex::one()).unwrap();

assert_eq!(new_validators.len(), 1);
assert_eq!(new_validators[0], v_stash, "Our validator was not selected!");
Expand Down Expand Up @@ -484,7 +484,8 @@ benchmarks! {
)?;
let session_index = SessionIndex::one();
}: {
let validators = Staking::<T>::new_era(session_index).ok_or("`new_era` failed")?;
let validators = Staking::<T>::try_trigger_new_era(session_index)
.ok_or("`new_era` failed")?;
assert!(validators.len() == v as usize);
}

Expand All @@ -500,7 +501,7 @@ benchmarks! {
None,
)?;
// Start a new Era
let new_validators = Staking::<T>::new_era(SessionIndex::one()).unwrap();
let new_validators = Staking::<T>::try_trigger_new_era(SessionIndex::one()).unwrap();
assert!(new_validators.len() == v as usize);

let current_era = CurrentEra::get().unwrap();
Expand Down
Loading