1use codec::Encode;
22use sp_weights::Weight;
23
24use crate::{
25 traits::{
26 self, transaction_extension::TransactionExtension, AsTransactionAuthorizedOrigin,
27 DispatchInfoOf, DispatchTransaction, Dispatchable, MaybeDisplay, Member,
28 PostDispatchInfoOf, ValidateUnsigned,
29 },
30 transaction_validity::{TransactionSource, TransactionValidity},
31};
32
33use super::unchecked_extrinsic::ExtensionVersion;
34
35const DEFAULT_EXTENSION_VERSION: ExtensionVersion = 0;
38
39#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)]
42pub enum ExtrinsicFormat<AccountId, Extension> {
43 Bare,
46 Signed(AccountId, Extension),
49 General(ExtensionVersion, Extension),
52}
53
54#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)]
60pub struct CheckedExtrinsic<AccountId, Call, Extension> {
61 pub format: ExtrinsicFormat<AccountId, Extension>,
64
65 pub function: Call,
67}
68
69impl<AccountId, Call, Extension, RuntimeOrigin> traits::Applyable
70 for CheckedExtrinsic<AccountId, Call, Extension>
71where
72 AccountId: Member + MaybeDisplay,
73 Call: Member + Dispatchable<RuntimeOrigin = RuntimeOrigin> + Encode,
74 Extension: TransactionExtension<Call>,
75 RuntimeOrigin: From<Option<AccountId>> + AsTransactionAuthorizedOrigin,
76{
77 type Call = Call;
78
79 fn validate<I: ValidateUnsigned<Call = Self::Call>>(
80 &self,
81 source: TransactionSource,
82 info: &DispatchInfoOf<Self::Call>,
83 len: usize,
84 ) -> TransactionValidity {
85 match self.format {
86 ExtrinsicFormat::Bare => {
87 let inherent_validation = I::validate_unsigned(source, &self.function)?;
88 #[allow(deprecated)]
89 let legacy_validation = Extension::bare_validate(&self.function, info, len)?;
90 Ok(legacy_validation.combine_with(inherent_validation))
91 },
92 ExtrinsicFormat::Signed(ref signer, ref extension) => {
93 let origin = Some(signer.clone()).into();
94 extension
95 .validate_only(
96 origin,
97 &self.function,
98 info,
99 len,
100 source,
101 DEFAULT_EXTENSION_VERSION,
102 )
103 .map(|x| x.0)
104 },
105 ExtrinsicFormat::General(extension_version, ref extension) => extension
106 .validate_only(None.into(), &self.function, info, len, source, extension_version)
107 .map(|x| x.0),
108 }
109 }
110
111 fn apply<I: ValidateUnsigned<Call = Self::Call>>(
112 self,
113 info: &DispatchInfoOf<Self::Call>,
114 len: usize,
115 ) -> crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>> {
116 match self.format {
117 ExtrinsicFormat::Bare => {
118 I::pre_dispatch(&self.function)?;
119 Extension::bare_validate_and_prepare(&self.function, info, len)?;
122 let res = self.function.dispatch(None.into());
123 let mut post_info = res.unwrap_or_else(|err| err.post_info);
124 let pd_res = res.map(|_| ()).map_err(|e| e.error);
125 Extension::bare_post_dispatch(info, &mut post_info, len, &pd_res)?;
128 Ok(res)
129 },
130 ExtrinsicFormat::Signed(signer, extension) => extension.dispatch_transaction(
131 Some(signer).into(),
132 self.function,
133 info,
134 len,
135 DEFAULT_EXTENSION_VERSION,
136 ),
137 ExtrinsicFormat::General(extension_version, extension) => extension
138 .dispatch_transaction(None.into(), self.function, info, len, extension_version),
139 }
140 }
141}
142
143impl<AccountId, Call: Dispatchable, Extension: TransactionExtension<Call>>
144 CheckedExtrinsic<AccountId, Call, Extension>
145{
146 pub fn extension_weight(&self) -> Weight {
149 match &self.format {
150 ExtrinsicFormat::Bare => Weight::zero(),
151 ExtrinsicFormat::Signed(_, ext) | ExtrinsicFormat::General(_, ext) =>
152 ext.weight(&self.function),
153 }
154 }
155}