Skip to content

Commit 791ba98

Browse files
authored
Merge pull request #17 from docknetwork/candidate-whitelist
Candidate whitelist
2 parents 5735cdc + 17108d6 commit 791ba98

File tree

7 files changed

+75
-3
lines changed

7 files changed

+75
-3
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

substrate/frame/staking/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pallet-staking"
3-
version = "4.0.0-dev"
3+
version = "4.1.0-dev"
44
authors = ["Dock.io", "Parity Technologies <admin@parity.io>"]
55
edition = "2021"
66
license = "Apache-2.0"
@@ -39,6 +39,7 @@ rand_chacha = { version = "0.2", default-features = false, optional = true }
3939
[dev-dependencies]
4040
sp-tracing = { version = "5.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29" }
4141
sp-core = { version = "6.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29" }
42+
sp-state-machine = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29" }
4243
sp-npos-elections = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29" }
4344
pallet-balances = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29" }
4445
pallet-timestamp = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.29" }

substrate/frame/staking/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@
282282
#![cfg_attr(not(feature = "std"), no_std)]
283283
#![recursion_limit = "256"]
284284

285+
extern crate alloc;
286+
285287
#[cfg(feature = "runtime-benchmarks")]
286288
pub mod benchmarking;
287289
#[cfg(any(feature = "runtime-benchmarks", test))]

substrate/frame/staking/src/pallet/impls.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,22 @@ impl<T: Config> Pallet<T> {
443443
}
444444

445445
// Set staking information for the new era.
446-
Self::store_stakers_info(exposures, new_planned_era)
446+
let new_validators = Self::store_stakers_info(exposures, new_planned_era);
447+
448+
if let Some(whitelist) = Self::candidate_whitelist() {
449+
let to_remove: Vec<_> = Validators::<T>::iter_keys()
450+
.filter(|validator| {
451+
!whitelist.contains(&validator)
452+
&& !new_validators.iter().any(|active| active == validator)
453+
})
454+
.collect();
455+
456+
for validator in to_remove {
457+
Self::do_remove_validator(&validator);
458+
}
459+
}
460+
461+
new_validators
447462
}
448463

449464
/// Potentially plan a new era.

substrate/frame/staking/src/pallet/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ const STAKING_ID: LockIdentifier = *b"staking ";
5050

5151
#[frame_support::pallet]
5252
pub mod pallet {
53+
use alloc::collections::BTreeSet;
54+
5355
use frame_election_provider_support::ElectionDataProvider;
5456

5557
use crate::BenchmarkingConfig;
@@ -516,6 +518,11 @@ pub mod pallet {
516518
#[pallet::storage]
517519
pub(crate) type ChillThreshold<T: Config> = StorageValue<_, Percent, OptionQuery>;
518520

521+
#[pallet::storage]
522+
#[pallet::getter(fn candidate_whitelist)]
523+
pub type CandidateWhitelist<T: Config> =
524+
StorageValue<_, Option<BTreeSet<T::AccountId>>, ValueQuery>;
525+
519526
#[pallet::genesis_config]
520527
pub struct GenesisConfig<T: Config> {
521528
pub history_depth: u32,
@@ -716,6 +723,8 @@ pub mod pallet {
716723
CommissionTooLow,
717724
/// Can't kill the stash while it has some unclaimed era rewards. It will be possible after claiming.
718725
CantKillStashWithUnclaimedRewards,
726+
/// Can only submit as candidates accounts that were whitelisted.
727+
NotInAWhitelist,
719728
}
720729

721730
#[pallet::hooks]
@@ -1048,6 +1057,11 @@ pub mod pallet {
10481057
Error::<T>::CommissionTooLow
10491058
);
10501059

1060+
ensure!(
1061+
Self::candidate_whitelist().map_or(true, |set| set.contains(&stash)),
1062+
Error::<T>::NotInAWhitelist
1063+
);
1064+
10511065
// Only check limits if they are not already a validator.
10521066
if !Validators::<T>::contains_key(stash) {
10531067
// If this error is reached, we need to adjust the `MinValidatorBond` and start
@@ -1753,6 +1767,18 @@ pub mod pallet {
17531767
})?;
17541768
Ok(())
17551769
}
1770+
1771+
#[pallet::weight(T::DbWeight::get().writes(1))]
1772+
pub fn set_whitelist(
1773+
origin: OriginFor<T>,
1774+
whitelist: Option<BTreeSet<T::AccountId>>,
1775+
) -> DispatchResult {
1776+
ensure_root(origin)?;
1777+
1778+
CandidateWhitelist::<T>::put(whitelist);
1779+
1780+
Ok(())
1781+
}
17561782
}
17571783
}
17581784

substrate/frame/staking/src/testing_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub fn create_stash_controller<T: Config>(
8888
amount,
8989
destination,
9090
)?;
91+
9192
Ok((stash, controller))
9293
}
9394

substrate/frame/staking/src/tests.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
//! Tests for the module.
1919
20+
use core::iter::{empty, once};
21+
2022
use super::{ConfigOp, Event, MaxUnlockingChunks, *};
2123
use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support};
2224
use frame_support::{
@@ -424,6 +426,30 @@ fn change_controller_works() {
424426
})
425427
}
426428

429+
#[test]
430+
fn whitelist_works() {
431+
ExtBuilder::default().build_and_execute(|| {
432+
super::Pallet::<Test>::set_whitelist(Origin::root(), empty().collect()).unwrap();
433+
// 10 and 11 are bonded as stash controller.
434+
assert_eq!(Staking::bonded(&11), Some(10));
435+
436+
// 10 can control 11 who is initially a validator.
437+
assert_ok!(Staking::chill(Origin::signed(10)));
438+
439+
assert_noop!(
440+
Staking::validate(Origin::signed(10), ValidatorPrefs::default()),
441+
Error::<Test>::NotInAWhitelist
442+
);
443+
444+
super::Pallet::<Test>::set_whitelist(Origin::root(), Some(once(11).collect())).unwrap();
445+
446+
assert_ok!(Staking::validate(
447+
Origin::signed(10),
448+
ValidatorPrefs::default()
449+
),);
450+
})
451+
}
452+
427453
#[test]
428454
fn rewards_should_work() {
429455
ExtBuilder::default()

0 commit comments

Comments
 (0)