Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Staking pallet: add bonding restriction #11

Open
wants to merge 1 commit into
base: joystream-polkadot-v0.9.39
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
));
});
}