feat: forward session events to staking pallet for era progression on Asset Hub
Asset Hub's pallet_staking_async era never advances because it expects SessionReport messages from the relay chain's ah_client pallet, which is not yet active. This adds a StakingSessionManager wrapper that intercepts local session rotation events and generates SessionReport messages to drive era transitions directly on Asset Hub. Changes: - Add StakingSessionManager in staking.rs that delegates to both CollatorSelection and Staking via on_relay_session_report() - Switch SessionManager from CollatorSelection to StakingSessionManager - Add FixActiveEraStart migration to correct ActiveEra.start=0 from genesis - Bump spec_version to 1_020_002
This commit is contained in:
@@ -138,7 +138,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: alloc::borrow::Cow::Borrowed("asset-hub-pezkuwichain"),
|
||||
impl_name: alloc::borrow::Cow::Borrowed("asset-hub-pezkuwichain"),
|
||||
authoring_version: 1,
|
||||
spec_version: 1_020_001,
|
||||
spec_version: 1_020_002,
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 16,
|
||||
@@ -844,7 +844,7 @@ impl pezpallet_session::Config for Runtime {
|
||||
type ValidatorIdOf = pezpallet_collator_selection::IdentityCollator;
|
||||
type ShouldEndSession = pezpallet_session::PeriodicSessions<Period, Offset>;
|
||||
type NextSessionRotation = pezpallet_session::PeriodicSessions<Period, Offset>;
|
||||
type SessionManager = CollatorSelection;
|
||||
type SessionManager = StakingSessionManager;
|
||||
// Essentially just Aura, but let's be pedantic.
|
||||
type SessionHandler = <SessionKeys as pezsp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
|
||||
type Keys = SessionKeys;
|
||||
@@ -1408,8 +1408,33 @@ pub type TxExtension = pezcumulus_pezpallet_weight_reclaim::StorageWeightReclaim
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
pub type UncheckedExtrinsic =
|
||||
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
|
||||
/// One-time migration to fix ActiveEra.start which was set to 0 at genesis.
|
||||
/// Without this, the first era's duration would be calculated as (now - 0) = ~56 years,
|
||||
/// though MaxEraDuration caps it to 6 hours. This migration sets it to the current timestamp
|
||||
/// so the first era duration is calculated correctly from the upgrade moment.
|
||||
pub struct FixActiveEraStart;
|
||||
impl pezframe_support::traits::OnRuntimeUpgrade for FixActiveEraStart {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let now_ms = pezpallet_timestamp::Now::<Runtime>::get();
|
||||
if now_ms > 0 {
|
||||
pezpallet_staking_async::ActiveEra::<Runtime>::mutate(|era| {
|
||||
if let Some(ref mut info) = era {
|
||||
info.start = Some(now_ms);
|
||||
log::info!(
|
||||
target: "runtime::staking",
|
||||
"FixActiveEraStart: Set ActiveEra.start to {}",
|
||||
now_ms,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
<Runtime as pezframe_system::Config>::DbWeight::get().reads_writes(2, 1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Migrations to apply on runtime upgrade.
|
||||
pub type Migrations = (
|
||||
FixActiveEraStart,
|
||||
InitStorageVersions,
|
||||
// unreleased
|
||||
pezcumulus_pezpallet_xcmp_queue::migration::v4::MigrationToV4<Runtime>,
|
||||
|
||||
@@ -312,6 +312,60 @@ impl pezpallet_staking_async_rc_client::Config for Runtime {
|
||||
type MaxValidatorSetRetries = ConstU32<64>;
|
||||
}
|
||||
|
||||
/// Forwards session events to both CollatorSelection (collator management) and
|
||||
/// Staking pallet (era management) via local SessionReport generation.
|
||||
///
|
||||
/// This is needed because `pallet_staking_async` expects `SessionReport` messages from
|
||||
/// the relay chain's `ah_client` pallet, which is not yet active. This wrapper generates
|
||||
/// local session reports from AH's own session rotation events.
|
||||
pub struct StakingSessionManager;
|
||||
|
||||
impl pezpallet_session::SessionManager<AccountId> for StakingSessionManager {
|
||||
fn new_session(new_index: u32) -> Option<Vec<AccountId>> {
|
||||
<CollatorSelection as pezpallet_session::SessionManager<AccountId>>::new_session(new_index)
|
||||
}
|
||||
|
||||
fn end_session(end_index: u32) {
|
||||
// Forward to CollatorSelection first
|
||||
<CollatorSelection as pezpallet_session::SessionManager<AccountId>>::end_session(end_index);
|
||||
|
||||
// Build local SessionReport for staking era progression
|
||||
let current_era =
|
||||
pezpallet_staking_async::CurrentEra::<Runtime>::get().unwrap_or(0);
|
||||
let active_era_idx = pezpallet_staking_async::ActiveEra::<Runtime>::get()
|
||||
.map(|e| e.index)
|
||||
.unwrap_or(0);
|
||||
|
||||
// Provide activation_timestamp when a planned era exists (CurrentEra > ActiveEra)
|
||||
let activation_timestamp = if current_era > active_era_idx {
|
||||
let now_ms = pezpallet_timestamp::Now::<Runtime>::get();
|
||||
Some((now_ms, current_era))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Equal reward points for all validators
|
||||
let validator_points: Vec<(AccountId, u32)> =
|
||||
pezpallet_staking_async::Validators::<Runtime>::iter_keys()
|
||||
.map(|v| (v, 20u32))
|
||||
.collect();
|
||||
|
||||
let report = rc_client::SessionReport::new_terminal(
|
||||
end_index,
|
||||
validator_points,
|
||||
activation_timestamp,
|
||||
);
|
||||
|
||||
let _ = <Staking as rc_client::AHStakingInterface>::on_relay_session_report(report);
|
||||
}
|
||||
|
||||
fn start_session(start_index: u32) {
|
||||
<CollatorSelection as pezpallet_session::SessionManager<AccountId>>::start_session(
|
||||
start_index,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode)]
|
||||
// Call indices taken from zagros-next runtime.
|
||||
pub enum RelayChainRuntimePallets {
|
||||
|
||||
Reference in New Issue
Block a user