From ee09cd327212dd6ed866cf1423bbfa1ca3a5557d Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Apr 2026 08:41:22 +0200 Subject: [PATCH 1/6] lastValidatorEra can be 1 higher --- substrate/frame/staking-async/src/pallet/impls.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking-async/src/pallet/impls.rs b/substrate/frame/staking-async/src/pallet/impls.rs index 07314b0087565..f4c6e1f6f4117 100644 --- a/substrate/frame/staking-async/src/pallet/impls.rs +++ b/substrate/frame/staking-async/src/pallet/impls.rs @@ -2011,14 +2011,16 @@ impl Pallet { let Some(era) = ActiveEra::::get().map(|a| a.index) else { return Ok(()) }; let overview_and_pages = ErasStakersOverview::::iter_prefix(era) .map(|(validator, metadata)| { - // ensure `LastValidatorEra` is correctly set - if LastValidatorEra::::get(&validator) != Some(era) { + let last_validator_era = LastValidatorEra::::get(&validator).unwrap_or_default(); + // If election for next era is finished, last_validator_era is set to next era. + if last_validator_era != era && last_validator_era != era + 1 { log!( - warn, - "Validator {:?} has incorrect LastValidatorEra (expected {:?}, got {:?})", + error, + "Validator {:?} has incorrect LastValidatorEra (expected {:?} or {:?}, got {:?})", validator, era, - LastValidatorEra::::get(&validator) + era + 1, + last_validator_era ); } From 1a227b1c2a2bcc5040d840103d14e65f19b3faee Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Apr 2026 08:59:55 +0200 Subject: [PATCH 2/6] test for last validator era --- .../staking-async/src/tests/try_state.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/substrate/frame/staking-async/src/tests/try_state.rs b/substrate/frame/staking-async/src/tests/try_state.rs index d1d0111ea18f7..786467595af2e 100644 --- a/substrate/frame/staking-async/src/tests/try_state.rs +++ b/substrate/frame/staking-async/src/tests/try_state.rs @@ -88,6 +88,36 @@ fn try_state_bad_exposure() { }); } +#[test] +fn last_validator_era_can_be_one_greater_than_active_era() { + // When the election for the next era has finished but the era is not yet active, + // `LastValidatorEra` is set to `active_era + 1`. + ExtBuilder::default().try_state(false).build_and_execute(|| { + Session::roll_until_active_era(1); + let era = active_era(); + + // Before election, `LastValidatorEra` equals the active era. + for (validator, _) in ErasStakersOverview::::iter_prefix(era) { + assert_eq!(LastValidatorEra::::get(&validator), Some(era)); + } + + // Roll session by session until the election for the next era has been stored, i.e. + // `ErasStakersOverview` for the next era is populated. + while ErasStakersOverview::::iter_prefix(era + 1).next().is_none() { + Session::roll_to_next_session(); + } + + // Election for era 2 is stored but era 2 is not yet active. + assert_eq!(active_era(), 1); + assert_eq!(current_era(), 2); + + // After election, `LastValidatorEra` is now 1 greater than active era. + for (validator, _) in ErasStakersOverview::::iter_prefix(era) { + assert_eq!(LastValidatorEra::::get(&validator), Some(era + 1)); + } + }); +} + #[test] fn try_state_bad_eras_total_stake() { ExtBuilder::default().try_state(false).build_and_execute(|| { From a38772534037651823f195611c732a3e6044e24c Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Apr 2026 10:38:20 +0200 Subject: [PATCH 3/6] add prdoc --- prdoc/pr_11647.prdoc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 prdoc/pr_11647.prdoc diff --git a/prdoc/pr_11647.prdoc b/prdoc/pr_11647.prdoc new file mode 100644 index 0000000000000..4b955171895b1 --- /dev/null +++ b/prdoc/pr_11647.prdoc @@ -0,0 +1,16 @@ +title: 'Fix try-state warning for LastValidatorEra in staking-async' +doc: +- audience: Runtime Dev + description: |- + Fixes a false try-state warning where `LastValidatorEra` was flagged as incorrect for active + validators. After the election for the next era completes but before that era becomes active, + `LastValidatorEra` is correctly set to `active_era + 1`. The previous check only accepted + `active_era`, causing spurious warnings. + + Adds a test verifying `LastValidatorEra` transitions from `active_era` to `active_era + 1` + once the next era's election results are stored. + + Fixes https://github.com/paritytech/polkadot-sdk/issues/11646 (item 1). +crates: +- name: pallet-staking-async + bump: patch From 0552566b7fd4fccc9047b434073590c5ecca337a Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Apr 2026 10:39:58 +0200 Subject: [PATCH 4/6] update prdoc --- prdoc/pr_11647.prdoc | 1 - 1 file changed, 1 deletion(-) diff --git a/prdoc/pr_11647.prdoc b/prdoc/pr_11647.prdoc index 4b955171895b1..ff6d770cbef3e 100644 --- a/prdoc/pr_11647.prdoc +++ b/prdoc/pr_11647.prdoc @@ -10,7 +10,6 @@ doc: Adds a test verifying `LastValidatorEra` transitions from `active_era` to `active_era + 1` once the next era's election results are stored. - Fixes https://github.com/paritytech/polkadot-sdk/issues/11646 (item 1). crates: - name: pallet-staking-async bump: patch From 9c55c2fe61d1bf37799af7b3f9462f7dc10f8875 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Apr 2026 12:43:20 +0200 Subject: [PATCH 5/6] prdoc --- prdoc/pr_11649.prdoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 prdoc/pr_11649.prdoc diff --git a/prdoc/pr_11649.prdoc b/prdoc/pr_11649.prdoc new file mode 100644 index 0000000000000..674f71f1adc96 --- /dev/null +++ b/prdoc/pr_11649.prdoc @@ -0,0 +1,15 @@ +title: 'Consolidate try-state warnings into summary counts' +doc: +- audience: Runtime Dev + description: |- + Aggregates repetitive try-state warnings (min bond violations, pool ED imbalance, depositor + insufficient stake) into single summary lines with counts and up to 10 example accounts. + Reduces log noise from hundreds of expected per-item warnings on production runtimes. + + Closes #11646. + +crates: +- name: pallet-staking-async + bump: patch +- name: pallet-nomination-pools + bump: patch From 84d0b0b2e2acf06b3fa5925551d0a223badff624 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Apr 2026 13:07:28 +0200 Subject: [PATCH 6/6] wrong PR --- prdoc/pr_11649.prdoc | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 prdoc/pr_11649.prdoc diff --git a/prdoc/pr_11649.prdoc b/prdoc/pr_11649.prdoc deleted file mode 100644 index 674f71f1adc96..0000000000000 --- a/prdoc/pr_11649.prdoc +++ /dev/null @@ -1,15 +0,0 @@ -title: 'Consolidate try-state warnings into summary counts' -doc: -- audience: Runtime Dev - description: |- - Aggregates repetitive try-state warnings (min bond violations, pool ED imbalance, depositor - insufficient stake) into single summary lines with counts and up to 10 example accounts. - Reduces log noise from hundreds of expected per-item warnings on production runtimes. - - Closes #11646. - -crates: -- name: pallet-staking-async - bump: patch -- name: pallet-nomination-pools - bump: patch