Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
dc9400a
session/staking/westend AH and RC: allow to set/purge session keys vi…
sigurpol Dec 15, 2025
0955884
ah-client: proper weight for set_keys_from_ah, purge_keys_from_ah
sigurpol Dec 17, 2025
3e86054
staking-async/rc-client: improve documentation
sigurpol Dec 17, 2025
1c09588
staking-async-rc-client: only validators are allowed to set/purge keys
sigurpol Dec 18, 2025
9b76270
fix prdoc
sigurpol Dec 18, 2025
4dd074b
staking-async-rc-client: session keys as raw bytes
sigurpol Dec 18, 2025
45a7526
staking-async-rc-client: improve documentation
sigurpol Dec 18, 2025
d36a42c
improve prdoc
sigurpol Dec 18, 2025
5064a6c
staking-async/ah: add unit testss
sigurpol Dec 18, 2025
619ec8a
staking-async/rc: add unit tests
sigurpol Dec 18, 2025
668f7a3
staking-async/ah: add e2e test
sigurpol Dec 18, 2025
e5b2ef8
staking-async/ah: more tests
sigurpol Dec 18, 2025
fe233b0
session keys and ownership proof fully validated on AH
sigurpol Dec 19, 2025
5fd5a0c
Merge branch 'master' into sigurpol-session-keys-asset-hub
sigurpol Dec 19, 2025
d4c3f2f
Updated ownership_proof_is_valid call to use the new 2 arg signature
sigurpol Dec 19, 2025
96a5e00
more tests
sigurpol Dec 19, 2025
bcd7664
Merge branch 'master' into sigurpol-session-keys-asset-hub
sigurpol Dec 24, 2025
e4af53f
staking-async: fix CI
sigurpol Dec 24, 2025
0a13bb5
asset-hub-westend: add support for staking proxy
sigurpol Dec 24, 2025
294704e
staking-async: tests around staking proxy
sigurpol Dec 24, 2025
b28ced4
asset-hub-westend: test keys match between AH and RC
sigurpol Dec 24, 2025
a498cbb
staking-async/rc: add benchmarks for set/purge_keys
sigurpol Dec 26, 2025
3519aef
Merge branch 'master' into sigurpol-session-keys-asset-hub
sigurpol Dec 26, 2025
fa76173
staking-async/rc: bounded vec for set_keys
sigurpol Dec 26, 2025
be0cd04
Update from github-actions[bot] running command 'bench --pallet palle…
github-actions[bot] Dec 26, 2025
23f49e5
Cleanup
sigurpol Dec 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,12 @@ pallet-vesting = { workspace = true }
pallet-whitelist = { workspace = true }
sp-api = { workspace = true }
sp-arithmetic = { workspace = true }
sp-authority-discovery = { workspace = true }
sp-block-builder = { workspace = true }
sp-consensus-aura = { workspace = true }
sp-consensus-babe = { workspace = true }
sp-consensus-beefy = { workspace = true }
sp-consensus-grandpa = { workspace = true }
sp-core = { workspace = true }
sp-genesis-builder = { workspace = true }
sp-inherents = { workspace = true }
Expand All @@ -102,6 +106,7 @@ pallet-xcm = { workspace = true }
pallet-xcm-benchmarks = { optional = true, workspace = true }
pallet-xcm-precompiles = { workspace = true }
polkadot-parachain-primitives = { workspace = true }
polkadot-primitives = { workspace = true }
polkadot-runtime-common = { workspace = true }
westend-runtime-constants = { workspace = true }
xcm = { workspace = true }
Expand Down Expand Up @@ -209,6 +214,7 @@ runtime-benchmarks = [
"pallet-xcm/runtime-benchmarks",
"parachains-common/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-primitives/runtime-benchmarks",
"polkadot-runtime-common/runtime-benchmarks",
"snowbridge-pallet-system-frontend/runtime-benchmarks",
"snowbridge-runtime-common/runtime-benchmarks",
Expand Down Expand Up @@ -369,6 +375,7 @@ std = [
"parachain-info/std",
"parachains-common/std",
"polkadot-parachain-primitives/std",
"polkadot-primitives/std",
"polkadot-runtime-common/std",
"primitive-types/std",
"scale-info/std",
Expand All @@ -378,8 +385,12 @@ std = [
"snowbridge-runtime-common/std",
"sp-api/std",
"sp-arithmetic/std",
"sp-authority-discovery/std",
"sp-block-builder/std",
"sp-consensus-aura/std",
"sp-consensus-babe/std",
"sp-consensus-beefy/std",
"sp-consensus-grandpa/std",
"sp-core/std",
"sp-genesis-builder/std",
"sp-inherents/std",
Expand Down
14 changes: 14 additions & 0 deletions cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ impl_opaque_keys! {
}
}

// Relay chain validator session keys (forwarded to RC).
// IMPORTANT: This MUST match the SessionKeys definition in the corresponding Relay Chain runtime
// (polkadot/runtime/westend/src/lib.rs). If the RC keys change, this must be updated too.
impl_opaque_keys! {
pub struct RCSessionKeys {
pub grandpa: sp_consensus_grandpa::AuthorityId,
pub babe: sp_consensus_babe::AuthorityId,
pub para_validator: polkadot_primitives::ValidatorId,
pub para_assignment: polkadot_primitives::AssignmentId,
pub authority_discovery: sp_authority_discovery::AuthorityId,
pub beefy: sp_consensus_beefy::ecdsa_crypto::AuthorityId,
}
}

#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
// Note: "westmint" is the legacy name for this chain. It has been renamed to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ impl pallet_staking_async_rc_client::Config for Runtime {
type MaxValidatorSetRetries = ConstU32<64>;
// export validator session at end of session 4 within an era.
type ValidatorSetExportSession = ConstU32<4>;
type Keys = RCSessionKeys;
}

#[derive(Encode, Decode)]
Expand All @@ -321,9 +322,15 @@ pub enum RelayChainRuntimePallets {

#[derive(Encode, Decode)]
pub enum AhClientCalls {
// index of `fn validator_set` in `staking-async-ah-client`. It has only one call.
// index of `fn validator_set` in `staking-async-ah-client`.
#[codec(index = 0)]
ValidatorSet(rc_client::ValidatorSetReport<AccountId>),
// index of `fn set_keys_from_ah` in `staking-async-ah-client`.
#[codec(index = 3)]
SetKeys { stash: AccountId, keys: Vec<u8>, proof: Vec<u8> },
// index of `fn purge_keys_from_ah` in `staking-async-ah-client`.
#[codec(index = 4)]
PurgeKeys { stash: AccountId },
}

pub struct ValidatorSetToXcm;
Expand All @@ -347,6 +354,64 @@ impl sp_runtime::traits::Convert<rc_client::ValidatorSetReport<AccountId>, Xcm<(
}
}

/// Message to set session keys on the Relay Chain.
#[derive(Encode, Decode, Clone)]
pub struct SetKeysMessage {
pub stash: AccountId,
pub keys: Vec<u8>,
pub proof: Vec<u8>,
}

pub struct SetKeysToXcm;
impl sp_runtime::traits::Convert<SetKeysMessage, Xcm<()>> for SetKeysToXcm {
fn convert(msg: SetKeysMessage) -> Xcm<()> {
Xcm(vec![
Instruction::UnpaidExecution {
weight_limit: WeightLimit::Unlimited,
check_origin: None,
},
Instruction::Transact {
origin_kind: OriginKind::Native,
fallback_max_weight: None,
call: RelayChainRuntimePallets::AhClient(AhClientCalls::SetKeys {
stash: msg.stash,
keys: msg.keys,
proof: msg.proof,
})
.encode()
.into(),
},
])
}
}

/// Message to purge session keys on the Relay Chain.
#[derive(Encode, Decode, Clone)]
pub struct PurgeKeysMessage {
pub stash: AccountId,
}

pub struct PurgeKeysToXcm;
impl sp_runtime::traits::Convert<PurgeKeysMessage, Xcm<()>> for PurgeKeysToXcm {
fn convert(msg: PurgeKeysMessage) -> Xcm<()> {
Xcm(vec![
Instruction::UnpaidExecution {
weight_limit: WeightLimit::Unlimited,
check_origin: None,
},
Instruction::Transact {
origin_kind: OriginKind::Native,
fallback_max_weight: None,
call: RelayChainRuntimePallets::AhClient(AhClientCalls::PurgeKeys {
stash: msg.stash,
})
.encode()
.into(),
},
])
}
}

parameter_types! {
pub RelayLocation: Location = Location::parent();
}
Expand All @@ -363,6 +428,24 @@ impl rc_client::SendToRelayChain for StakingXcmToRelayChain {
ValidatorSetToXcm,
>::send(report)
}

fn set_keys(stash: Self::AccountId, keys: Vec<u8>, proof: Vec<u8>) -> Result<(), ()> {
rc_client::XCMSender::<
xcm_config::XcmRouter,
RelayLocation,
SetKeysMessage,
SetKeysToXcm,
>::send(SetKeysMessage { stash, keys, proof })
}

fn purge_keys(stash: Self::AccountId) -> Result<(), ()> {
rc_client::XCMSender::<
xcm_config::XcmRouter,
RelayLocation,
PurgeKeysMessage,
PurgeKeysToXcm,
>::send(PurgeKeysMessage { stash })
}
}

