Skip to content

Commit

Permalink
staking pallet: add bonding restriction
Browse files Browse the repository at this point in the history
  • Loading branch information
mnaamani committed Mar 1, 2023
1 parent 1837f42 commit 50cf239
Show file tree
Hide file tree
Showing 14 changed files with 75 additions and 2 deletions.
1 change: 1 addition & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ impl pallet_staking::Config for Runtime {
type OnStakerSlash = NominationPools;
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
type BenchmarkingConfig = StakingBenchmarkingConfig;
type BondingRestriction = ();
}

impl pallet_fast_unstake::Config for Runtime {
Expand Down
1 change: 1 addition & 0 deletions frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ impl pallet_staking::Config for Test {
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

impl pallet_offences::Config for Test {
Expand Down
1 change: 1 addition & 0 deletions frame/beefy/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ impl pallet_staking::Config for Test {
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

impl pallet_offences::Config for Test {
Expand Down
1 change: 1 addition & 0 deletions frame/fast-unstake/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ impl pallet_staking::Config for Runtime {
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

pub struct BalanceToU256;
Expand Down
1 change: 1 addition & 0 deletions frame/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ impl pallet_staking::Config for Test {
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

impl pallet_offences::Config for Test {
Expand Down
1 change: 1 addition & 0 deletions frame/nomination-pools/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ impl pallet_staking::Config for Runtime {
type OnStakerSlash = Pools;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions frame/nomination-pools/test-staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ impl pallet_staking::Config for Runtime {
type OnStakerSlash = Pools;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

parameter_types! {
Expand Down
1 change: 1 addition & 0 deletions frame/offences/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ impl pallet_staking::Config for Test {
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

impl pallet_im_online::Config for Test {
Expand Down
1 change: 1 addition & 0 deletions frame/root-offences/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ impl pallet_staking::Config for Test {
type OnStakerSlash = OnStakerSlashMock<Test>;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

impl pallet_session::historical::Config for Test {
Expand Down
1 change: 1 addition & 0 deletions frame/session/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ impl pallet_staking::Config for Test {
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = ();
}

impl crate::Config for Test {}
Expand Down
16 changes: 16 additions & 0 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,3 +958,19 @@ impl BenchmarkingConfig for TestBenchmarkingConfig {
type MaxValidators = frame_support::traits::ConstU32<100>;
type MaxNominators = frame_support::traits::ConstU32<100>;
}

/// Means for checking if there is any external restriction on bonding with a specific account
///
/// Allows for parts of the runtime that might implement other forms of fund locking to prevent
/// incompatible locking on a stash account which could lead to unsafe state.
pub trait BondingRestriction<AccountId> {
/// Determine if bonding is allowed with stash and controller combination
fn can_bond(stash: &AccountId) -> bool;
}

// No restrictions
impl<AccountId> BondingRestriction<AccountId> for () {
fn can_bond(_stash: &AccountId) -> bool {
true
}
}
11 changes: 11 additions & 0 deletions frame/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use sp_staking::offence::{DisableStrategy, OffenceDetails, OnOffenceHandler};

pub const INIT_TIMESTAMP: u64 = 30_000;
pub const BLOCK_TIME: u64 = 1000;
pub const RESTRICTED_ACCOUNT: AccountId = 55500;

/// The AccountId alias in this test module.
pub(crate) type AccountId = u64;
Expand Down Expand Up @@ -304,6 +305,7 @@ impl crate::pallet::pallet::Config for Test {
type OnStakerSlash = OnStakerSlashMock<Test>;
type BenchmarkingConfig = TestBenchmarkingConfig;
type WeightInfo = ();
type BondingRestriction = AccountRestricted555;
}

pub(crate) type StakingCall = crate::Call<Test>;
Expand Down Expand Up @@ -811,3 +813,12 @@ pub(crate) fn staking_events_since_last_call() -> Vec<crate::Event<Test>> {
pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) {
(Balances::free_balance(who), Balances::reserved_balance(who))
}

pub struct AccountRestricted555;

// Restrict stash account
impl BondingRestriction<AccountId> for AccountRestricted555 {
fn can_bond(stash: &AccountId) -> bool {
*stash != RESTRICTED_ACCOUNT
}
}
11 changes: 10 additions & 1 deletion frame/staking/src/pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ mod impls;
pub use impls::*;

use crate::{
slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout,
slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, BondingRestriction, EraPayout,
EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf,
RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk,
ValidatorPrefs,
Expand Down Expand Up @@ -271,6 +271,9 @@ pub mod pallet {

/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;

/// Interface for doing bonding restriction check
type BondingRestriction: BondingRestriction<Self::AccountId>;
}

/// The ideal number of active validators.
Expand Down Expand Up @@ -774,6 +777,8 @@ pub mod pallet {
CommissionTooLow,
/// Some bound is not met.
BoundNotMet,
/// External restriction prevents bonding with given account
BondingRestricted,
}

#[pallet::hooks]
Expand Down Expand Up @@ -867,6 +872,10 @@ pub mod pallet {
return Err(Error::<T>::AlreadyPaired.into())
}

if !T::BondingRestriction::can_bond(&stash) {
return Err(Error::<T>::BondingRestricted.into())
}

// Reject a bond which is considered to be _dust_.
if value < T::Currency::minimum_balance() {
return Err(Error::<T>::InsufficientBond.into())
Expand Down
29 changes: 28 additions & 1 deletion frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use super::{ConfigOp, Event, *};
use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support};
use frame_support::{
assert_noop, assert_ok, assert_storage_noop, bounded_vec,
assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_vec,
dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo},
pallet_prelude::*,
traits::{Currency, Get, ReservableCurrency},
Expand Down Expand Up @@ -5825,3 +5825,30 @@ mod staking_interface {
});
}
}

#[test]
fn bond_restriction_works() {
ExtBuilder::default().build_and_execute(|| {
start_session(2);
assert_err!(
Staking::bond(
RuntimeOrigin::signed(RESTRICTED_ACCOUNT),
1,
1000,
RewardDestination::Controller
),
Error::<Test>::BondingRestricted
);

// put some money in account that we'll use.
let _ = Balances::make_free_balance_be(&(RESTRICTED_ACCOUNT + 1), 2000);

// Using unrestricted account should not fail
assert_ok!(Staking::bond(
RuntimeOrigin::signed(RESTRICTED_ACCOUNT + 1),
1,
1000,
RewardDestination::Controller
));
});
}

0 comments on commit 50cf239

Please sign in to comment.