Skip to content

Commit 1454caa

Browse files
[unstable2507] Backport #9721 (#9726)
Backport #9721 into `unstable2507` from sigurpol. See the [documentation](https://github.com/paritytech/polkadot-sdk/blob/master/docs/BACKPORT.md) on how to use this bot. <!-- # To be used by other automation, do not modify: original-pr-number: #${pull_number} --> Co-authored-by: Paolo La Camera <[email protected]>
1 parent 9b635dc commit 1454caa

File tree

2 files changed

+40
-13
lines changed

2 files changed

+40
-13
lines changed

prdoc/pr_9721.prdoc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
title: 'staking-async: handle uninitialized state in try-runtime checks'
2+
3+
doc:
4+
- audience: Runtime Dev
5+
description: |-
6+
Handle the case where ActiveEra is None (uninitialized staking state) in the try-state checks.
7+
This fixes try-runtime failures when deploying staking-async for the first time on chains without existing staking.
8+
9+
crates:
10+
- name: pallet-staking-async
11+
bump: patch

substrate/frame/staking-async/src/session_rotation.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -483,21 +483,37 @@ impl<T: Config> Rotator<T> {
483483

484484
#[cfg(any(feature = "try-runtime", test))]
485485
pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
486-
// planned era can always be at most one more than active era
487-
let planned = Self::planned_era();
488-
let active = Self::active_era();
489-
ensure!(
490-
planned == active || planned == active + 1,
491-
"planned era is always equal or one more than active"
492-
);
486+
// Check planned era vs active era relationship
487+
let active_era = ActiveEra::<T>::get();
488+
let planned_era = CurrentEra::<T>::get();
493489

494-
// bonded eras must always be the range [active - bonding_duration .. active_era]
495490
let bonded = BondedEras::<T>::get();
496-
ensure!(
497-
bonded.into_iter().map(|(era, _sess)| era).collect::<Vec<_>>() ==
498-
(active.saturating_sub(T::BondingDuration::get())..=active).collect::<Vec<_>>(),
499-
"BondedEras range incorrect"
500-
);
491+
492+
match (&active_era, &planned_era) {
493+
(None, None) => {
494+
// Uninitialized state - both should be None
495+
ensure!(bonded.is_empty(), "BondedEras must be empty when ActiveEra is None");
496+
},
497+
(Some(active), Some(planned)) => {
498+
// Normal state - planned can be at most one more than active
499+
ensure!(
500+
*planned == active.index || *planned == active.index + 1,
501+
"planned era is always equal or one more than active"
502+
);
503+
504+
// If we have an active era, bonded eras must always be the range
505+
// [active - bonding_duration .. active_era]
506+
ensure!(
507+
bonded.into_iter().map(|(era, _sess)| era).collect::<Vec<_>>() ==
508+
(active.index.saturating_sub(T::BondingDuration::get())..=active.index)
509+
.collect::<Vec<_>>(),
510+
"BondedEras range incorrect"
511+
);
512+
},
513+
_ => {
514+
ensure!(false, "ActiveEra and CurrentEra must both be None or both be Some");
515+
},
516+
}
501517

502518
Ok(())
503519
}

0 commit comments

Comments
 (0)