Skip to content

Put a bitten relay's Asset Hub staking client in Buffered - #28

Merged
csmnprschv merged 1 commit into
mainfrom
cosmin-put-a-bitten-relays-asset-hub-staking-client-in-buffered
Sep 15, 2026
Merged

csmnprschv merged 1 commit into
mainfrom
cosmin-put-a-bitten-relays-asset-hub-staking-client-in-buffered

Conversation

@csmnprschv

Copy link
Copy Markdown
Collaborator

Since staking moved to Asset Hub the relay no longer chooses its own
validators. Asset Hub's pallet-staking-async elects from the source
chain's staking state and pushes the set to the relay's StakingAhClient.
Its Mode reads Active on live Polkadot, Kusama and Paseo, and Passive on
live Previewnet.

A fork holds session keys for six accounts, so pallet_session drops
every elected validator, writes an empty Session::QueuedKeys and
announces the next BABE epoch with no authorities. Nobody can claim a
slot in that epoch, so no block ever enacts the next rotation and the
chain stops at the boundary. Session::Validators and Babe::Authorities
both still read six afterwards, so a dead fork looks healthy.

Measured on the Polkadot fork: block 32891881 opened epoch 13768
carrying a BABE NextEpochData digest of 34 bytes, 0x01 0x00 followed by
32 bytes of randomness, so no authorities were announced for epoch
13769. Babe::NextAuthorities went from six to zero across that block.
The fork produced its last block in the final slot of epoch 13768, slot
298129239, and stopped: the first slot of the empty epoch found no
author, and Session::CurrentIndex never advanced past 13768.

In Buffered, StakingAhClient answers new_session() with None
unconditionally, so pallet_session rebuilds the queue from the injected
six, and it refuses any set Asset Hub sends: can_accept_validator_set()
holds only in Active, and the call fails with Error::Blocked.

Staking::ForceEra predates this and stays. Buffered keeps Asset Hub's
set out, so what ForceEra guards is ElectionProviderMultiPhase. Under
SessionsPerEra 1, Previewnet's value, EPM opens its signed phase and
then its unsigned phase every session, and the unsigned phase never
ends: it ends only when elect() is called, and nothing calls it.
Validators' offchain workers compute a candidate validator set once and
keep resubmitting it as an unsigned transaction. Where SessionsPerEra is
6, as on Polkadot and Kusama, it never opens them and the write changes
nothing.

Since staking moved to Asset Hub the relay no longer chooses its own
validators. Asset Hub's pallet-staking-async elects from the source
chain's staking state and pushes the set to the relay's StakingAhClient.
Its Mode reads Active on live Polkadot, Kusama and Paseo, and Passive on
live Previewnet.

A fork holds session keys for six accounts, so pallet_session drops
every elected validator, writes an empty Session::QueuedKeys and
announces the next BABE epoch with no authorities. Nobody can claim a
slot in that epoch, so no block ever enacts the next rotation and the
chain stops at the boundary. Session::Validators and Babe::Authorities
both still read six afterwards, so a dead fork looks healthy.

Measured on the Polkadot fork: block 32891881 opened epoch 13768
carrying a BABE NextEpochData digest of 34 bytes, 0x01 0x00 followed by
32 bytes of randomness, so no authorities were announced for epoch
13769. Babe::NextAuthorities went from six to zero across that block.
The fork produced its last block in the final slot of epoch 13768, slot
298129239, and stopped: the first slot of the empty epoch found no
author, and Session::CurrentIndex never advanced past 13768.

In Buffered, StakingAhClient answers new_session() with None
unconditionally, so pallet_session rebuilds the queue from the injected
six, and it refuses any set Asset Hub sends: can_accept_validator_set()
holds only in Active, and the call fails with Error::Blocked.

Staking::ForceEra predates this and stays. Buffered keeps Asset Hub's
set out, so what ForceEra guards is ElectionProviderMultiPhase. Under
SessionsPerEra 1, Previewnet's value, EPM opens its signed phase and
then its unsigned phase every session, and the unsigned phase never
ends: it ends only when elect() is called, and nothing calls it.
Validators' offchain workers compute a candidate validator set once and
keep resubmitting it as an unsigned transaction. Where SessionsPerEra is
6, as on Polkadot and Kusama, it never opens them and the write changes
nothing.

Signed-off-by: Cosmin Paraschiv <cosmin@parity.io>
@csmnprschv csmnprschv self-assigned this Sep 15, 2026
@csmnprschv
csmnprschv merged commit ef00d7b into main Sep 15, 2026
15 checks passed
@csmnprschv
csmnprschv deleted the cosmin-put-a-bitten-relays-asset-hub-staking-client-in-buffered branch September 15, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants