use frame_support::{dispatch::DispatchResult, traits::Currency, weights::Weight};
pub use pallet::*;
use pallet_identity;
use sp_core::Get;
#[cfg(feature = "runtime-benchmarks")]
use frame_benchmarking::{account, v2::*, BenchmarkError};
pub trait WeightInfo {
fn reap_identity(r: u32, s: u32) -> Weight;
fn poke_deposit() -> Weight;
}
impl WeightInfo for () {
fn reap_identity(_r: u32, _s: u32) -> Weight {
Weight::MAX
}
fn poke_deposit() -> Weight {
Weight::MAX
}
}
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn reap_identity(_r: u32, _s: u32) -> Weight {
Weight::zero()
}
fn poke_deposit() -> Weight {
Weight::zero()
}
}
type BalanceOf<T> = <<T as pallet_identity::Config>::Currency as Currency<
<T as frame_system::Config>::AccountId,
>>::Balance;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::{
dispatch::{DispatchResultWithPostInfo, PostDispatchInfo},
pallet_prelude::*,
traits::EnsureOrigin,
};
use frame_system::pallet_prelude::*;
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config + pallet_identity::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type Reaper: EnsureOrigin<Self::RuntimeOrigin>;
type ReapIdentityHandler: OnReapIdentity<Self::AccountId>;
type WeightInfo: WeightInfo;
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
IdentityReaped { who: T::AccountId },
DepositUpdated { who: T::AccountId, identity: BalanceOf<T>, subs: BalanceOf<T> },
}
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::reap_identity(
T::MaxRegistrars::get(),
T::MaxSubAccounts::get()
))]
pub fn reap_identity(
origin: OriginFor<T>,
who: T::AccountId,
) -> DispatchResultWithPostInfo {
T::Reaper::ensure_origin(origin)?;
let (registrars, bytes, subs) = pallet_identity::Pallet::<T>::reap_identity(&who)?;
T::ReapIdentityHandler::on_reap_identity(&who, bytes, subs)?;
Self::deposit_event(Event::IdentityReaped { who });
let post = PostDispatchInfo {
actual_weight: Some(<T as pallet::Config>::WeightInfo::reap_identity(
registrars, subs,
)),
pays_fee: Pays::No,
};
Ok(post)
}
#[pallet::call_index(1)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::poke_deposit())]
pub fn poke_deposit(origin: OriginFor<T>, who: T::AccountId) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
let (id_deposit, subs_deposit) = pallet_identity::Pallet::<T>::poke_deposit(&who)?;
Self::deposit_event(Event::DepositUpdated {
who,
identity: id_deposit,
subs: subs_deposit,
});
Ok(Pays::No.into())
}
}
}
pub trait OnReapIdentity<AccountId> {
fn on_reap_identity(who: &AccountId, bytes: u32, subs: u32) -> DispatchResult;
#[cfg(feature = "runtime-benchmarks")]
fn ensure_successful_identity_reaping(who: &AccountId, bytes: u32, subs: u32);
}
impl<AccountId> OnReapIdentity<AccountId> for () {
fn on_reap_identity(_who: &AccountId, _bytes: u32, _subs: u32) -> DispatchResult {
Ok(())
}
#[cfg(feature = "runtime-benchmarks")]
fn ensure_successful_identity_reaping(_: &AccountId, _: u32, _: u32) {}
}
#[cfg(feature = "runtime-benchmarks")]
#[benchmarks]
mod benchmarks {
use super::*;
use alloc::{boxed::Box, vec, vec::Vec};
use codec::Encode;
use frame_support::traits::EnsureOrigin;
use frame_system::RawOrigin;
use pallet_identity::{Data, IdentityInformationProvider, Judgement, Pallet as Identity};
use sp_runtime::{
traits::{Bounded, Hash, StaticLookup},
Saturating,
};
const SEED: u32 = 0;
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();
let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
assert_eq!(event, &system_event);
}
#[benchmark]
fn reap_identity(
r: Linear<0, { T::MaxRegistrars::get() }>,
s: Linear<0, { T::MaxSubAccounts::get() }>,
) -> Result<(), BenchmarkError> {
let target: T::AccountId = account("target", 0, SEED);
let target_origin =
<T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(target.clone()));
let target_lookup = T::Lookup::unlookup(target.clone());
let _ = T::Currency::make_free_balance_be(&target, BalanceOf::<T>::max_value());
let info = <T as pallet_identity::Config>::IdentityInformation::create_identity_info();
Identity::<T>::set_identity(
RawOrigin::Signed(target.clone()).into(),
Box::new(info.clone()),
)?;
let mut subs = Vec::new();
let data = Data::Raw(vec![0; 32].try_into().unwrap());
for ii in 0..s {
let sub_account = account("sub", ii, SEED);
subs.push((sub_account, data.clone()));
}
Identity::<T>::set_subs(target_origin.clone(), subs.clone())?;
T::ReapIdentityHandler::ensure_successful_identity_reaping(
&target,
info.encoded_size() as u32,
subs.len() as u32,
);
let registrar_origin = T::RegistrarOrigin::try_successful_origin()
.expect("RegistrarOrigin has no successful origin required for the benchmark");
for ii in 0..r {
let registrar: T::AccountId = account("registrar", ii, SEED);
let registrar_lookup = T::Lookup::unlookup(registrar.clone());
let _ = <T as pallet_identity::Config>::Currency::make_free_balance_be(
®istrar,
<T as pallet_identity::Config>::Currency::minimum_balance(),
);
Identity::<T>::add_registrar(registrar_origin.clone(), registrar_lookup)?;
Identity::<T>::set_fee(RawOrigin::Signed(registrar.clone()).into(), ii, 10u32.into())?;
let fields = <T as pallet_identity::Config>::IdentityInformation::all_fields();
Identity::<T>::set_fields(RawOrigin::Signed(registrar.clone()).into(), ii, fields)?;
Identity::<T>::request_judgement(target_origin.clone(), ii, 10u32.into())?;
Identity::<T>::provide_judgement(
RawOrigin::Signed(registrar).into(),
ii,
target_lookup.clone(),
Judgement::Reasonable,
<T as frame_system::Config>::Hashing::hash_of(&info),
)?;
}
let origin = T::Reaper::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
#[extrinsic_call]
_(origin as T::RuntimeOrigin, target.clone());
assert_last_event::<T>(Event::<T>::IdentityReaped { who: target.clone() }.into());
let fields = <T as pallet_identity::Config>::IdentityInformation::all_fields();
assert!(!Identity::<T>::has_identity(&target, fields));
assert_eq!(Identity::<T>::subs(&target).len(), 0);
Ok(())
}
#[benchmark]
fn poke_deposit() -> Result<(), BenchmarkError> {
let target: T::AccountId = account("target", 0, SEED);
let _ = T::Currency::make_free_balance_be(&target, BalanceOf::<T>::max_value());
let info = <T as pallet_identity::Config>::IdentityInformation::create_identity_info();
let _ = Identity::<T>::set_identity_no_deposit(&target, info.clone());
let sub_account: T::AccountId = account("sub", 0, SEED);
let name = Data::Raw(b"benchsub".to_vec().try_into().unwrap());
let _ = Identity::<T>::set_subs_no_deposit(&target, vec![(sub_account.clone(), name)]);
let expected_id_deposit = <T as pallet_identity::Config>::BasicDeposit::get()
.saturating_add(
<T as pallet_identity::Config>::ByteDeposit::get()
.saturating_mul(<BalanceOf<T>>::from(info.encoded_size() as u32)),
);
let expected_sub_deposit = <T as pallet_identity::Config>::SubAccountDeposit::get();
#[extrinsic_call]
_(RawOrigin::Root, target.clone());
assert_last_event::<T>(
Event::<T>::DepositUpdated {
who: target,
identity: expected_id_deposit,
subs: expected_sub_deposit,
}
.into(),
);
Ok(())
}
impl_benchmark_test_suite!(
Pallet,
crate::integration_tests::new_test_ext(),
crate::integration_tests::Test,
);
}