use frame_support::dispatch::{DispatchInfo, GetDispatchInfo};
use sp_runtime::{
traits::{
self, DispatchInfoOf, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf,
SignedExtension, ValidateUnsigned,
},
transaction_validity::{
InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
},
RuntimeDebug,
};
use crate::SelfContainedCall;
#[derive(Clone, Eq, PartialEq, RuntimeDebug)]
pub enum CheckedSignature<AccountId, Extra, SelfContainedSignedInfo> {
Signed(AccountId, Extra),
Unsigned,
SelfContained(SelfContainedSignedInfo),
}
#[derive(Clone, Eq, PartialEq, RuntimeDebug)]
pub struct CheckedExtrinsic<AccountId, Call, Extra, SelfContainedSignedInfo> {
pub signed: CheckedSignature<AccountId, Extra, SelfContainedSignedInfo>,
pub function: Call,
}
impl<AccountId, Call: GetDispatchInfo, Extra, SelfContainedSignedInfo> GetDispatchInfo
for CheckedExtrinsic<AccountId, Call, Extra, SelfContainedSignedInfo>
{
fn get_dispatch_info(&self) -> DispatchInfo {
self.function.get_dispatch_info()
}
}
impl<AccountId, Call, Extra, SelfContainedSignedInfo, Origin> traits::Applyable
for CheckedExtrinsic<AccountId, Call, Extra, SelfContainedSignedInfo>
where
AccountId: Member + MaybeDisplay,
Call: Member
+ Dispatchable<RuntimeOrigin = Origin>
+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
Extra: SignedExtension<AccountId = AccountId, Call = Call>,
Origin: From<Option<AccountId>>,
SelfContainedSignedInfo: Send + Sync + 'static,
{
type Call = Call;
fn validate<U: ValidateUnsigned<Call = Self::Call>>(
&self,
source: TransactionSource,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
match &self.signed {
CheckedSignature::Signed(id, extra) => {
Extra::validate(extra, id, &self.function, info, len)
}
CheckedSignature::Unsigned => {
let valid = Extra::validate_unsigned(&self.function, info, len)?;
let unsigned_validation = U::validate_unsigned(source, &self.function)?;
Ok(valid.combine_with(unsigned_validation))
}
CheckedSignature::SelfContained(signed_info) => self
.function
.validate_self_contained(signed_info, info, len)
.ok_or(TransactionValidityError::Invalid(
InvalidTransaction::BadProof,
))?,
}
}
fn apply<U: ValidateUnsigned<Call = Self::Call>>(
self,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> sp_runtime::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>> {
match self.signed {
CheckedSignature::Signed(id, extra) => {
let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?;
let maybe_who = Some(id);
let res = self.function.dispatch(Origin::from(maybe_who));
let post_info = match res {
Ok(info) => info,
Err(err) => err.post_info,
};
Extra::post_dispatch(
Some(pre),
info,
&post_info,
len,
&res.map(|_| ()).map_err(|e| e.error),
)?;
Ok(res)
}
CheckedSignature::Unsigned => {
Extra::pre_dispatch_unsigned(&self.function, info, len)?;
U::pre_dispatch(&self.function)?;
let maybe_who = None;
let res = self.function.dispatch(Origin::from(maybe_who));
let post_info = match res {
Ok(info) => info,
Err(err) => err.post_info,
};
Extra::post_dispatch(
None,
info,
&post_info,
len,
&res.map(|_| ()).map_err(|e| e.error),
)?;
Ok(res)
}
CheckedSignature::SelfContained(signed_info) => {
self.function
.pre_dispatch_self_contained(&signed_info, info, len)
.ok_or(TransactionValidityError::Invalid(
InvalidTransaction::BadProof,
))??;
let res = self.function.apply_self_contained(signed_info).ok_or(
TransactionValidityError::Invalid(InvalidTransaction::BadProof),
)?;
let post_info = match res {
Ok(info) => info,
Err(err) => err.post_info,
};
Extra::post_dispatch(
None,
info,
&post_info,
len,
&res.map(|_| ()).map_err(|e| e.error),
)?;
Ok(res)
}
}
}
}