diff --git a/pezcumulus/teyrchains/runtimes/assets/asset-hub-pezkuwichain/src/lib.rs b/pezcumulus/teyrchains/runtimes/assets/asset-hub-pezkuwichain/src/lib.rs index f3a13ae4..9d90a584 100644 --- a/pezcumulus/teyrchains/runtimes/assets/asset-hub-pezkuwichain/src/lib.rs +++ b/pezcumulus/teyrchains/runtimes/assets/asset-hub-pezkuwichain/src/lib.rs @@ -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; type NextSessionRotation = pezpallet_session::PeriodicSessions; - type SessionManager = CollatorSelection; + type SessionManager = StakingSessionManager; // Essentially just Aura, but let's be pedantic. type SessionHandler = ::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; +/// 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::::get(); + if now_ms > 0 { + pezpallet_staking_async::ActiveEra::::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, + ); + } + }); + } + ::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, diff --git a/pezcumulus/teyrchains/runtimes/assets/asset-hub-pezkuwichain/src/staking.rs b/pezcumulus/teyrchains/runtimes/assets/asset-hub-pezkuwichain/src/staking.rs index de146b5e..5203eccb 100644 --- a/pezcumulus/teyrchains/runtimes/assets/asset-hub-pezkuwichain/src/staking.rs +++ b/pezcumulus/teyrchains/runtimes/assets/asset-hub-pezkuwichain/src/staking.rs @@ -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 for StakingSessionManager { + fn new_session(new_index: u32) -> Option> { + >::new_session(new_index) + } + + fn end_session(end_index: u32) { + // Forward to CollatorSelection first + >::end_session(end_index); + + // Build local SessionReport for staking era progression + let current_era = + pezpallet_staking_async::CurrentEra::::get().unwrap_or(0); + let active_era_idx = pezpallet_staking_async::ActiveEra::::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::::get(); + Some((now_ms, current_era)) + } else { + None + }; + + // Equal reward points for all validators + let validator_points: Vec<(AccountId, u32)> = + pezpallet_staking_async::Validators::::iter_keys() + .map(|v| (v, 20u32)) + .collect(); + + let report = rc_client::SessionReport::new_terminal( + end_index, + validator_points, + activation_timestamp, + ); + + let _ = ::on_relay_session_report(report); + } + + fn start_session(start_index: u32) { + >::start_session( + start_index, + ); + } +} + #[derive(Encode, Decode)] // Call indices taken from zagros-next runtime. pub enum RelayChainRuntimePallets {