diff --git a/crates/pallet-humanode-session/src/lib.rs b/crates/pallet-humanode-session/src/lib.rs index 9ec64b7fb..afe8b47a1 100644 --- a/crates/pallet-humanode-session/src/lib.rs +++ b/crates/pallet-humanode-session/src/lib.rs @@ -20,7 +20,7 @@ const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[allow(clippy::missing_docs_in_private_items)] #[frame_support::pallet] pub mod pallet { - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, storage::with_storage_layer}; use frame_system::pallet_prelude::*; use super::*; @@ -49,6 +49,9 @@ pub mod pallet { /// The max amount of bioauth-powered session validators. type MaxBioauthValidators: Get; + + /// The maximum number of banned accounts. + type MaxBannedAccounts: Get; } #[pallet::pallet] @@ -71,6 +74,11 @@ pub mod pallet { #[pallet::storage] pub type CurrentSessionIndex = StorageValue<_, SessionIndex, OptionQuery>; + /// A list of all banned accounts that can't be validators in the network. + #[pallet::storage] + pub type BannedAccounts = + StorageValue<_, BoundedVec, ValueQuery>; + /// Possible errors. #[pallet::error] pub enum Error { @@ -81,6 +89,10 @@ pub mod pallet { /// The provided account could not be found in current validators list or it was already /// disabled. AccountIsNotValidator, + /// The account is already banned. + AccountIsAlreadyBanned, + /// The BannedAccounts storage has reached the limit as BoundedVec. + TooManyBannedAccounts, } #[pallet::call] @@ -88,13 +100,39 @@ pub mod pallet { /// Kick validator based on provided account id. #[pallet::call_index(0)] #[pallet::weight(0)] - pub fn kick_validator(origin: OriginFor, account_id: T::AccountId) -> DispatchResult { + pub fn kick(origin: OriginFor, account_id: T::AccountId) -> DispatchResult { ensure_root(origin)?; Self::disable(account_id)?; Ok(()) } + + /// Ban account. + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn ban(origin: OriginFor, account_id: T::AccountId) -> DispatchResult { + ensure_root(origin)?; + + ensure!( + !Self::is_banned(&account_id), + Error::::AccountIsAlreadyBanned + ); + + with_storage_layer(move || { + Self::disable(account_id.clone())?; + + >::try_mutate::<_, DispatchError, _>(move |banned_accounts| { + banned_accounts + .try_push(account_id) + .map_err(|_| Error::::TooManyBannedAccounts)?; + + Ok(()) + })?; + + Ok(()) + }) + } } #[pallet::hooks] @@ -212,6 +250,13 @@ impl Pallet { Ok(()) } + + /// Check whether the provided account is banned or not. + fn is_banned(account_id: &T::AccountId) -> bool { + BannedAccounts::::get() + .iter() + .any(|banned_account_id| banned_account_id == account_id) + } } impl pallet_session::historical::SessionManager>