This repository has been archived by the owner on Feb 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
1,700 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
[package] | ||
authors = ["Anonymous"] | ||
description = "Simple staking pallet with a fixed stake." | ||
edition = "2021" | ||
homepage = "https://substrate.io" | ||
license = "Apache-2.0" | ||
name = "pallet-collator-selection" | ||
repository = "https://github.com/paritytech/cumulus/" | ||
version = "3.0.0" | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] | ||
|
||
[dependencies] | ||
log = { version = "0.4.17", default-features = false } | ||
codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.0.0" } | ||
rand = { version = "0.8.5", features = ["std_rng"], default-features = false } | ||
scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } | ||
|
||
sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
sp-staking = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
pallet-authorship = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
pallet-session = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
|
||
frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
|
||
nimbus-primitives = { git = "https://github.com/acurast/nimbus", default-features = false, branch = "polkadot-v0.9.41" } | ||
|
||
[dev-dependencies] | ||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.41" } | ||
|
||
[features] | ||
default = ["std"] | ||
runtime-benchmarks = [ | ||
"frame-benchmarking/runtime-benchmarks", | ||
"frame-support/runtime-benchmarks", | ||
"frame-system/runtime-benchmarks", | ||
] | ||
std = [ | ||
"codec/std", | ||
"log/std", | ||
"scale-info/std", | ||
"rand/std", | ||
"sp-runtime/std", | ||
"sp-staking/std", | ||
"sp-std/std", | ||
"frame-support/std", | ||
"frame-system/std", | ||
"frame-benchmarking/std", | ||
"pallet-authorship/std", | ||
"pallet-session/std", | ||
"nimbus-primitives/std" | ||
] | ||
|
||
try-runtime = [ "frame-support/try-runtime" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
Forked from [paritytech/cumulus](https://github.com/paritytech/cumulus/tree/master/pallets/collator-selection) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,260 @@ | ||
// Copyright (C) 2021 Parity Technologies (UK) Ltd. | ||
// Copyright 2023 Papers AG | ||
|
||
//! Benchmarking setup for pallet-collator-selection | ||
use super::*; | ||
|
||
#[allow(unused)] | ||
use crate::Pallet as CollatorSelection; | ||
use frame_benchmarking::{ | ||
account, benchmarks, impl_benchmark_test_suite, whitelisted_caller, BenchmarkError, | ||
}; | ||
use frame_support::{ | ||
assert_ok, | ||
codec::Decode, | ||
traits::{Currency, EnsureOrigin, Get}, | ||
}; | ||
use frame_system::{EventRecord, RawOrigin}; | ||
use pallet_authorship::EventHandler; | ||
use pallet_session::{self as session, SessionManager}; | ||
use sp_std::prelude::*; | ||
|
||
pub type BalanceOf<T> = | ||
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance; | ||
|
||
const SEED: u32 = 0; | ||
|
||
// TODO: remove if this is given in substrate commit. | ||
macro_rules! whitelist { | ||
($acc:ident) => { | ||
frame_benchmarking::benchmarking::add_to_whitelist( | ||
frame_system::Account::<T>::hashed_key_for(&$acc).into(), | ||
); | ||
}; | ||
} | ||
|
||
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) { | ||
let events = frame_system::Pallet::<T>::events(); | ||
let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into(); | ||
// compare to the last event record | ||
let EventRecord { event, .. } = &events[events.len() - 1]; | ||
assert_eq!(event, &system_event); | ||
} | ||
|
||
fn create_funded_user<T: Config>( | ||
string: &'static str, | ||
n: u32, | ||
balance_factor: u32, | ||
) -> T::AccountId { | ||
let user = account(string, n, SEED); | ||
let balance = T::Currency::minimum_balance() * balance_factor.into(); | ||
let _ = T::Currency::make_free_balance_be(&user, balance); | ||
user | ||
} | ||
|
||
fn keys<T: Config + session::Config>(c: u32) -> <T as session::Config>::Keys { | ||
use rand::{RngCore, SeedableRng}; | ||
|
||
let keys = { | ||
let mut keys = [0u8; 128]; | ||
|
||
if c > 0 { | ||
let mut rng = rand::rngs::StdRng::seed_from_u64(c as u64); | ||
rng.fill_bytes(&mut keys); | ||
} | ||
|
||
keys | ||
}; | ||
|
||
Decode::decode(&mut &keys[..]).unwrap() | ||
} | ||
|
||
fn validator<T: Config + session::Config>(c: u32) -> (T::AccountId, <T as session::Config>::Keys) { | ||
(create_funded_user::<T>("candidate", c, 1000), keys::<T>(c)) | ||
} | ||
|
||
fn register_validators<T: Config + session::Config>(count: u32) -> Vec<T::AccountId> { | ||
let validators = (0..count).map(|c| validator::<T>(c)).collect::<Vec<_>>(); | ||
|
||
for (who, keys) in validators.clone() { | ||
<session::Pallet<T>>::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap(); | ||
} | ||
|
||
validators.into_iter().map(|(who, _)| who).collect() | ||
} | ||
|
||
fn register_candidates<T: Config>(count: u32) { | ||
let candidates = (0..count) | ||
.map(|c| account("candidate", c, SEED)) | ||
.collect::<Vec<_>>(); | ||
assert!( | ||
<CandidacyBond<T>>::get() > 0u32.into(), | ||
"Bond cannot be zero!" | ||
); | ||
|
||
for who in candidates { | ||
T::Currency::make_free_balance_be(&who, <CandidacyBond<T>>::get() * 2u32.into()); | ||
<CollatorSelection<T>>::register_as_candidate(RawOrigin::Signed(who).into()).unwrap(); | ||
} | ||
} | ||
|
||
benchmarks! { | ||
where_clause { where T: pallet_authorship::Config + session::Config } | ||
|
||
set_invulnerables { | ||
let b in 1 .. T::MaxInvulnerables::get(); | ||
let new_invulnerables = register_validators::<T>(b); | ||
let origin = | ||
T::UpdateOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; | ||
}: { | ||
assert_ok!( | ||
<CollatorSelection<T>>::set_invulnerables(origin, new_invulnerables.clone()) | ||
); | ||
} | ||
verify { | ||
assert_last_event::<T>(Event::NewInvulnerables{invulnerables: new_invulnerables}.into()); | ||
} | ||
|
||
set_desired_candidates { | ||
let max: u32 = 999; | ||
let origin = | ||
T::UpdateOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; | ||
}: { | ||
assert_ok!( | ||
<CollatorSelection<T>>::set_desired_candidates(origin, max.clone()) | ||
); | ||
} | ||
verify { | ||
assert_last_event::<T>(Event::NewDesiredCandidates{desired_candidates: max}.into()); | ||
} | ||
|
||
set_candidacy_bond { | ||
let bond_amount: BalanceOf<T> = T::Currency::minimum_balance() * 10u32.into(); | ||
let origin = | ||
T::UpdateOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; | ||
}: { | ||
assert_ok!( | ||
<CollatorSelection<T>>::set_candidacy_bond(origin, bond_amount.clone()) | ||
); | ||
} | ||
verify { | ||
assert_last_event::<T>(Event::NewCandidacyBond{bond_amount}.into()); | ||
} | ||
|
||
// worse case is when we have all the max-candidate slots filled except one, and we fill that | ||
// one. | ||
register_as_candidate { | ||
let c in 1 .. T::MaxCandidates::get() - 1; | ||
|
||
<CandidacyBond<T>>::put(T::Currency::minimum_balance()); | ||
<DesiredCandidates<T>>::put(c + 1); | ||
|
||
register_validators::<T>(c); | ||
register_candidates::<T>(c); | ||
|
||
let caller: T::AccountId = whitelisted_caller(); | ||
let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into(); | ||
T::Currency::make_free_balance_be(&caller, bond.clone()); | ||
|
||
<session::Pallet<T>>::set_keys( | ||
RawOrigin::Signed(caller.clone()).into(), | ||
keys::<T>(c + 1), | ||
Vec::new() | ||
).unwrap(); | ||
|
||
}: _(RawOrigin::Signed(caller.clone())) | ||
verify { | ||
assert_last_event::<T>(Event::CandidateAdded{account_id: caller, deposit: bond / 2u32.into()}.into()); | ||
} | ||
|
||
// worse case is the last candidate leaving. | ||
leave_intent { | ||
let c in (T::MinCandidates::get() + 1) .. T::MaxCandidates::get(); | ||
<CandidacyBond<T>>::put(T::Currency::minimum_balance()); | ||
<DesiredCandidates<T>>::put(c); | ||
|
||
register_validators::<T>(c); | ||
register_candidates::<T>(c); | ||
|
||
let leaving = <Candidates<T>>::get().last().unwrap().who.clone(); | ||
whitelist!(leaving); | ||
}: _(RawOrigin::Signed(leaving.clone())) | ||
verify { | ||
assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving}.into()); | ||
} | ||
|
||
// worse case is paying a non-existing candidate account. | ||
note_author { | ||
<CandidacyBond<T>>::put(T::Currency::minimum_balance()); | ||
T::Currency::make_free_balance_be( | ||
&<CollatorSelection<T>>::account_id(), | ||
T::Currency::minimum_balance() * 4u32.into(), | ||
); | ||
let author = account("author", 0, SEED); | ||
let new_block: T::BlockNumber = 10u32.into(); | ||
|
||
frame_system::Pallet::<T>::set_block_number(new_block); | ||
assert!(T::Currency::free_balance(&author) == 0u32.into()); | ||
}: { | ||
<CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone()) | ||
} verify { | ||
assert!(T::Currency::free_balance(&author) > 0u32.into()); | ||
assert_eq!(frame_system::Pallet::<T>::block_number(), new_block); | ||
} | ||
|
||
// worst case for new session. | ||
new_session { | ||
let r in 1 .. T::MaxCandidates::get(); | ||
let c in 1 .. T::MaxCandidates::get(); | ||
|
||
<CandidacyBond<T>>::put(T::Currency::minimum_balance()); | ||
<DesiredCandidates<T>>::put(c); | ||
frame_system::Pallet::<T>::set_block_number(0u32.into()); | ||
|
||
register_validators::<T>(c); | ||
register_candidates::<T>(c); | ||
|
||
let new_block: T::BlockNumber = 1800u32.into(); | ||
let zero_block: T::BlockNumber = 0u32.into(); | ||
let candidates = <Candidates<T>>::get(); | ||
|
||
let non_removals = c.saturating_sub(r); | ||
|
||
for i in 0..c { | ||
<LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), zero_block); | ||
} | ||
|
||
if non_removals > 0 { | ||
for i in 0..non_removals { | ||
<LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block); | ||
} | ||
} else { | ||
for i in 0..c { | ||
<LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block); | ||
} | ||
} | ||
|
||
let pre_length = <Candidates<T>>::get().len(); | ||
|
||
frame_system::Pallet::<T>::set_block_number(new_block); | ||
|
||
assert!(<Candidates<T>>::get().len() == c as usize); | ||
}: { | ||
<CollatorSelection<T> as SessionManager<_>>::new_session(0) | ||
} verify { | ||
if c > r && non_removals >= T::MinCandidates::get() { | ||
assert!(<Candidates<T>>::get().len() < pre_length); | ||
} else if c > r && non_removals < T::MinCandidates::get() { | ||
assert!(<Candidates<T>>::get().len() == T::MinCandidates::get() as usize); | ||
} else { | ||
assert!(<Candidates<T>>::get().len() == pre_length); | ||
} | ||
} | ||
} | ||
|
||
impl_benchmark_test_suite!( | ||
CollatorSelection, | ||
crate::mock::new_test_ext(), | ||
crate::mock::Test, | ||
); |
Oops, something went wrong.