fix(staking-async): add stalled era recovery for zombie pending eras

When an election completes with 0 winners and RC never sends
activation_timestamp, the pending era becomes a zombie blocking all
future era transitions. Detect this condition (election idle + not
fetching) and revert the planned era to break the deadlock.
This commit is contained in:
2026-02-18 21:22:56 +03:00
parent 098e3041bb
commit 4d0176e2f0
2 changed files with 33 additions and 7 deletions
@@ -1226,6 +1226,9 @@ pub mod pezpallet {
EraDurationBoundExceeded,
/// Received a validator activation event that is not recognized.
UnknownValidatorActivation,
/// A pending era's election completed but produced no viable result. The planned
/// era was reverted and a new election was initiated to break the deadlock.
StalledEraRecovery,
}
#[pezpallet::error]
@@ -673,13 +673,36 @@ impl<T: Config> Rotator<T> {
Self::plan_new_era();
},
(true, true) => {
// we are waiting for to start the previously planned era, we cannot plan a new era
// now.
crate::log!(
debug,
"time to plan a new era {:?}, but waiting for the activation of the previous.",
current_planned_era
);
// We have a pending era but also want to plan a new one.
// Detect zombie pending era: election completed but produced 0 winners,
// RC never sent activation_timestamp. Break the deadlock by reverting
// the planned era and re-planning with a fresh election.
let election_idle = T::ElectionProvider::status().is_err();
let not_fetching = NextElectionPage::<T>::get().is_none();
if election_idle && not_fetching {
crate::log!(
warn,
"Detected stalled pending era {:?}: election finished but era was \
never activated. Reverting planned era and re-planning.",
current_planned_era
);
let active = Self::active_era();
CurrentEra::<T>::put(active);
EraElectionPlanner::<T>::cleanup();
Pezpallet::<T>::deposit_event(Event::Unexpected(
UnexpectedKind::StalledEraRecovery,
));
Self::plan_new_era();
} else {
crate::log!(
debug,
"time to plan a new era {:?}, but waiting for the activation of \
the previous (election_idle: {}, fetching: {}).",
current_planned_era,
election_idle,
!not_fetching
);
}
},
}