parameter_types! {
Expand Down
3 changes: 1 addition & 2 deletions polkadot/runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,6 @@ impl pallet_authorship::Config for Runtime {
parameter_types! {
pub const Period: BlockNumber = 10 * MINUTES;
pub const Offset: BlockNumber = 0;
pub const KeyDeposit: Balance = deposit(1, 5 * 32 + 33);
}

impl_opaque_keys! {
Expand All @@ -535,7 +534,7 @@ impl pallet_session::Config for Runtime {
type DisablingStrategy = pallet_session::disabling::UpToLimitWithReEnablingDisablingStrategy;
type WeightInfo = weights::pallet_session::WeightInfo<Runtime>;
type Currency = Balances;
type KeyDeposit = KeyDeposit;
type KeyDeposit = ();
}

impl pallet_session::historical::Config for Runtime {
Expand Down
18 changes: 18 additions & 0 deletions prdoc/pr_10666.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
title: 'staking-async: allow session keys handling on AssetHub'
doc:
- audience: Runtime Dev
description: |-
- Added session keys handling on AssetHub for staking-async: validators can now call set_keys and purge_keys on AssetHub, which forwards the request to the RelayChain via XCM.
- Validators are still allowed to call `set_keys` and `purge_keys` via relay-chain pallet-session's related extrinsics. This option will be deprecated in the future.
- Until then, no key deposit is set on AssetHub yet
crates:
- name: asset-hub-westend-runtime
bump: major
- name: westend-runtime
bump: major
- name: pallet-session
bump: major
- name: pallet-staking-async-ah-client
bump: major
- name: pallet-staking-async-rc-client
bump: major
11 changes: 9 additions & 2 deletions substrate/frame/session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,10 @@ impl<T: Config> Pallet<T> {
///
/// This ensures that the reference counter in system is incremented appropriately and as such
/// must accept an account ID, rather than a validator ID.
fn do_set_keys(account: &T::AccountId, keys: T::Keys) -> DispatchResult {
///
/// This function is public to allow cross-chain session key management (e.g., from AssetHub
/// via `pallet-staking-async-ah-client`).
pub fn do_set_keys(account: &T::AccountId, keys: T::Keys) -> DispatchResult {
let who = T::ValidatorIdOf::convert(account.clone())
.ok_or(Error::<T>::NoAssociatedValidatorId)?;

Expand Down Expand Up @@ -923,7 +926,11 @@ impl<T: Config> Pallet<T> {
Ok(old_keys)
}

fn do_purge_keys(account: &T::AccountId) -> DispatchResult {
/// Purge session keys for an account.
///
/// This function is public to allow cross-chain session key management (e.g., from AssetHub
/// via `pallet-staking-async-ah-client`).
pub fn do_purge_keys(account: &T::AccountId) -> DispatchResult {
let who = T::ValidatorIdOf::convert(account.clone())
// `purge_keys` may not have a controller-stash pair any more. If so then we expect the
// stash account to be passed in directly and convert that to a `ValidatorId` using the
Expand Down
Loading
Loading