pallet_handles/
handles_signed_extension.rsuse crate::{Call, Config, Error, MSAIdToDisplayName, WeightInfo};
use common_primitives::msa::MsaValidator;
use core::marker::PhantomData;
use frame_support::{
dispatch::DispatchInfo, ensure, pallet_prelude::ValidTransaction, traits::IsSubType,
unsigned::UnknownTransaction, RuntimeDebugNoBound,
};
use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{
AsSystemOriginSigner, DispatchInfoOf, Dispatchable, PostDispatchInfoOf,
TransactionExtension,
},
transaction_validity::{
InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
},
DispatchError, DispatchResult, ModuleError, Weight,
};
#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct HandlesSignedExtension<T: Config + Send + Sync>(PhantomData<T>);
impl<T: Config + Send + Sync> HandlesSignedExtension<T> {
pub fn new() -> Self {
Self(core::marker::PhantomData)
}
pub fn validate_retire_handle(delegator_key: &T::AccountId) -> TransactionValidity {
const TAG_PREFIX: &str = "HandlesRetireHandle";
let delegator_msa_id =
T::MsaInfoProvider::ensure_valid_msa_key(delegator_key).map_err(map_dispatch_error)?;
let handle_from_state = MSAIdToDisplayName::<T>::try_get(delegator_msa_id)
.map_err(|_| UnknownTransaction::CannotLookup)?;
let expiration = handle_from_state.1;
let current_block = frame_system::Pallet::<T>::block_number();
let is_past_min_lifetime = current_block >= expiration;
ensure!(
is_past_min_lifetime,
map_dispatch_error(DispatchError::Other(
Error::<T>::HandleWithinMortalityPeriod.into()
))
);
ValidTransaction::with_tag_prefix(TAG_PREFIX).build()
}
}
impl<T: Config + Send + Sync> core::fmt::Debug for HandlesSignedExtension<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "HandlesSignedExtension<{:?}>", self.0)
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
Ok(())
}
}
pub fn map_dispatch_error(err: DispatchError) -> InvalidTransaction {
InvalidTransaction::Custom(match err {
DispatchError::Module(ModuleError { error, .. }) => error[0],
_ => 255u8,
})
}
#[derive(RuntimeDebugNoBound)]
pub enum Val {
Valid,
Refund(Weight),
}
#[derive(RuntimeDebugNoBound)]
pub enum Pre {
Valid,
Refund(Weight),
}
impl<T: Config + Send + Sync> TransactionExtension<T::RuntimeCall> for HandlesSignedExtension<T>
where
T::RuntimeCall: Dispatchable<Info = DispatchInfo> + IsSubType<Call<T>>,
<T as frame_system::Config>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId> + Clone,
{
const IDENTIFIER: &'static str = "HandlesSignedExtension";
type Implicit = ();
type Val = Val;
type Pre = Pre;
fn weight(&self, call: &T::RuntimeCall) -> Weight {
if let Some(Call::retire_handle {}) = call.is_sub_type() {
T::WeightInfo::validate_retire_handle_benchmark()
} else {
Weight::zero()
}
}
fn validate(
&self,
origin: <T as frame_system::Config>::RuntimeOrigin,
call: &T::RuntimeCall,
_info: &DispatchInfoOf<T::RuntimeCall>,
_len: usize,
_self_implicit: Self::Implicit,
_inherited_implication: &impl parity_scale_codec::Encode,
_source: TransactionSource,
) -> sp_runtime::traits::ValidateResult<Self::Val, T::RuntimeCall> {
let Some(who) = origin.as_system_origin_signer() else {
return Ok((ValidTransaction::default(), Val::Refund(self.weight(call)), origin));
};
let validity = match call.is_sub_type() {
Some(Call::retire_handle {}) => Self::validate_retire_handle(who),
_ => Ok(Default::default()),
};
validity.map(|v| (v, Val::Valid, origin))
}
fn prepare(
self,
val: Self::Val,
_origin: &<T as frame_system::Config>::RuntimeOrigin,
_call: &T::RuntimeCall,
_info: &DispatchInfoOf<T::RuntimeCall>,
_len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
match val {
Val::Valid => Ok(Pre::Valid),
Val::Refund(w) => Ok(Pre::Refund(w)),
}
}
fn post_dispatch_details(
pre: Self::Pre,
_info: &DispatchInfo,
_post_info: &PostDispatchInfoOf<T::RuntimeCall>,
_len: usize,
_result: &DispatchResult,
) -> Result<Weight, sp_runtime::transaction_validity::TransactionValidityError> {
match pre {
Pre::Valid => Ok(Weight::zero()),
Pre::Refund(w) => Ok(w),
}
}
}