Skip to content

Commit

Permalink
Add pallet_pooled_staking to Dancelight (#774)
Browse files Browse the repository at this point in the history
* Add pallet_pooled_staking to Dancelight

* zepter

* toml-maid

* Fix benchmark compilation

* Fix tests

The max_collators config item was being ignored in Dancelight before
this PR

* Fix benchmark compilation

* Add weights

* typescript-api

* Delay instead of G

* Add staking integration tests

* Add special accounts that need existential deposit to genesis

* Fix total issuance test
  • Loading branch information
tmpolaczyk authored Dec 12, 2024
1 parent ebf3c86 commit 4147496
Show file tree
Hide file tree
Showing 19 changed files with 3,376 additions and 937 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

10 changes: 5 additions & 5 deletions runtime/dancebox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1569,11 +1569,11 @@ parameter_types! {
pub const StakingSessionDelay: u32 = 2;
}

pub struct SessionTimer<G>(PhantomData<G>);
pub struct SessionTimer<Delay>(PhantomData<Delay>);

impl<G> Timer for SessionTimer<G>
impl<Delay> Timer for SessionTimer<Delay>
where
G: Get<u32>,
Delay: Get<u32>,
{
type Instant = u32;

Expand All @@ -1582,7 +1582,7 @@ where
}

fn is_elapsed(instant: &Self::Instant) -> bool {
let delay = G::get();
let delay = Delay::get();
let Some(end) = instant.checked_add(delay) else {
return false;
};
Expand All @@ -1591,7 +1591,7 @@ where

#[cfg(feature = "runtime-benchmarks")]
fn elapsed_instant() -> Self::Instant {
let delay = G::get();
let delay = Delay::get();
Self::now()
.checked_add(delay)
.expect("overflow when computing valid elapsed instant")
Expand Down
4 changes: 4 additions & 0 deletions solo-chains/runtime/dancelight/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ pallet-author-noting-runtime-api = { workspace = true }
pallet-configuration = { workspace = true }
pallet-data-preservers = { workspace = true }
pallet-inflation-rewards = { workspace = true }
pallet-pooled-staking = { workspace = true }
pallet-registrar = { workspace = true }
pallet-registrar-runtime-api = { workspace = true }
pallet-services-payment = { workspace = true }
Expand Down Expand Up @@ -237,6 +238,7 @@ std = [
"pallet-multisig/std",
"pallet-offences/std",
"pallet-parameters/std",
"pallet-pooled-staking/std",
"pallet-preimage/std",
"pallet-proxy/std",
"pallet-ranked-collective/std",
Expand Down Expand Up @@ -347,6 +349,7 @@ runtime-benchmarks = [
"pallet-multisig/runtime-benchmarks",
"pallet-offences/runtime-benchmarks",
"pallet-parameters/runtime-benchmarks",
"pallet-pooled-staking/runtime-benchmarks",
"pallet-preimage/runtime-benchmarks",
"pallet-proxy/runtime-benchmarks",
"pallet-ranked-collective/runtime-benchmarks",
Expand Down Expand Up @@ -425,6 +428,7 @@ try-runtime = [
"pallet-multisig/try-runtime",
"pallet-offences/try-runtime",
"pallet-parameters/try-runtime",
"pallet-pooled-staking/try-runtime",
"pallet-preimage/try-runtime",
"pallet-proxy/try-runtime",
"pallet-ranked-collective/try-runtime",
Expand Down
17 changes: 16 additions & 1 deletion solo-chains/runtime/dancelight/src/genesis_config_presets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,25 @@ fn dancelight_testnet_genesis(
let next_free_para_id = max_para_id
.map(|x| ParaId::from(u32::from(*x) + 1))
.unwrap_or(primitives::LOWEST_PUBLIC_ID);
let accounts_with_ed = [
crate::StakingAccount::get(),
crate::DancelightBondAccount::get(),
crate::PendingRewardsAccount::get(),
];

serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::<Vec<_>>(),
"balances": endowed_accounts
.iter()
.cloned()
.map(|k| (k, ENDOWMENT))
.chain(
accounts_with_ed
.iter()
.cloned()
.map(|k| (k, crate::EXISTENTIAL_DEPOSIT)),
)
.collect::<Vec<_>>(),
},
"session": {
"keys": initial_authorities
Expand Down
129 changes: 125 additions & 4 deletions solo-chains/runtime/dancelight/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,9 @@ pub struct TreasuryBenchmarkHelper<T>(PhantomData<T>);

#[cfg(feature = "runtime-benchmarks")]
use frame_support::traits::Currency;
use frame_support::traits::{ExistenceRequirement, OnUnbalanced, WithdrawReasons};
use frame_support::traits::{
ExistenceRequirement, OnUnbalanced, ValidatorRegistration, WithdrawReasons,
};
use pallet_services_payment::BalanceOf;
#[cfg(feature = "runtime-benchmarks")]
use pallet_treasury::ArgumentsFactory;
Expand Down Expand Up @@ -1307,7 +1309,9 @@ impl pallet_beefy_mmr::Config for Runtime {

impl paras_sudo_wrapper::Config for Runtime {}

use pallet_pooled_staking::traits::{IsCandidateEligible, Timer};
use pallet_staking::SessionInterface;

pub struct DancelightSessionInterface;
impl SessionInterface<AccountId> for DancelightSessionInterface {
fn disable_validator(validator_index: u32) -> bool {
Expand Down Expand Up @@ -1654,10 +1658,106 @@ impl pallet_inflation_rewards::Config for Runtime {
type InflationRate = InflationRate;
type OnUnbalanced = OnUnbalancedInflation;
type PendingRewardsAccount = PendingRewardsAccount;
type StakingRewardsDistributor = InvulnerableRewardDistribution<Self, Balances, ()>;
type StakingRewardsDistributor = InvulnerableRewardDistribution<Self, Balances, PooledStaking>;
type RewardsPortion = RewardsPortion;
}

parameter_types! {
pub StakingAccount: AccountId32 = PalletId(*b"POOLSTAK").into_account_truncating();
pub const InitialManualClaimShareValue: u128 = MILLIUNITS;
pub const InitialAutoCompoundingShareValue: u128 = MILLIUNITS;
pub const MinimumSelfDelegation: u128 = 10_000 * UNITS;
pub const RewardsCollatorCommission: Perbill = Perbill::from_percent(20);
// Need to wait 2 sessions before being able to join or leave staking pools
pub const StakingSessionDelay: u32 = 2;
}

pub struct SessionTimer<Delay>(PhantomData<Delay>);

impl<Delay> Timer for SessionTimer<Delay>
where
Delay: Get<u32>,
{
type Instant = u32;

fn now() -> Self::Instant {
Session::current_index()
}

fn is_elapsed(instant: &Self::Instant) -> bool {
let delay = Delay::get();
let Some(end) = instant.checked_add(delay) else {
return false;
};
end <= Self::now()
}

#[cfg(feature = "runtime-benchmarks")]
fn elapsed_instant() -> Self::Instant {
let delay = Delay::get();
Self::now()
.checked_add(delay)
.expect("overflow when computing valid elapsed instant")
}

#[cfg(feature = "runtime-benchmarks")]
fn skip_to_elapsed() {
let session_to_reach = Self::elapsed_instant();
while Self::now() < session_to_reach {
Session::rotate_session();
}
}
}

pub struct CandidateHasRegisteredKeys;
impl IsCandidateEligible<AccountId> for CandidateHasRegisteredKeys {
fn is_candidate_eligible(a: &AccountId) -> bool {
<Session as ValidatorRegistration<AccountId>>::is_registered(a)
}
#[cfg(feature = "runtime-benchmarks")]
fn make_candidate_eligible(a: &AccountId, eligible: bool) {
use crate::genesis_config_presets::get_authority_keys_from_seed;

if eligible {
let a_u8: &[u8] = a.as_ref();
let seed = sp_runtime::format!("{:?}", a_u8);
let authority_keys = get_authority_keys_from_seed(&seed, None);
let _ = Session::set_keys(
RuntimeOrigin::signed(a.clone()),
SessionKeys {
grandpa: authority_keys.grandpa,
babe: authority_keys.babe,
para_validator: authority_keys.para_validator,
para_assignment: authority_keys.para_assignment,
authority_discovery: authority_keys.authority_discovery,
beefy: authority_keys.beefy,
nimbus: authority_keys.nimbus,
},
vec![],
);
} else {
let _ = Session::purge_keys(RuntimeOrigin::signed(a.clone()));
}
}
}

impl pallet_pooled_staking::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type Balance = Balance;
type StakingAccount = StakingAccount;
type InitialManualClaimShareValue = InitialManualClaimShareValue;
type InitialAutoCompoundingShareValue = InitialAutoCompoundingShareValue;
type MinimumSelfDelegation = MinimumSelfDelegation;
type RuntimeHoldReason = RuntimeHoldReason;
type RewardsCollatorCommission = RewardsCollatorCommission;
type JoiningRequestTimer = SessionTimer<StakingSessionDelay>;
type LeavingRequestTimer = SessionTimer<StakingSessionDelay>;
type EligibleCandidatesBufferSize = ConstU32<100>;
type EligibleCandidatesFilter = CandidateHasRegisteredKeys;
type WeightInfo = weights::pallet_pooled_staking::SubstrateWeight<Runtime>;
}

construct_runtime! {
pub enum Runtime
{
Expand Down Expand Up @@ -1703,6 +1803,7 @@ construct_runtime! {

// InflationRewards must be after Session
InflationRewards: pallet_inflation_rewards = 33,
PooledStaking: pallet_pooled_staking = 34,

// Governance stuff; uncallable initially.
Treasury: pallet_treasury = 40,
Expand Down Expand Up @@ -2101,6 +2202,7 @@ mod benches {
[pallet_external_validators_rewards, ExternalValidatorsRewards]
[pallet_external_validator_slashes, ExternalValidatorSlashes]
[pallet_invulnerables, TanssiInvulnerables]
[pallet_pooled_staking, PooledStaking]
// XCM
[pallet_xcm, PalletXcmExtrinsicsBenchmark::<Runtime>]
[pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::<Runtime>]
Expand Down Expand Up @@ -3041,8 +3143,27 @@ impl tanssi_initializer::ApplyNewSession<Runtime> for OwnApplySession {
ContainerRegistrar::initializer_on_new_session(&session_index);

let invulnerables = TanssiInvulnerables::invulnerables().to_vec();

let next_collators = invulnerables;
let candidates_staking =
pallet_pooled_staking::SortedEligibleCandidates::<Runtime>::get().to_vec();
// Max number of collators is set in pallet_configuration
let target_session_index = session_index.saturating_add(1);
let max_collators = <CollatorConfiguration as GetHostConfiguration<u32>>::max_collators(
target_session_index,
);
let next_collators: Vec<_> = 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();

// Queue next session keys.
let queued_amalgamated = next_collators
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,27 +185,33 @@ fn test_author_collation_aura_change_of_authorities_on_session() {
DAVE.into()
));

assert!(
authorities_for_container(1000u32.into())
== Some(vec![alice_keys.nimbus.clone(), bob_keys.nimbus.clone()])
assert_eq!(
authorities_for_container(1000u32.into()),
Some(vec![alice_keys.nimbus.clone(), bob_keys.nimbus.clone()])
);

// SESSION CHANGE. First session. it takes 2 sessions to see the change
run_to_session(1u32);

assert!(babe_authorities() == vec![alice_keys.babe.clone(), bob_keys.babe.clone()]);
assert!(
authorities_for_container(1000u32.into())
== Some(vec![alice_keys.nimbus.clone(), bob_keys.nimbus.clone()])
assert_eq!(
babe_authorities(),
vec![alice_keys.babe.clone(), bob_keys.babe.clone()]
);
assert_eq!(
authorities_for_container(1000u32.into()),
Some(vec![alice_keys.nimbus.clone(), bob_keys.nimbus.clone()])
);

// Invulnerables should have triggered on new session authorities change
run_to_session(2u32);

assert!(babe_authorities() == vec![alice_keys.babe.clone(), bob_keys.babe.clone()]);
assert!(
authorities_for_container(1000u32.into())
== Some(vec![charlie_keys.nimbus.clone(), dave_keys.nimbus.clone()])
assert_eq!(
babe_authorities(),
vec![alice_keys.babe.clone(), bob_keys.babe.clone()]
);
assert_eq!(
authorities_for_container(1000u32.into()),
Some(vec![charlie_keys.nimbus.clone(), dave_keys.nimbus.clone()])
);
});
}
Expand All @@ -225,7 +231,7 @@ fn test_collators_per_container() {
(AccountId::from(BOB), 100 * UNIT),
])
.with_config(pallet_configuration::HostConfiguration {
max_collators: 2,
max_collators: 100,
min_orchestrator_collators: 0,
max_orchestrator_collators: 0,
collators_per_container: 2,
Expand Down Expand Up @@ -261,9 +267,9 @@ fn test_collators_per_container() {
));

// Initial assignment: Alice & Bob collating for container 1000
assert!(
authorities_for_container(1000u32.into())
== Some(vec![alice_keys.nimbus.clone(), bob_keys.nimbus.clone()])
assert_eq!(
authorities_for_container(1000u32.into()),
Some(vec![alice_keys.nimbus.clone(), bob_keys.nimbus.clone()])
);

// Change the collators_per_container param to 3.
Expand All @@ -275,20 +281,20 @@ fn test_collators_per_container() {

// SESSION CHANGE. First session. it takes 2 sessions to see the change
run_to_session(1u32);
assert!(
authorities_for_container(1000u32.into())
== Some(vec![alice_keys.nimbus.clone(), bob_keys.nimbus.clone()])
assert_eq!(
authorities_for_container(1000u32.into()),
Some(vec![alice_keys.nimbus.clone(), bob_keys.nimbus.clone()])
);

// We should see Charlie included in the authorities now
run_to_session(2u32);
assert!(
authorities_for_container(1000u32.into())
== Some(vec![
alice_keys.nimbus.clone(),
bob_keys.nimbus.clone(),
charlie_keys.nimbus.clone()
])
assert_eq!(
authorities_for_container(1000u32.into()),
Some(vec![
alice_keys.nimbus.clone(),
bob_keys.nimbus.clone(),
charlie_keys.nimbus.clone()
])
);
});
}
Expand Down
1 change: 1 addition & 0 deletions solo-chains/runtime/dancelight/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mod relay_registrar;
mod services_payment;
mod session_keys;
mod slashes;
mod staking;
mod sudo;

#[test]
Expand Down
Loading

0 comments on commit 4147496

Please sign in to comment.