Skip to content

Commit 199da6f

Browse files
Ank4nkianenigmagithub-actions[bot]tdimitrov
authored andcommitted
[AHM] Async Staking module across AH and RC (#8127)
Moved from: #7601. Follow ups to: #7282. Closes: #8146 --- This PR is the final outcome of a multi-month development period, with a lot of background work since 2022. Its main aim is to make pallet-staking, alongside its `type ElectionProvider` compatible to be used in a parachain, and report back the validator set to a relay-chain. This setup is intended to be used for Polkadot, Kusama and Westend relay-chains, with the corresponding AssetHubs hosting the staking system. While this PR is quite big, a lot of the diffs are due to adding a relay and parachain runtime for testing. The following is a guide to help reviewers/auditors distinguish what has actually changed in this PR. > Additional reading: See polkadot-js/apps#11401, and the hackmd shared in there, which contains more in-depth explanation of how RC <> AH communicate. ## Added > [This shows the partial diff](ankn/diff-staking-async...ankn/diff-staking-async-1) introduced in pallet-staking-async and election-provider-multi-block relative to the existing (in master) pallet-staking and election-provider-multi-phase. This PR adds the following new pallets, all of which are not used anywhere yet, with the exception of one (see `westend-runtime` changes below). #### `pallet-election-provider-multi-block` This is a set of 4 pallets, capable of implementing an async, multi-page `ElectionProvider`. This pallet is not used in any real runtime yet, and is intended to be used in `AssetHub`, next to `pallet-staking-async`. #### `pallet-staking-async` A fork of the old `pallet-staking`, with a number of key differences, making it suitable to be used in a parachain: 1. It no longer has access to a secure timestamp, previously used to calculate the duration of an era. 2. It no longer has access to a `pallet-session`. 3. It no longer has access to a `pallet-authorship`. 5. It is capable of working with a multi-page `ElectionProvider`, aka. `pallet-election-provider-multi-block`. To compensate for the above, this pallet relies on XCM messages coming from the relay-chain, informing the pallet of: * When a new era should be activated, and how long its duration was * When an offence has happened on the relay relay-chain * When a session ends on the relay-chain, and how many reward points were accumulated for each validators during that period. #### `pallet-staking-async-ah-client` and `pallet-staking-async-rc-client` Are the two new pallets that facilitate the above communication. #### `pallet-ahm-test` A test-only crate that contains e2e rust-based unit test for all of the above. #### `pallet-staking-async-rc-runtime` and `pallet-staking-async-parachain-runtime` Forks of westend and westend-asset-hub, customized to be used for testing all of the above with Zombienet. It contains a lot of unrelated code as well. ## Changed > [This shows the partial diff](ankn/8127-diff-changed-base...ankn/8127-diff-changed-compare) that shows the changes to existing pallets used in prod runtimes as well as westend runtime changes. #### `Identification` This mechanism, which lives on the relay-chain, is expressed by `type FullIdentification` and `type FullIdentificationOf` in runtimes. It is a way to identify the full data needed to slash a validator. Historically, it was pointing to a validator, and their `struct Exposure`. With the move to Asset-Hub, this is no longer possible for two reasons: 1. Relay chain no longer knows the full exposures 2. Even if, the full exposures are getting bigger and bigger and relying the entirety of it is not scalable. Instead, runtimes now move to a new `type FullIdentificationOf = DefaultExposureOf`, which will identify a validator with a `Exposure::default()`. This is suboptimal, as it forces us to still store a number of bytes. Yet, it allows any old `FullIdentification`, pertaining to an old slash, to be decoded. This compromise is only needed to cater for slashes that happen around the time of AHM. #### `westend-runtime` This runtime already has the `pallet-staking-async-ah-client`, integrated into all the places such that: 1. It handles the validator reward points 2. It handles offences 5. It is the `SessionManager` Yet, it is delegating all of the above to its `type Fallback`, which is the old `pallet-staking`. This is a preparatory step for AHM, and should not be any logical change. #### `pallet-election-provider-multi-phase` This is the old single-page `ElectionProvider`. It has been updated to work with multi-page traits, yet it only supports `page-size = 1` for now. It should not have seen any logical changes. #### `pallet-bags-list` Now has two new features. 1. It can be `Locked`, in which case all updates to it fail with an `Err(_)`, even deletion of a node. This is needed because we cannot alter any nodes in this pallet during a multi-page iteration, aka. multi-page snapshot. 2. To combat this, the same `rebag` transaction can be also be used to remove a node from the list, or add a node to the list. This is done through the `score_of` api. See the file changes and tests under `./substrate/frame/bags-list` for more info. #### RuntimeDebug -> Debug To facilitate debugging, a number of types' `RuntimeDebug` impl has been changed to `Debug`. See #3107 ## Weights Below is a summary of the weights. These are generated using `staking-async/runtimes/parachain`, which assumes 22_500 nominators divided by `32` pages for Polkadot, and 12_500 nominators divided by `16` pages in Kusama, both leading to ~700 nominators snapshotted and exported per page. Doubling these parameters would easily slash the PoV weights by half, but with 10MB PoV, these numbers should be good. Also noting that with PoV clawback, we migth get even more proof_size weight back in the runtime. Although, afaik this reclaimed value does not take compression into account. ``` #### new: polkadot/pallet_election_provider_multi_block.rs old: kusama +-----------------------------------------+--------------------------------------+---------+---------+-----------------+ | File | Extrinsic | Old | New | Change [%] | +======================================================================================================================+ | pallet_election_provider_multi_block.rs | on_initialize_into_snapshot_msp | 2.41MiB | 2.41MiB | -0.03 | |-----------------------------------------+--------------------------------------+---------+---------+-----------------| | pallet_election_provider_multi_block.rs | on_initialize_into_snapshot_rest | 3.24MiB | 3.06MiB | -5.53 | |-----------------------------------------+--------------------------------------+---------+---------+-----------------| | pallet_election_provider_multi_block.rs | on_initialize_into_signed | 3.36MiB | 3.12MiB | -7.12 | |-----------------------------------------+--------------------------------------+---------+---------+-----------------| | pallet_election_provider_multi_block.rs | export_non_terminal | 2.12MiB | 1.32MiB | -37.60 | |-----------------------------------------+--------------------------------------+---------+---------+-----------------| | pallet_election_provider_multi_block.rs | export_terminal | 4.08MiB | 2.25MiB | -44.82 | |-----------------------------------------+--------------------------------------+---------+---------+-----------------| | pallet_election_provider_multi_block.rs | on_initialize_nothing | 3.53KiB | 3.53KiB | Unchanged | |-----------------------------------------+--------------------------------------+---------+---------+-----------------| | pallet_election_provider_multi_block.rs | on_initialize_into_unsigned | 3.71KiB | 3.71KiB | Unchanged | |-----------------------------------------+--------------------------------------+---------+---------+-----------------| | pallet_election_provider_multi_block.rs | on_initialize_into_signed_validation | 3.71KiB | 3.71KiB | Unchanged | |-----------------------------------------+--------------------------------------+---------+---------+-----------------| | pallet_election_provider_multi_block.rs | manage | 0B | 0B | Unchanged | +-----------------------------------------+--------------------------------------+---------+---------+-----------------+ #### new: polkadot/pallet_election_provider_multi_block_signed.rs old: kusama +------------------------------------------------+----------------------+----------+----------+-----------------+ | File | Extrinsic | Old | New | Change [%] | +===============================================================================================================+ | pallet_election_provider_multi_block_signed.rs | bail | 43.61KiB | 82.74KiB | +89.72 | |------------------------------------------------+----------------------+----------+----------+-----------------| | pallet_election_provider_multi_block_signed.rs | register_eject | 46.54KiB | 85.80KiB | +84.35 | |------------------------------------------------+----------------------+----------+----------+-----------------| | pallet_election_provider_multi_block_signed.rs | clear_old_round_data | 85.23KiB | 85.17KiB | -0.06 | |------------------------------------------------+----------------------+----------+----------+-----------------| | pallet_election_provider_multi_block_signed.rs | submit_page | 6.95KiB | 6.90KiB | -0.70 | |------------------------------------------------+----------------------+----------+----------+-----------------| | pallet_election_provider_multi_block_signed.rs | register_not_full | 6.45KiB | 6.39KiB | -1.00 | |------------------------------------------------+----------------------+----------+----------+-----------------| | pallet_election_provider_multi_block_signed.rs | unset_page | 20.76KiB | 18.55KiB | -10.67 | +------------------------------------------------+----------------------+----------+----------+-----------------+ #### new: polkadot/pallet_election_provider_multi_block_unsigned.rs old: kusama +--------------------------------------------------+-------------------+----------+-----------+------------------+ | File | Extrinsic | Old | New | Change [%] | +================================================================================================================+ | pallet_election_provider_multi_block_unsigned.rs | submit_unsigned | 63.56KiB | 696.00KiB | +995.01 | |--------------------------------------------------+-------------------+----------+-----------+------------------| | pallet_election_provider_multi_block_unsigned.rs | validate_unsigned | 1.81KiB | 3.66KiB | +102.65 | +--------------------------------------------------+-------------------+----------+-----------+------------------+ #### new: polkadot/pallet_election_provider_multi_block_verifier.rs old: kusama +--------------------------------------------------+------------------------------------+-----------+-----------+-----------------+ | File | Extrinsic | Old | New | Change [%] | +=================================================================================================================================+ | pallet_election_provider_multi_block_verifier.rs | on_initialize_invalid_terminal | 1.18MiB | 1.69MiB | +42.87 | |--------------------------------------------------+------------------------------------+-----------+-----------+-----------------| | pallet_election_provider_multi_block_verifier.rs | on_initialize_valid_terminal | 1.18MiB | 1.69MiB | +42.71 | |--------------------------------------------------+------------------------------------+-----------+-----------+-----------------| | pallet_election_provider_multi_block_verifier.rs | on_initialize_invalid_non_terminal | 1.30MiB | 450.82KiB | -66.08 | |--------------------------------------------------+------------------------------------+-----------+-----------+-----------------| | pallet_election_provider_multi_block_verifier.rs | on_initialize_valid_non_terminal | 279.93KiB | 62.22KiB | -77.77 | +--------------------------------------------------+------------------------------------+-----------+-----------+-----------------+ ``` <summary> note for PR authors <details> <br> ## TODO - [x] Finalize weights - [x] Lock voter list when snapshot being taken - [x] push based election - [x] OffchainWorker miner can now run on multiple pages - [x] Trimming is improved, all bounds are respected. - [x] clients pallets: add ID - [x] make election prolonged - [x] bring westend-next and ah-next to staking-next - [x] Test pre-migration to post-migration state in ahm-test. - [x] Offence reporting works without exposure info on RC (done but recheck). - [ ] staking-async fix tests - [ ] root offence testing (minimally done in migration test) - [ ] Run benchmarking - [x] ~~Add custom decoder for OffenceDetails~~. ## TODO before finalizing PR - [x] Go over again and ensure no interaction with staking-classic except by AhClient (and pallets that are going away) in Westend. Make any non used apis private. - [ ] Create diff with changes from staking-classic. ## Migration Notes - At the start of the AHM migration, trigger: `RC::pallet_staking_async_ah_client::on_migration_start()` - At the start of the AHM migration, trigger the following: - definitely filter `staking::bond` - RC: set `staking::Forcing` to `ForceNone`. - At the end of the AHM migration, trigger the following - `RC::pallet_staking_async_ah_client::on_migration_end()` - Set `AH::pallet_staking_async::ForceEra` to `Forcing::NotForcing`. - Set RC staking and pool min bond to be u32::max. ## Follow-up - [ ] Offence generation e2e test (zombienet) </details> </summary> --------- Co-authored-by: kianenigma <[email protected]> Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Kian Paimani <[email protected]> Co-authored-by: Tsvetomir Dimitrov <[email protected]>
1 parent b411b8d commit 199da6f

File tree

294 files changed

+80247
-1097
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

294 files changed

+80247
-1097
lines changed

Cargo.lock

Lines changed: 380 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ members = [
352352
"substrate/frame/core-fellowship",
353353
"substrate/frame/delegated-staking",
354354
"substrate/frame/democracy",
355+
"substrate/frame/election-provider-multi-block",
355356
"substrate/frame/election-provider-multi-phase",
356357
"substrate/frame/election-provider-multi-phase/test-staking-e2e",
357358
"substrate/frame/election-provider-support",
@@ -427,6 +428,15 @@ members = [
427428
"substrate/frame/session/benchmarking",
428429
"substrate/frame/society",
429430
"substrate/frame/staking",
431+
"substrate/frame/staking-async",
432+
"substrate/frame/staking-async/ah-client",
433+
"substrate/frame/staking-async/ahm-test",
434+
"substrate/frame/staking-async/rc-client",
435+
"substrate/frame/staking-async/reward-fn",
436+
"substrate/frame/staking-async/runtime-api",
437+
"substrate/frame/staking-async/runtimes/parachain",
438+
"substrate/frame/staking-async/runtimes/rc",
439+
"substrate/frame/staking-async/runtimes/rc/constants",
430440
"substrate/frame/staking/reward-curve",
431441
"substrate/frame/staking/reward-fn",
432442
"substrate/frame/staking/runtime-api",
@@ -945,6 +955,7 @@ pallet-default-config-example = { path = "substrate/frame/examples/default-confi
945955
pallet-delegated-staking = { path = "substrate/frame/delegated-staking", default-features = false }
946956
pallet-democracy = { path = "substrate/frame/democracy", default-features = false }
947957
pallet-dev-mode = { path = "substrate/frame/examples/dev-mode", default-features = false }
958+
pallet-election-provider-multi-block = { path = "substrate/frame/election-provider-multi-block", default-features = false }
948959
pallet-election-provider-multi-phase = { path = "substrate/frame/election-provider-multi-phase", default-features = false }
949960
pallet-election-provider-support-benchmarking = { path = "substrate/frame/election-provider-support/benchmarking", default-features = false }
950961
pallet-elections-phragmen = { path = "substrate/frame/elections-phragmen", default-features = false }
@@ -1014,6 +1025,16 @@ pallet-staking = { path = "substrate/frame/staking", default-features = false }
10141025
pallet-staking-reward-curve = { path = "substrate/frame/staking/reward-curve", default-features = false }
10151026
pallet-staking-reward-fn = { path = "substrate/frame/staking/reward-fn", default-features = false }
10161027
pallet-staking-runtime-api = { path = "substrate/frame/staking/runtime-api", default-features = false }
1028+
# TODO: remove the reward stuff as they are not needed here
1029+
pallet-staking-async = { path = "substrate/frame/staking-async", default-features = false }
1030+
pallet-staking-async-ah-client = { path = "substrate/frame/staking-async/ah-client", default-features = false }
1031+
pallet-staking-async-parachain-runtime = { path = "substrate/frame/staking-async/runtimes/parachain" }
1032+
pallet-staking-async-rc-client = { path = "substrate/frame/staking-async/rc-client", default-features = false }
1033+
pallet-staking-async-rc-runtime = { path = "substrate/frame/staking-async/runtimes/rc" }
1034+
pallet-staking-async-rc-runtime-constants = { path = "substrate/frame/staking-async/runtimes/rc/constants", default-features = false }
1035+
pallet-staking-async-reward-curve = { path = "substrate/frame/staking-async/reward-curve", default-features = false }
1036+
pallet-staking-async-reward-fn = { path = "substrate/frame/staking-async/reward-fn", default-features = false }
1037+
pallet-staking-async-runtime-api = { path = "substrate/frame/staking-async/runtime-api", default-features = false }
10171038
pallet-state-trie-migration = { path = "substrate/frame/state-trie-migration", default-features = false }
10181039
pallet-statement = { default-features = false, path = "substrate/frame/statement" }
10191040
pallet-sudo = { path = "substrate/frame/sudo", default-features = false }

cumulus/pallets/collator-selection/src/mock.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ impl pallet_session::SessionHandler<u64> for TestSessionHandler {
117117
}
118118
fn on_new_session<Ks: OpaqueKeys>(_: bool, keys: &[(u64, Ks)], _: &[(u64, Ks)]) {
119119
SessionChangeBlock::set(System::block_number());
120-
dbg!(keys.len());
121120
SessionHandlerCollators::set(keys.iter().map(|(a, _)| *a).collect::<Vec<_>>())
122121
}
123122
fn on_before_session_ending() {}

docs/sdk/src/guides/your_first_node.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ mod tests {
335335
.output()
336336
.unwrap();
337337

338-
// atleast blocks should be imported
338+
// at least blocks should be imported
339339
assert!(String::from_utf8(output.stderr)
340340
.unwrap()
341341
.contains(format!("Imported #{}", 7).to_string().as_str()));

polkadot/node/primitives/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ const MERKLE_PROOF_MAX_DEPTH: usize = 8;
7373

7474
/// The bomb limit for decompressing code blobs.
7575
#[deprecated(
76-
note = "`VALIDATION_CODE_BOMB_LIMIT` will be removed. Use `validation_code_bomb_limit`
76+
note = "`VALIDATION_CODE_BOMB_LIMIT` will be removed. Use `validation_code_bomb_limit`
7777
runtime API to retrieve the value from the runtime"
7878
)]
7979
pub const VALIDATION_CODE_BOMB_LIMIT: usize = (MAX_CODE_SIZE * 4u32) as usize;

polkadot/parachain/src/primitives.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ pub struct BlockData(#[cfg_attr(feature = "std", serde(with = "bytes"))] pub Vec
163163
Ord,
164164
PartialEq,
165165
PartialOrd,
166-
RuntimeDebug,
166+
Debug,
167167
serde::Serialize,
168168
serde::Deserialize,
169169
TypeInfo,

polkadot/runtime/parachains/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ pallet-session = { workspace = true }
4747
pallet-staking = { workspace = true }
4848
pallet-timestamp = { workspace = true }
4949

50+
# only used in benchmarking
51+
frame-election-provider-support = { workspace = true, optional = true }
52+
5053
polkadot-primitives = { workspace = true }
5154
xcm = { workspace = true }
5255
xcm-executor = { workspace = true }
@@ -80,6 +83,7 @@ std = [
8083
"bitvec/std",
8184
"codec/std",
8285
"frame-benchmarking?/std",
86+
"frame-election-provider-support?/std",
8387
"frame-support/std",
8488
"frame-system/std",
8589
"log/std",
@@ -118,6 +122,7 @@ std = [
118122
]
119123
runtime-benchmarks = [
120124
"frame-benchmarking/runtime-benchmarks",
125+
"frame-election-provider-support/runtime-benchmarks",
121126
"frame-support-test/runtime-benchmarks",
122127
"frame-support/runtime-benchmarks",
123128
"frame-system/runtime-benchmarks",
@@ -139,6 +144,7 @@ runtime-benchmarks = [
139144
"xcm/runtime-benchmarks",
140145
]
141146
try-runtime = [
147+
"frame-election-provider-support?/try-runtime",
142148
"frame-support-test/try-runtime",
143149
"frame-support/try-runtime",
144150
"frame-system/try-runtime",

polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ where
8282

8383
pallet_session::Pallet::<T>::on_initialize(BlockNumberFor::<T>::one());
8484
initializer::Pallet::<T>::on_initialize(BlockNumberFor::<T>::one());
85+
86+
// signal to `pallet-staking`'s `ElectionProvider` to be ready asap.
87+
use frame_election_provider_support::ElectionProvider;
88+
<<T as pallet_staking::Config>::ElectionProvider as ElectionProvider>::asap();
89+
8590
// skip sessions until the new validator set is enacted
8691
while pallet_session::Pallet::<T>::validators().len() < n as usize {
8792
pallet_session::Pallet::<T>::rotate_session();

polkadot/runtime/parachains/src/origin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub mod pallet {
5959
Encode,
6060
Decode,
6161
DecodeWithMemTracking,
62-
sp_core::RuntimeDebug,
62+
Debug,
6363
scale_info::TypeInfo,
6464
MaxEncodedLen,
6565
)]

polkadot/runtime/parachains/src/reward_points.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
2424
use crate::{session_info, shared};
2525
use alloc::collections::btree_set::BTreeSet;
26-
use frame_support::traits::{Defensive, ValidatorSet};
26+
use frame_support::traits::{Defensive, RewardsReporter, ValidatorSet};
2727
use polkadot_primitives::{SessionIndex, ValidatorIndex};
2828

2929
/// The amount of era points given by backing a candidate that is included.
@@ -32,12 +32,13 @@ pub const BACKING_POINTS: u32 = 20;
3232
pub const DISPUTE_STATEMENT_POINTS: u32 = 20;
3333

3434
/// Rewards validators for participating in parachains with era points in pallet-staking.
35-
pub struct RewardValidatorsWithEraPoints<C>(core::marker::PhantomData<C>);
35+
pub struct RewardValidatorsWithEraPoints<C, R>(core::marker::PhantomData<(C, R)>);
3636

37-
impl<C> RewardValidatorsWithEraPoints<C>
37+
impl<C, R> RewardValidatorsWithEraPoints<C, R>
3838
where
39-
C: pallet_staking::Config + session_info::Config,
39+
C: session_info::Config,
4040
C::ValidatorSet: ValidatorSet<C::AccountId, ValidatorId = C::AccountId>,
41+
R: RewardsReporter<C::AccountId>,
4142
{
4243
/// Reward validators in session with points, but only if they are in the active set.
4344
fn reward_only_active(
@@ -61,14 +62,15 @@ where
6162
.filter(|v| active_set.contains(v))
6263
.map(|v| (v, points));
6364

64-
<pallet_staking::Pallet<C>>::reward_by_ids(rewards);
65+
R::reward_by_ids(rewards);
6566
}
6667
}
6768

68-
impl<C> crate::inclusion::RewardValidators for RewardValidatorsWithEraPoints<C>
69+
impl<C, R> crate::inclusion::RewardValidators for RewardValidatorsWithEraPoints<C, R>
6970
where
70-
C: pallet_staking::Config + shared::Config + session_info::Config,
71+
C: shared::Config + session_info::Config,
7172
C::ValidatorSet: ValidatorSet<C::AccountId, ValidatorId = C::AccountId>,
73+
R: RewardsReporter<C::AccountId>,
7274
{
7375
fn reward_backing(indices: impl IntoIterator<Item = ValidatorIndex>) {
7476
let session_index = shared::CurrentSessionIndex::<C>::get();
@@ -78,10 +80,11 @@ where
7880
fn reward_bitfields(_validators: impl IntoIterator<Item = ValidatorIndex>) {}
7981
}
8082

81-
impl<C> crate::disputes::RewardValidators for RewardValidatorsWithEraPoints<C>
83+
impl<C, R> crate::disputes::RewardValidators for RewardValidatorsWithEraPoints<C, R>
8284
where
83-
C: pallet_staking::Config + session_info::Config,
85+
C: session_info::Config,
8486
C::ValidatorSet: ValidatorSet<C::AccountId, ValidatorId = C::AccountId>,
87+
R: RewardsReporter<C::AccountId>,
8588
{
8689
fn reward_dispute_statement(
8790
session: SessionIndex,

0 commit comments

Comments
 (0)