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 crate::{
22	traits::{
23		self, DispatchInfoOf, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf,
24		SignedExtension, ValidateUnsigned,
25	},
26	transaction_validity::{TransactionSource, TransactionValidity},
27};
28
29/// Definition of something that the external world might want to say; its existence implies that it
30/// has been checked and is good, particularly with regards to the signature.
31///
32/// This is typically passed into [`traits::Applyable::apply`], which should execute
33/// [`CheckedExtrinsic::function`], alongside all other bits and bobs.
34#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)]
35pub struct CheckedExtrinsic<AccountId, Call, Extra> {
36	/// Who this purports to be from and the number of extrinsics have come before
37	/// from the same signer, if anyone (note this is not a signature).
38	pub signed: Option<(AccountId, Extra)>,
39
40	/// The function that should be called.
41	pub function: Call,
42}
43
44impl<AccountId, Call, Extra, RuntimeOrigin> traits::Applyable
45	for CheckedExtrinsic<AccountId, Call, Extra>
46where
47	AccountId: Member + MaybeDisplay,
48	Call: Member + Dispatchable<RuntimeOrigin = RuntimeOrigin>,
49	Extra: SignedExtension<AccountId = AccountId, Call = Call>,
50	RuntimeOrigin: From<Option<AccountId>>,
51{
52	type Call = Call;
53
54	fn validate<U: ValidateUnsigned<Call = Self::Call>>(
55		&self,
56		// TODO [#5006;ToDr] should source be passed to `SignedExtension`s?
57		// Perhaps a change for 2.0 to avoid breaking too much APIs?
58		source: TransactionSource,
59		info: &DispatchInfoOf<Self::Call>,
60		len: usize,
61	) -> TransactionValidity {
62		if let Some((ref id, ref extra)) = self.signed {
63			Extra::validate(extra, id, &self.function, info, len)
64		} else {
65			let valid = Extra::validate_unsigned(&self.function, info, len)?;
66			let unsigned_validation = U::validate_unsigned(source, &self.function)?;
67			Ok(valid.combine_with(unsigned_validation))
68		}
69	}
70
71	fn apply<U: ValidateUnsigned<Call = Self::Call>>(
72		self,
73		info: &DispatchInfoOf<Self::Call>,
74		len: usize,
75	) -> crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>> {
76		let (maybe_who, maybe_pre) = if let Some((id, extra)) = self.signed {
77			let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?;
78			(Some(id), Some(pre))
79		} else {
80			Extra::pre_dispatch_unsigned(&self.function, info, len)?;
81			U::pre_dispatch(&self.function)?;
82			(None, None)
83		};
84		let res = self.function.dispatch(RuntimeOrigin::from(maybe_who));
85		let post_info = match res {
86			Ok(info) => info,
87			Err(err) => err.post_info,
88		};
89		Extra::post_dispatch(
90			maybe_pre,
91			info,
92			&post_info,
93			len,
94			&res.map(|_| ()).map_err(|e| e.error),
95		)?;
96		Ok(res)
97	}
98}