sp_runtime/traits/transaction_extension/
dispatch_transaction.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//! The [DispatchTransaction] trait.
19
20use crate::{
21	generic::ExtensionVersion,
22	traits::AsTransactionAuthorizedOrigin,
23	transaction_validity::{InvalidTransaction, TransactionSource},
24};
25
26use super::*;
27
28/// Single-function utility trait with a blanket impl over [`TransactionExtension`] in order to
29/// provide transaction dispatching functionality. We avoid implementing this directly on the trait
30/// since we never want it to be overriden by the trait implementation.
31pub trait DispatchTransaction<Call: Dispatchable> {
32	/// The origin type of the transaction.
33	type Origin;
34	/// The info type.
35	type Info;
36	/// The resultant type.
37	type Result;
38	/// The `Val` of the extension.
39	type Val;
40	/// The `Pre` of the extension.
41	type Pre;
42	/// Just validate a transaction.
43	///
44	/// The is basically the same as [validate](TransactionExtension::validate), except that there
45	/// is no need to supply the bond data.
46	fn validate_only(
47		&self,
48		origin: Self::Origin,
49		call: &Call,
50		info: &Self::Info,
51		len: usize,
52		source: TransactionSource,
53		extension_version: ExtensionVersion,
54	) -> Result<(ValidTransaction, Self::Val, Self::Origin), TransactionValidityError>;
55	/// Validate and prepare a transaction, ready for dispatch.
56	fn validate_and_prepare(
57		self,
58		origin: Self::Origin,
59		call: &Call,
60		info: &Self::Info,
61		len: usize,
62		extension_version: ExtensionVersion,
63	) -> Result<(Self::Pre, Self::Origin), TransactionValidityError>;
64	/// Dispatch a transaction with the given base origin and call.
65	fn dispatch_transaction(
66		self,
67		origin: Self::Origin,
68		call: Call,
69		info: &Self::Info,
70		len: usize,
71		extension_version: ExtensionVersion,
72	) -> Self::Result;
73	/// Do everything which would be done in a [dispatch_transaction](Self::dispatch_transaction),
74	/// but instead of executing the call, execute `substitute` instead. Since this doesn't actually
75	/// dispatch the call, it doesn't need to consume it and so `call` can be passed as a reference.
76	fn test_run(
77		self,
78		origin: Self::Origin,
79		call: &Call,
80		info: &Self::Info,
81		len: usize,
82		extension_version: ExtensionVersion,
83		substitute: impl FnOnce(
84			Self::Origin,
85		) -> crate::DispatchResultWithInfo<<Call as Dispatchable>::PostInfo>,
86	) -> Self::Result;
87}
88
89impl<T: TransactionExtension<Call>, Call: Dispatchable + Encode> DispatchTransaction<Call> for T
90where
91	<Call as Dispatchable>::RuntimeOrigin: AsTransactionAuthorizedOrigin,
92{
93	type Origin = <Call as Dispatchable>::RuntimeOrigin;
94	type Info = DispatchInfoOf<Call>;
95	type Result = crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Call>>;
96	type Val = T::Val;
97	type Pre = T::Pre;
98
99	fn validate_only(
100		&self,
101		origin: Self::Origin,
102		call: &Call,
103		info: &DispatchInfoOf<Call>,
104		len: usize,
105		source: TransactionSource,
106		extension_version: ExtensionVersion,
107	) -> Result<(ValidTransaction, T::Val, Self::Origin), TransactionValidityError> {
108		match self.validate(
109			origin,
110			call,
111			info,
112			len,
113			self.implicit()?,
114			&TxBaseImplication((extension_version, call)),
115			source,
116		) {
117			// After validation, some origin must have been authorized.
118			Ok((_, _, origin)) if !origin.is_transaction_authorized() =>
119				Err(InvalidTransaction::UnknownOrigin.into()),
120			res => res,
121		}
122	}
123	fn validate_and_prepare(
124		self,
125		origin: Self::Origin,
126		call: &Call,
127		info: &DispatchInfoOf<Call>,
128		len: usize,
129		extension_version: ExtensionVersion,
130	) -> Result<(T::Pre, Self::Origin), TransactionValidityError> {
131		let (_, val, origin) = self.validate_only(
132			origin,
133			call,
134			info,
135			len,
136			TransactionSource::InBlock,
137			extension_version,
138		)?;
139		let pre = self.prepare(val, &origin, &call, info, len)?;
140		Ok((pre, origin))
141	}
142	fn dispatch_transaction(
143		self,
144		origin: <Call as Dispatchable>::RuntimeOrigin,
145		call: Call,
146		info: &DispatchInfoOf<Call>,
147		len: usize,
148		extension_version: ExtensionVersion,
149	) -> Self::Result {
150		let (pre, origin) =
151			self.validate_and_prepare(origin, &call, info, len, extension_version)?;
152		let mut res = call.dispatch(origin);
153		let pd_res = res.map(|_| ()).map_err(|e| e.error);
154		let post_info = match &mut res {
155			Ok(info) => info,
156			Err(err) => &mut err.post_info,
157		};
158		post_info.set_extension_weight(info);
159		T::post_dispatch(pre, info, post_info, len, &pd_res)?;
160		Ok(res)
161	}
162	fn test_run(
163		self,
164		origin: Self::Origin,
165		call: &Call,
166		info: &Self::Info,
167		len: usize,
168		extension_version: ExtensionVersion,
169		substitute: impl FnOnce(
170			Self::Origin,
171		) -> crate::DispatchResultWithInfo<<Call as Dispatchable>::PostInfo>,
172	) -> Self::Result {
173		let (pre, origin) =
174			self.validate_and_prepare(origin, &call, info, len, extension_version)?;
175		let mut res = substitute(origin);
176		let pd_res = res.map(|_| ()).map_err(|e| e.error);
177		let post_info = match &mut res {
178			Ok(info) => info,
179			Err(err) => &mut err.post_info,
180		};
181		post_info.set_extension_weight(info);
182		T::post_dispatch(pre, info, post_info, len, &pd_res)?;
183		Ok(res)
184	}
185}