sp_runtime/generic/
checked_extrinsic.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Generic implementation of an extrinsic that has passed the verification
19//! stage.
20
21use 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
35/// Default version of the [Extension](TransactionExtension) used to construct the inherited
36/// implication for legacy transactions.
37const DEFAULT_EXTENSION_VERSION: ExtensionVersion = 0;
38
39/// The kind of extrinsic this is, including any fields required of that kind. This is basically
40/// the full extrinsic except the `Call`.
41#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)]
42pub enum ExtrinsicFormat<AccountId, Extension> {
43	/// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or
44	/// `ValidateUnsigned`, both deprecated, or alternatively a `ProvideInherent`.
45	Bare,
46	/// Extrinsic has a default `Origin` of `Signed(AccountId)` and must pass all
47	/// `TransactionExtension`s regular checks and includes all extension data.
48	Signed(AccountId, Extension),
49	/// Extrinsic has a default `Origin` of `None` and must pass all `TransactionExtension`s.
50	/// regular checks and includes all extension data.
51	General(ExtensionVersion, Extension),
52}
53
54/// Definition of something that the external world might want to say; its existence implies that it
55/// has been checked and is good, particularly with regards to the signature.
56///
57/// This is typically passed into [`traits::Applyable::apply`], which should execute
58/// [`CheckedExtrinsic::function`], alongside all other bits and bobs.
59#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)]
60pub struct CheckedExtrinsic<AccountId, Call, Extension> {
61	/// Who this purports to be from and the number of extrinsics have come before
62	/// from the same signer, if anyone (note this is not a signature).
63	pub format: ExtrinsicFormat<AccountId, Extension>,
64
65	/// The function that should be called.
66	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				// TODO: Separate logic from `TransactionExtension` into a new `InherentExtension`
120				// interface.
121				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				// TODO: Separate logic from `TransactionExtension` into a new `InherentExtension`
126				// interface.
127				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	/// Returns the weight of the extension of this transaction, if present. If the transaction
147	/// doesn't use any extension, the weight returned is equal to zero.
148	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}