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

Commit

Permalink
Emergency mode for elections. (#8918)
Browse files Browse the repository at this point in the history
  • Loading branch information
kianenigma authored May 28, 2021
1 parent dcd291a commit 0bb7d20
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 11 deletions.
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.
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.

<QueuedSolution<T>>::put(solution);
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.
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.
<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.
Self::rotate_round();
Ok((supports, weight))
},
Err(why) => {
log!(error, "Entering emergency mode.");
<CurrentPhase<T>>::put(Phase::Emergency);
Err(why)
}
}
}
}

Expand Down

0 comments on commit 0bb7d20

Please sign in to comment.