Skip to content

Commit

Permalink
Use invulnerables and pallet_staking candidates as collators
Browse files Browse the repository at this point in the history
  • Loading branch information
tmpolaczyk committed Sep 4, 2023
1 parent a81275d commit 221439b
Show file tree
Hide file tree
Showing 2 changed files with 351 additions and 3 deletions.
55 changes: 52 additions & 3 deletions runtime/dancebox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub mod migrations;
use {
core::marker::PhantomData,
cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases,
cumulus_primitives_core::{BodyId, ParaId},
cumulus_primitives_core::{relay_chain::SessionIndex, BodyId, ParaId},
frame_support::{
construct_runtime,
dispatch::DispatchClass,
Expand All @@ -59,7 +59,7 @@ use {
},
nimbus_primitives::NimbusId,
pallet_registrar_runtime_api::ContainerChainGenesisData,
pallet_session::ShouldEndSession,
pallet_session::{SessionManager, ShouldEndSession},
pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter, Multiplier},
polkadot_runtime_common::BlockHashCount,
scale_info::TypeInfo,
Expand Down Expand Up @@ -462,6 +462,55 @@ impl pallet_initializer::Config for Runtime {

impl parachain_info::Config for Runtime {}

/// Returns a list of collators by combining pallet_invulnerables and pallet_pooled_staking.
pub struct CollatorsFromInvulnerablesAndThenFromStaking;

/// Play the role of the session manager.
impl SessionManager<AccountId> for CollatorsFromInvulnerablesAndThenFromStaking {
fn new_session(index: SessionIndex) -> Option<Vec<AccountId>> {
log::info!(
"assembling new collators for new session {} at #{:?}",
index,
<frame_system::Pallet<Runtime>>::block_number(),
);

let invulnerables = Invulnerables::invulnerables().to_vec();
let candidates_staking =
pallet_pooled_staking::SortedEligibleCandidates::<Runtime>::get().to_vec();
// Max number of collators is set in pallet_configuration
let max_collators = Configuration::config().max_collators;
let collators = invulnerables
.iter()
.cloned()
.chain(candidates_staking.into_iter().filter_map(|elig| {
let cand = elig.candidate;
if invulnerables.contains(&cand) {
// If a candidate is both in pallet_invulnerables and pallet_staking, do not count it twice
None
} else {
Some(cand)
}
}))
.take(max_collators as usize)
.collect();

// TODO: weight?
/*
frame_system::Pallet::<T>::register_extra_weight_unchecked(
T::WeightInfo::new_session(invulnerables.len() as u32),
DispatchClass::Mandatory,
);
*/
Some(collators)
}
fn start_session(_: SessionIndex) {
// we don't care.
}
fn end_session(_: SessionIndex) {
// we don't care.
}
}

parameter_types! {
pub const Period: u32 = prod_or_fast!(1 * HOURS, 1 * MINUTES);
pub const Offset: u32 = 0;
Expand All @@ -474,7 +523,7 @@ impl pallet_session::Config for Runtime {
type ValidatorIdOf = pallet_invulnerables::IdentityCollator;
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type SessionManager = Invulnerables;
type SessionManager = CollatorsFromInvulnerablesAndThenFromStaking;
// Essentially just Aura, but let's be pedantic.
type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
Expand Down
299 changes: 299 additions & 0 deletions runtime/dancebox/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3204,3 +3204,302 @@ fn test_staking_leave_execute_bad_origin() {
},
);
}

#[test]
fn test_pallet_session_takes_validators_from_invulnerables_and_staking() {
// Alice, Bob, Charlie are invulnerables
// Alice, Dave are in pallet_staking
// Expected collators are Alice, Bob, Charlie, Dave
ExtBuilder::default()
.with_balances(vec![
// Alice gets 10k extra tokens for her mapping deposit
(AccountId::from(ALICE), 210_000 * UNIT),
(AccountId::from(BOB), 100_000 * UNIT),
(AccountId::from(CHARLIE), 100_000 * UNIT),
(AccountId::from(DAVE), 100_000 * UNIT),
])
.with_collators(vec![
(AccountId::from(ALICE), 210 * UNIT),
(AccountId::from(BOB), 100 * UNIT),
(AccountId::from(CHARLIE), 100 * UNIT),
])
.with_para_ids(vec![
(1001, empty_genesis_data(), vec![]),
(1002, empty_genesis_data(), vec![]),
])
.with_config(pallet_configuration::HostConfiguration {
max_collators: 100,
min_orchestrator_collators: 2,
max_orchestrator_collators: 2,
collators_per_container: 2,
})
.build()
.execute_with(|| {
run_to_block(2);

let stake = 10 * MinimumSelfDelegation::get();

assert_ok!(PooledStaking::request_delegate(
origin_of(ALICE.into()),
ALICE.into(),
TargetPool::AutoCompounding,
stake,
));

// Register Dave in pallet_session (invulnerables are automatically registered)
let dave_account_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
assert_ok!(Session::set_keys(
origin_of(DAVE.into()),
dancebox_runtime::SessionKeys {
nimbus: dave_account_id,
},
vec![]
));

assert_ok!(PooledStaking::request_delegate(
origin_of(DAVE.into()),
DAVE.into(),
TargetPool::AutoCompounding,
stake,
));

let eligible_candidates =
pallet_pooled_staking::SortedEligibleCandidates::<Runtime>::get().to_vec();
assert_eq!(
eligible_candidates,
vec![
EligibleCandidate {
candidate: ALICE.into(),
stake
},
EligibleCandidate {
candidate: DAVE.into(),
stake
},
]
);

assert_eq!(
pallet_invulnerables::Invulnerables::<Runtime>::get().to_vec(),
vec![
AccountId::from(ALICE),
AccountId::from(BOB),
AccountId::from(CHARLIE),
]
);

// Need to trigger new session to update pallet_session
run_to_session(2);

assert_eq!(
Session::validators(),
vec![
AccountId::from(ALICE),
AccountId::from(BOB),
AccountId::from(CHARLIE),
AccountId::from(DAVE),
]
);
});
}

#[test]
fn test_pallet_session_limits_num_validators() {
// Set max_collators = 2, now only the first 2 invulnerables are valid collators
ExtBuilder::default()
.with_balances(vec![
// Alice gets 10k extra tokens for her mapping deposit
(AccountId::from(ALICE), 210_000 * UNIT),
(AccountId::from(BOB), 100_000 * UNIT),
(AccountId::from(CHARLIE), 100_000 * UNIT),
(AccountId::from(DAVE), 100_000 * UNIT),
])
.with_collators(vec![
(AccountId::from(ALICE), 210 * UNIT),
(AccountId::from(BOB), 100 * UNIT),
(AccountId::from(CHARLIE), 100 * UNIT),
])
.with_para_ids(vec![
(1001, empty_genesis_data(), vec![]),
(1002, empty_genesis_data(), vec![]),
])
.with_config(pallet_configuration::HostConfiguration {
max_collators: 2,
min_orchestrator_collators: 2,
max_orchestrator_collators: 2,
collators_per_container: 2,
})
.build()
.execute_with(|| {
run_to_block(2);

let stake = 10 * MinimumSelfDelegation::get();

assert_ok!(PooledStaking::request_delegate(
origin_of(ALICE.into()),
ALICE.into(),
TargetPool::AutoCompounding,
stake,
));

// Register Dave in pallet_session (invulnerables are automatically registered)
let dave_account_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
assert_ok!(Session::set_keys(
origin_of(DAVE.into()),
dancebox_runtime::SessionKeys {
nimbus: dave_account_id,
},
vec![]
));

assert_ok!(PooledStaking::request_delegate(
origin_of(DAVE.into()),
DAVE.into(),
TargetPool::AutoCompounding,
stake,
));

let eligible_candidates =
pallet_pooled_staking::SortedEligibleCandidates::<Runtime>::get().to_vec();
assert_eq!(
eligible_candidates,
vec![
EligibleCandidate {
candidate: ALICE.into(),
stake
},
EligibleCandidate {
candidate: DAVE.into(),
stake
},
]
);

assert_eq!(
pallet_invulnerables::Invulnerables::<Runtime>::get().to_vec(),
vec![
AccountId::from(ALICE),
AccountId::from(BOB),
AccountId::from(CHARLIE),
]
);

// Need to trigger new session to update pallet_session
run_to_session(2);

assert_eq!(
Session::validators(),
vec![AccountId::from(ALICE), AccountId::from(BOB),]
);
});
}

#[test]
fn test_pallet_session_limits_num_validators_from_staking() {
// Set max_collators = 2, take 1 invulnerable and the rest from staking
ExtBuilder::default()
.with_balances(vec![
// Alice gets 10k extra tokens for her mapping deposit
(AccountId::from(ALICE), 210_000 * UNIT),
(AccountId::from(BOB), 100_000 * UNIT),
(AccountId::from(CHARLIE), 100_000 * UNIT),
(AccountId::from(DAVE), 100_000 * UNIT),
])
.with_collators(vec![(AccountId::from(ALICE), 210 * UNIT)])
.with_para_ids(vec![
(1001, empty_genesis_data(), vec![]),
(1002, empty_genesis_data(), vec![]),
])
.with_config(pallet_configuration::HostConfiguration {
max_collators: 2,
min_orchestrator_collators: 2,
max_orchestrator_collators: 2,
collators_per_container: 2,
})
.build()
.execute_with(|| {
run_to_block(2);

let stake = 10 * MinimumSelfDelegation::get();

// Register accounts in pallet_session (invulnerables are automatically registered)
let bob_account_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
assert_ok!(Session::set_keys(
origin_of(BOB.into()),
dancebox_runtime::SessionKeys {
nimbus: bob_account_id,
},
vec![]
));
let charlie_account_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
assert_ok!(Session::set_keys(
origin_of(CHARLIE.into()),
dancebox_runtime::SessionKeys {
nimbus: charlie_account_id,
},
vec![]
));
let dave_account_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
assert_ok!(Session::set_keys(
origin_of(DAVE.into()),
dancebox_runtime::SessionKeys {
nimbus: dave_account_id,
},
vec![]
));

assert_ok!(PooledStaking::request_delegate(
origin_of(BOB.into()),
BOB.into(),
TargetPool::AutoCompounding,
stake,
));

assert_ok!(PooledStaking::request_delegate(
origin_of(CHARLIE.into()),
CHARLIE.into(),
TargetPool::AutoCompounding,
stake,
));

assert_ok!(PooledStaking::request_delegate(
origin_of(DAVE.into()),
DAVE.into(),
TargetPool::AutoCompounding,
stake,
));

let eligible_candidates =
pallet_pooled_staking::SortedEligibleCandidates::<Runtime>::get().to_vec();
assert_eq!(
eligible_candidates,
vec![
EligibleCandidate {
candidate: BOB.into(),
stake
},
EligibleCandidate {
candidate: CHARLIE.into(),
stake
},
EligibleCandidate {
candidate: DAVE.into(),
stake
},
]
);

assert_eq!(
pallet_invulnerables::Invulnerables::<Runtime>::get().to_vec(),
vec![AccountId::from(ALICE),]
);

// Need to trigger new session to update pallet_session
run_to_session(2);

assert_eq!(
Session::validators(),
vec![AccountId::from(ALICE), AccountId::from(BOB),]
);
});
}

0 comments on commit 221439b

Please sign in to comment.