Skip to main content

sp_runtime/generic/
unchecked_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 unchecked (pre-verification) extrinsic.
19
20use crate::{
21	generic::{CheckedExtrinsic, ExtrinsicFormat},
22	traits::{
23		self, AsTransactionAuthorizedOrigin, Checkable, DecodeWithVersion,
24		DecodeWithVersionWithMemTracking, Dispatchable, ExtensionVariant, ExtrinsicCall,
25		ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, InvalidVersion, LazyExtrinsic,
26		MaybeDisplay, Member, Pipeline, PipelineVersion, SignaturePayload, TransactionExtension,
27	},
28	transaction_validity::{InvalidTransaction, TransactionValidityError},
29	OpaqueExtrinsic,
30};
31#[cfg(all(not(feature = "std"), feature = "serde"))]
32use alloc::format;
33use alloc::{vec, vec::Vec};
34use codec::{
35	Compact, CountedInput, Decode, DecodeWithMemLimit, DecodeWithMemTracking, Encode, EncodeLike,
36	Input,
37};
38use core::fmt::{
39	Debug, {self},
40};
41use scale_info::{build::Fields, meta_type, Path, StaticTypeInfo, Type, TypeInfo, TypeParameter};
42use sp_io::hashing::blake2_256;
43use sp_weights::Weight;
44
45/// Type to represent the version of the [Extension](TransactionExtension) used in this extrinsic.
46pub type ExtensionVersion = u8;
47/// Type to represent the extrinsic format version which defines an [UncheckedExtrinsic].
48pub type ExtrinsicVersion = u8;
49
50/// Current version of the [`UncheckedExtrinsic`] encoded format.
51///
52/// This version needs to be bumped if the encoded representation changes.
53/// It ensures that if the representation is changed and the format is not known,
54/// the decoding fails.
55pub const EXTRINSIC_FORMAT_VERSION: ExtrinsicVersion = 5;
56/// Legacy version of the [`UncheckedExtrinsic`] encoded format.
57///
58/// This version was used in the signed/unsigned transaction model and is still supported for
59/// compatibility reasons. It will be deprecated in favor of v5 extrinsics and an inherent/general
60/// transaction model.
61pub const LEGACY_EXTRINSIC_FORMAT_VERSION: ExtrinsicVersion = 4;
62
63/// Maximum decoded heap size for a runtime call (in bytes).
64pub const DEFAULT_MAX_CALL_SIZE: usize = 16 * 1024 * 1024; // 16 MiB
65
66/// The `SignaturePayload` of `UncheckedExtrinsic`.
67pub type UncheckedSignaturePayload<Address, Signature, Extension> = (Address, Signature, Extension);
68
69impl<Address: TypeInfo, Signature: TypeInfo, Extension: TypeInfo> SignaturePayload
70	for UncheckedSignaturePayload<Address, Signature, Extension>
71{
72	type SignatureAddress = Address;
73	type Signature = Signature;
74	type SignatureExtra = Extension;
75}
76
77/// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and
78/// holds any necessary specialized data.
79///
80/// Bare extrinsics and signed extrinsics are extended with the transaction extension version 0,
81/// specified by the generic parameter `ExtensionV0`.
82///
83/// General extrinsics support multiple transaction extension version, specified by both
84/// `ExtensionV0` and `ExtensionOtherVersions`, by default `ExtensionOtherVersions` is set to
85/// invalid version, making `ExtensionV0` the only supported version. If you want to support more
86/// versions, you need to specify the `ExtensionOtherVersions` parameter.
87#[derive(Eq, PartialEq, Clone)]
88pub enum Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions = InvalidVersion> {
89	/// An extrinsic without a signature or any extension. This means it's either an inherent or
90	/// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with
91	/// the general transaction which is without a signature but does have an extension).
92	///
93	/// NOTE: In the future, once we remove `ValidateUnsigned`, this will only serve Inherent
94	/// extrinsics and thus can be renamed to `Inherent`.
95	Bare(ExtrinsicVersion),
96	/// An old-school transaction extrinsic which includes a signature of some hard-coded crypto.
97	/// Available only on extrinsic version 4.
98	Signed(Address, Signature, ExtensionV0),
99	/// A new-school transaction extrinsic which does not include a signature by default. The
100	/// origin authorization, through signatures or other means, is performed by the transaction
101	/// extension in this extrinsic. Available starting with extrinsic version 5.
102	General(ExtensionVariant<ExtensionV0, ExtensionOtherVersions>),
103}
104
105const VERSION_MASK: u8 = 0b0011_1111;
106const TYPE_MASK: u8 = 0b1100_0000;
107const BARE_EXTRINSIC: u8 = 0b0000_0000;
108const SIGNED_EXTRINSIC: u8 = 0b1000_0000;
109const GENERAL_EXTRINSIC: u8 = 0b0100_0000;
110
111impl<Address, Signature, ExtensionV0, ExtensionOtherVersions> Decode
112	for Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>
113where
114	Address: Decode,
115	Signature: Decode,
116	ExtensionV0: Decode,
117	ExtensionOtherVersions: DecodeWithVersion,
118{
119	fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
120		let version_and_type = input.read_byte()?;
121
122		let version = version_and_type & VERSION_MASK;
123		let xt_type = version_and_type & TYPE_MASK;
124
125		let preamble = match (version, xt_type) {
126			(
127				extrinsic_version @ LEGACY_EXTRINSIC_FORMAT_VERSION..=EXTRINSIC_FORMAT_VERSION,
128				BARE_EXTRINSIC,
129			) => Self::Bare(extrinsic_version),
130			(LEGACY_EXTRINSIC_FORMAT_VERSION, SIGNED_EXTRINSIC) => {
131				let address = Address::decode(input)?;
132				let signature = Signature::decode(input)?;
133				let ext = ExtensionV0::decode(input)?;
134				Self::Signed(address, signature, ext)
135			},
136			(EXTRINSIC_FORMAT_VERSION, GENERAL_EXTRINSIC) => {
137				let ext_version = ExtensionVersion::decode(input)?;
138				let ext =
139					ExtensionVariant::<ExtensionV0, ExtensionOtherVersions>::decode_with_version(
140						ext_version,
141						input,
142					)?;
143				Self::General(ext)
144			},
145			(_, _) => return Err("Invalid transaction version".into()),
146		};
147
148		Ok(preamble)
149	}
150}
151
152impl<Address, Signature, ExtensionV0, ExtensionOtherVersions> DecodeWithMemTracking
153	for Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>
154where
155	Address: DecodeWithMemTracking,
156	Signature: DecodeWithMemTracking,
157	ExtensionV0: DecodeWithMemTracking,
158	ExtensionOtherVersions: DecodeWithVersionWithMemTracking,
159{
160}
161
162impl<Address, Signature, ExtensionV0, ExtensionOtherVersions> Encode
163	for Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>
164where
165	Address: Encode,
166	Signature: Encode,
167	ExtensionV0: Encode,
168	ExtensionOtherVersions: Encode + PipelineVersion,
169{
170	fn size_hint(&self) -> usize {
171		match &self {
172			Preamble::Bare(_) => EXTRINSIC_FORMAT_VERSION.size_hint(),
173			Preamble::Signed(address, signature, ext) => LEGACY_EXTRINSIC_FORMAT_VERSION
174				.size_hint()
175				.saturating_add(address.size_hint())
176				.saturating_add(signature.size_hint())
177				.saturating_add(ext.size_hint()),
178			Preamble::General(ext) => EXTRINSIC_FORMAT_VERSION
179				.size_hint()
180				.saturating_add(0u8.size_hint()) // version
181				.saturating_add(ext.size_hint()),
182		}
183	}
184
185	fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
186		match &self {
187			Preamble::Bare(extrinsic_version) => {
188				(extrinsic_version | BARE_EXTRINSIC).encode_to(dest);
189			},
190			Preamble::Signed(address, signature, ext) => {
191				(LEGACY_EXTRINSIC_FORMAT_VERSION | SIGNED_EXTRINSIC).encode_to(dest);
192				address.encode_to(dest);
193				signature.encode_to(dest);
194				ext.encode_to(dest);
195			},
196			Preamble::General(ext) => {
197				(EXTRINSIC_FORMAT_VERSION | GENERAL_EXTRINSIC).encode_to(dest);
198				ext.version().encode_to(dest);
199				ext.encode_to(dest);
200			},
201		}
202	}
203}
204
205impl<Address, Signature, ExtensionV0, ExtensionOtherVersions>
206	Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>
207{
208	/// Returns `Some` if this is a signed extrinsic, together with the relevant inner fields.
209	pub fn to_signed(self) -> Option<(Address, Signature, ExtensionV0)> {
210		match self {
211			Self::Signed(a, s, e) => Some((a, s, e)),
212			_ => None,
213		}
214	}
215}
216
217impl<Address, Signature, ExtensionV0, ExtensionOtherVersions> fmt::Debug
218	for Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>
219where
220	Address: fmt::Debug,
221	ExtensionV0: fmt::Debug,
222	ExtensionOtherVersions: fmt::Debug,
223{
224	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225		match self {
226			Self::Bare(_) => write!(f, "Bare"),
227			Self::Signed(address, _, tx_ext) => write!(f, "Signed({:?}, {:?})", address, tx_ext),
228			Self::General(tx_ext) => write!(f, "General({:?})", tx_ext),
229		}
230	}
231}
232
233/// An extrinsic right from the external world. This is unchecked and so can contain a signature.
234///
235/// An extrinsic is formally described as any external data that is originating from the outside of
236/// the runtime and fed into the runtime as a part of the block-body.
237///
238/// Prerequisite concepts: Inherents vs Transactions
239/// * Inherents are special types of extrinsics that are placed into the block by the block-builder.
240///   They are unsigned because the assertion is that they are "inherently true" by virtue of
241///   getting past all validators.
242/// * Transactions are all other statements provided by external entities that the chain deems
243///   values and decided to include in the block. This value is typically in the form of fee
244///   payment, but it could in principle be any other interaction. Transactions are either signed or
245///   unsigned. A sensible transaction pool should ensure that only transactions that are worthwhile
246///   are considered for block-building.
247///
248/// Types of extrinsics:
249/// - **Bare**: An extrinsic without a signature or any additional data. After being checked, bare
250///   extrinsics can be applied, the apply logic is extended with `ExtensionV0`.
251///   Bare extrinsics are typically used for inherent extrinsics.
252///   Bare extrinsics are also used for some unsigned transactions, this feature will be deprecated,
253///   see [transaction horizon](https://github.com/paritytech/polkadot-sdk/issues/2415).
254/// - **Signed**: An extrinsic with a signature and extended with transaction extension
255///   `ExtensionV0`. (transaction extension: [`TransactionExtension`]).
256/// - **General**: An extrinsic extended with a versioned transaction extension. The transaction
257///   extension is specified by both `ExtensionV0` and `ExtensionOtherVersions`. By default,
258///   `ExtensionOtherVersions` is set to invalid version, making `ExtensionV0` the only supported
259///   version. General transaction is a generalization of signed transaction that doesn't hardcode a
260///   signature, instead signature is to be set and checked by a transaction extension.
261///
262/// #[cfg_attr(all(feature = "std", not(windows)), doc = simple_mermaid::mermaid!("../../docs/mermaid/extrinsics.mmd"))]
263///
264/// This type is by no means enforced within Substrate, but given its genericness, it is highly
265/// likely that for most use-cases it will suffice. Thus, the encoding of this type will dictate
266/// exactly what bytes should be sent to a runtime to transact with it.
267///
268/// This can be checked using [`Checkable`], yielding a [`CheckedExtrinsic`], which is the
269/// counterpart of this type after its signature (and other non-negotiable validity checks) have
270/// passed.
271///
272/// # Usage:
273///
274/// Usage with multiple versions for general transaction.
275/// ```
276/// use sp_runtime::{
277///     generic::UncheckedExtrinsic,
278///     traits::{MultiVersion, PipelineAtVers},
279/// };
280///
281/// struct Signature; // Some signature scheme.
282/// struct Call; // Some call type.
283/// struct AccountId; // Type for account identifier that can sign a transaction.
284///
285/// // Some implementation of `TransactionExtension`.
286/// struct PaymentExt;
287/// struct PaymentV2Ext;
288/// struct SigV2Ext;
289/// struct NonceExt;
290/// struct NonceV2Ext;
291///
292/// // Definition of the extrinsic.
293/// type ExtensionV0 = (SigV2Ext, NonceExt, PaymentExt);
294/// type ExtensionV1 = PipelineAtVers<1, (SigV2Ext, NonceExt, PaymentV2Ext)>;
295/// type ExtensionV2 = PipelineAtVers<2, (SigV2Ext, NonceV2Ext, PaymentV2Ext)>;
296///
297/// type OtherVersions = MultiVersion<ExtensionV1, ExtensionV2>;
298///
299/// type Extrinsic = UncheckedExtrinsic<
300///     AccountId,
301///     Call,
302///     Signature,
303///     ExtensionV0,
304///     OtherVersions,
305/// >;
306/// ```
307#[derive(DecodeWithMemTracking, Eq, Clone)]
308#[codec(decode_with_mem_tracking_bound(
309	Address: DecodeWithMemTracking,
310	Call: DecodeWithMemTracking,
311	Signature: DecodeWithMemTracking,
312	ExtensionV0: DecodeWithMemTracking,
313	ExtensionOtherVersions: DecodeWithVersionWithMemTracking,
314))]
315pub struct UncheckedExtrinsic<
316	Address,
317	Call,
318	Signature,
319	ExtensionV0,
320	ExtensionOtherVersions = InvalidVersion,
321	const MAX_CALL_SIZE: usize = DEFAULT_MAX_CALL_SIZE,
322> {
323	/// Information regarding the type of extrinsic this is (inherent or transaction) as well as
324	/// associated extension (`Extension`) data if it's a transaction and a possible signature.
325	pub preamble: Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>,
326	/// The function that should be called.
327	pub function: Call,
328	/// Stores the raw encoded call.
329	///
330	/// This is mainly interesting if this extrinsic was created by decoding it from bytes. In this
331	/// case this field should be set to `Some` holding the original bytes used to decode the
332	/// [`Self::function`]. This is done to protect against decode implementations of `Call` that
333	/// are not bijective (encodes to the exact same bytes it was encoded from). If this `field`
334	/// is set, it is being used when re-encoding this transaction.
335	pub encoded_call: Option<Vec<u8>>,
336	/// The encoded length of this extrinsic.
337	///
338	/// Used internally to optimize some allocations, should be set to `None` if not known.
339	#[codec(skip)]
340	pub encoded_len: Option<usize>,
341}
342
343impl<
344		Address: Debug,
345		Call: Debug,
346		Signature: Debug,
347		ExtensionV0: Debug,
348		ExtensionOtherVersions: Debug,
349		const MAX_CALL_SIZE: usize,
350	> Debug
351	for UncheckedExtrinsic<
352		Address,
353		Call,
354		Signature,
355		ExtensionV0,
356		ExtensionOtherVersions,
357		MAX_CALL_SIZE,
358	>
359{
360	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361		let mut debug_struct = f.debug_struct("UncheckedExtrinsic");
362
363		debug_struct.field("preamble", &self.preamble);
364
365		// Given our current allocator, we can at maximum allocate 32MiB and this is not enough for
366		// big transactions.
367		if self.encoded_len.unwrap_or_default() < 1024 * 1024 {
368			debug_struct.field("function", &self.function)
369		} else {
370			debug_struct.field("function", &"Too big to be printed from the runtime")
371		}
372		.finish()
373	}
374}
375
376impl<
377		Address: PartialEq,
378		Call: PartialEq,
379		Signature: PartialEq,
380		ExtensionV0: PartialEq,
381		ExtensionOtherVersions: PartialEq,
382		const MAX_CALL_SIZE: usize,
383	> PartialEq
384	for UncheckedExtrinsic<
385		Address,
386		Call,
387		Signature,
388		ExtensionV0,
389		ExtensionOtherVersions,
390		MAX_CALL_SIZE,
391	>
392{
393	fn eq(&self, other: &Self) -> bool {
394		self.preamble == other.preamble && self.function == other.function
395	}
396}
397
398/// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded
399/// `Vec<u8>`, but requires some logic to extract the signature and payload.
400///
401/// See [`UncheckedExtrinsic::encode`] and [`UncheckedExtrinsic::decode`].
402impl<Address, Call, Signature, ExtensionV0, const MAX_CALL_SIZE: usize, ExtensionOtherVersions>
403	TypeInfo
404	for UncheckedExtrinsic<
405		Address,
406		Call,
407		Signature,
408		ExtensionV0,
409		ExtensionOtherVersions,
410		MAX_CALL_SIZE,
411	>
412where
413	Address: StaticTypeInfo,
414	Call: StaticTypeInfo,
415	Signature: StaticTypeInfo,
416	ExtensionV0: StaticTypeInfo,
417	ExtensionOtherVersions: StaticTypeInfo,
418{
419	type Identity = UncheckedExtrinsic<
420		Address,
421		Call,
422		Signature,
423		ExtensionV0,
424		ExtensionOtherVersions,
425		MAX_CALL_SIZE,
426	>;
427
428	fn type_info() -> Type {
429		Type::builder()
430			.path(Path::new("UncheckedExtrinsic", module_path!()))
431			// Include the type parameter types, even though they are not used directly in any of
432			// the described fields. These type definitions can be used by downstream consumers
433			// to help construct the custom decoding from the opaque bytes (see below).
434			.type_params(vec![
435				TypeParameter::new("Address", Some(meta_type::<Address>())),
436				TypeParameter::new("Call", Some(meta_type::<Call>())),
437				TypeParameter::new("Signature", Some(meta_type::<Signature>())),
438				TypeParameter::new("Extra", Some(meta_type::<ExtensionV0>())),
439				// NOTE: We avoid adding `ExtensionOtherVersions` in the type parameter type info
440				// because they break tools like subxt that hard-coded the number of type
441				// parameters. Also in general type parameters are not useful, information related
442				// to transaction extension are available in the metadata like for v16 the fields
443				// `transaction_extensions_by_version` and `transaction_extensions`.
444			])
445			.docs(&["UncheckedExtrinsic raw bytes, requires custom decoding routine"])
446			// Because of the custom encoding, we can only accurately describe the encoding as an
447			// opaque `Vec<u8>`. Downstream consumers will need to manually implement the codec to
448			// encode/decode the `signature` and `function` fields.
449			.composite(Fields::unnamed().field(|f| f.ty::<Vec<u8>>()))
450	}
451}
452
453impl<Address, Call, Signature, ExtensionV0, ExtensionOtherVersions, const MAX_CALL_SIZE: usize>
454	UncheckedExtrinsic<Address, Call, Signature, ExtensionV0, ExtensionOtherVersions, MAX_CALL_SIZE>
455{
456	/// New instance of a bare (ne unsigned) extrinsic. This could be used for an inherent or an
457	/// old-school "unsigned transaction" (which are new being deprecated in favour of general
458	/// transactions).
459	#[deprecated = "Use new_bare instead"]
460	pub fn new_unsigned(function: Call) -> Self {
461		Self::new_bare(function)
462	}
463
464	/// Returns `true` if this extrinsic instance is an inherent, `false`` otherwise.
465	pub fn is_inherent(&self) -> bool {
466		matches!(self.preamble, Preamble::Bare(_))
467	}
468
469	/// Returns `true` if this extrinsic instance is an old-school signed transaction, `false`
470	/// otherwise.
471	pub fn is_signed(&self) -> bool {
472		matches!(self.preamble, Preamble::Signed(..))
473	}
474
475	/// Create an `UncheckedExtrinsic` from a `Preamble` and the actual `Call`.
476	pub fn from_parts(
477		function: Call,
478		preamble: Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>,
479	) -> Self {
480		Self { preamble, function, encoded_call: None, encoded_len: None }
481	}
482
483	/// New instance of a bare (ne unsigned) extrinsic.
484	pub fn new_bare(function: Call) -> Self {
485		Self::from_parts(function, Preamble::Bare(EXTRINSIC_FORMAT_VERSION))
486	}
487
488	/// New instance of a bare (ne unsigned) extrinsic on extrinsic format version 4.
489	pub fn new_bare_legacy(function: Call) -> Self {
490		Self::from_parts(function, Preamble::Bare(LEGACY_EXTRINSIC_FORMAT_VERSION))
491	}
492
493	/// New instance of an old-school signed transaction on extrinsic format version 4.
494	pub fn new_signed(
495		function: Call,
496		signed: Address,
497		signature: Signature,
498		tx_ext: ExtensionV0,
499	) -> Self {
500		Self::from_parts(function, Preamble::Signed(signed, signature, tx_ext))
501	}
502
503	/// New instance of a new-school unsigned transaction.
504	pub fn new_transaction(function: Call, tx_ext: ExtensionV0) -> Self {
505		Self::from_parts(function, Preamble::General(ExtensionVariant::V0(tx_ext)))
506	}
507
508	fn decode_with_len<I: Input>(input: &mut I, len: usize) -> Result<Self, codec::Error>
509	where
510		Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>: DecodeWithMemTracking,
511		Call: DecodeWithMemTracking,
512	{
513		let mut input = CountedInput::new(input);
514
515		// Decode the preamble using the same memory limit as we will use for the `call`.
516		// The preamble is not that big, but we play it safe.
517		let preamble =
518			DecodeWithMemLimit::decode_with_mem_limit(&mut input, MAX_CALL_SIZE.saturating_add(1))?;
519
520		struct CloneBytes<'a, I>(&'a mut I, Vec<u8>);
521		impl<I: Input> Input for CloneBytes<'_, I> {
522			fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
523				self.0.remaining_len()
524			}
525
526			fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
527				self.0.read(into)?;
528
529				self.1.extend_from_slice(into);
530				Ok(())
531			}
532
533			fn descend_ref(&mut self) -> Result<(), codec::Error> {
534				self.0.descend_ref()
535			}
536
537			fn ascend_ref(&mut self) {
538				self.0.ascend_ref();
539			}
540
541			fn on_before_alloc_mem(&mut self, size: usize) -> Result<(), codec::Error> {
542				self.0.on_before_alloc_mem(size)
543			}
544		}
545
546		let mut clone_bytes = CloneBytes(&mut input, Vec::with_capacity(len));
547
548		// Adds 1 byte to the `MAX_CALL_SIZE` as the decoding fails exactly at the given value and
549		// the maximum should be allowed to fit in.
550		let function =
551			Call::decode_with_mem_limit(&mut clone_bytes, MAX_CALL_SIZE.saturating_add(1))?;
552
553		let encoded_call = Some(clone_bytes.1);
554
555		if input.count() != len as u64 {
556			return Err("Invalid length prefix".into());
557		}
558
559		Ok(Self { preamble, function, encoded_call, encoded_len: Some(len) })
560	}
561
562	fn encode_without_prefix(&self) -> Vec<u8>
563	where
564		Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>: Encode,
565		Call: Encode,
566	{
567		let mut encoded = self.preamble.encode();
568
569		match &self.encoded_call {
570			Some(call) => {
571				encoded.extend(call);
572			},
573			None => {
574				self.function.encode_to(&mut encoded);
575			},
576		}
577
578		encoded
579	}
580}
581
582impl<Address, Call, Signature, ExtensionV0, const MAX_CALL_SIZE: usize, ExtensionOtherVersions>
583	ExtrinsicLike
584	for UncheckedExtrinsic<
585		Address,
586		Call,
587		Signature,
588		ExtensionV0,
589		ExtensionOtherVersions,
590		MAX_CALL_SIZE,
591	>
592{
593	fn is_signed(&self) -> Option<bool> {
594		Some(matches!(self.preamble, Preamble::Signed(..)))
595	}
596
597	fn is_bare(&self) -> bool {
598		matches!(self.preamble, Preamble::Bare(_))
599	}
600}
601
602impl<Address, Call, Signature, ExtensionV0, const MAX_CALL_SIZE: usize, ExtensionOtherVersions>
603	ExtrinsicCall
604	for UncheckedExtrinsic<
605		Address,
606		Call,
607		Signature,
608		ExtensionV0,
609		ExtensionOtherVersions,
610		MAX_CALL_SIZE,
611	>
612{
613	type Call = Call;
614
615	fn call(&self) -> &Call {
616		&self.function
617	}
618
619	fn into_call(self) -> Self::Call {
620		self.function
621	}
622}
623
624// TODO: Migrate existing extension pipelines to support current `Signed` transactions as `General`
625// transactions by adding an extension to validate signatures, as they are currently validated in
626// the `Checkable` implementation for `Signed` transactions.
627
628impl<
629		LookupSource,
630		AccountId,
631		Call,
632		Signature,
633		ExtensionV0,
634		const MAX_CALL_SIZE: usize,
635		ExtensionOtherVersions,
636		Lookup,
637	> Checkable<Lookup>
638	for UncheckedExtrinsic<
639		LookupSource,
640		Call,
641		Signature,
642		ExtensionV0,
643		ExtensionOtherVersions,
644		MAX_CALL_SIZE,
645	>
646where
647	LookupSource: Member + MaybeDisplay,
648	Call: Encode + Member + Dispatchable,
649	Signature: Member + traits::Verify,
650	<Signature as traits::Verify>::Signer: IdentifyAccount<AccountId = AccountId>,
651	ExtensionV0: Encode + TransactionExtension<Call>,
652	AccountId: Member + MaybeDisplay,
653	Lookup: traits::Lookup<Source = LookupSource, Target = AccountId>,
654{
655	type Checked = CheckedExtrinsic<AccountId, Call, ExtensionV0, ExtensionOtherVersions>;
656
657	fn check(self, lookup: &Lookup) -> Result<Self::Checked, TransactionValidityError> {
658		Ok(match self.preamble {
659			Preamble::Signed(signed, signature, tx_ext) => {
660				let signed = lookup.lookup(signed)?;
661				// The `Implicit` is "implicitly" included in the payload.
662				let raw_payload = SignedPayload::new(
663					CallAndMaybeEncoded { encoded: self.encoded_call, call: self.function },
664					tx_ext,
665				)?;
666
667				let mut payload = Vec::with_capacity(self.encoded_len.unwrap_or_default());
668				raw_payload.0.encode_to(&mut payload);
669
670				let payload =
671					if payload.len() > 256 { blake2_256(&payload).to_vec() } else { payload };
672
673				if !signature.verify(payload.as_ref(), &signed) {
674					return Err(InvalidTransaction::BadProof.into());
675				}
676
677				let (function, tx_ext, _) = raw_payload.deconstruct();
678				CheckedExtrinsic { format: ExtrinsicFormat::Signed(signed, tx_ext), function }
679			},
680			Preamble::General(tx_ext) => CheckedExtrinsic {
681				format: ExtrinsicFormat::General(tx_ext),
682				function: self.function,
683			},
684			Preamble::Bare(_) => {
685				CheckedExtrinsic { format: ExtrinsicFormat::Bare, function: self.function }
686			},
687		})
688	}
689
690	#[cfg(feature = "try-runtime")]
691	fn unchecked_into_checked_i_know_what_i_am_doing(
692		self,
693		lookup: &Lookup,
694	) -> Result<Self::Checked, TransactionValidityError> {
695		Ok(match self.preamble {
696			Preamble::Signed(signed, _, tx_ext) => {
697				let signed = lookup.lookup(signed)?;
698				CheckedExtrinsic {
699					format: ExtrinsicFormat::Signed(signed, tx_ext),
700					function: self.function,
701				}
702			},
703			Preamble::General(tx_ext) => CheckedExtrinsic {
704				format: ExtrinsicFormat::General(tx_ext),
705				function: self.function,
706			},
707			Preamble::Bare(_) => {
708				CheckedExtrinsic { format: ExtrinsicFormat::Bare, function: self.function }
709			},
710		})
711	}
712}
713
714impl<
715		Address,
716		Call: Dispatchable,
717		Signature,
718		ExtensionV0,
719		const MAX_CALL_SIZE: usize,
720		ExtensionOtherVersions,
721	> ExtrinsicMetadata
722	for UncheckedExtrinsic<
723		Address,
724		Call,
725		Signature,
726		ExtensionV0,
727		ExtensionOtherVersions,
728		MAX_CALL_SIZE,
729	>
730{
731	const VERSIONS: &'static [u8] = &[LEGACY_EXTRINSIC_FORMAT_VERSION, EXTRINSIC_FORMAT_VERSION];
732	type TransactionExtensionPipelines = ExtensionVariant<ExtensionV0, ExtensionOtherVersions>;
733}
734
735impl<Address, Call, Signature, ExtensionV0, const MAX_CALL_SIZE: usize, ExtensionOtherVersions>
736	UncheckedExtrinsic<Address, Call, Signature, ExtensionV0, ExtensionOtherVersions, MAX_CALL_SIZE>
737where
738	Call: Dispatchable + Encode,
739	ExtensionV0: TransactionExtension<Call>,
740	ExtensionOtherVersions: Pipeline<Call>,
741	<Call as Dispatchable>::RuntimeOrigin: AsTransactionAuthorizedOrigin,
742{
743	/// Returns the weight of the extension of this transaction, if present. If the transaction
744	/// doesn't use any extension, the weight returned is equal to zero.
745	pub fn extension_weight(&self) -> Weight {
746		match &self.preamble {
747			Preamble::Bare(_) => Weight::zero(),
748			Preamble::Signed(_, _, ext) => ext.weight(&self.function),
749			Preamble::General(ext) => ext.weight(&self.function),
750		}
751	}
752}
753
754impl<Address, Call, Signature, ExtensionV0, ExtensionOtherVersions, const MAX_CALL_SIZE: usize>
755	Decode
756	for UncheckedExtrinsic<
757		Address,
758		Call,
759		Signature,
760		ExtensionV0,
761		ExtensionOtherVersions,
762		MAX_CALL_SIZE,
763	>
764where
765	Address: DecodeWithMemTracking,
766	Signature: DecodeWithMemTracking,
767	Call: DecodeWithMemTracking,
768	ExtensionV0: DecodeWithMemTracking,
769	ExtensionOtherVersions: DecodeWithVersionWithMemTracking,
770{
771	fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
772		// This is a little more complicated than usual since the binary format must be compatible
773		// with SCALE's generic `Vec<u8>` type. Basically this just means accepting that there
774		// will be a prefix of vector length.
775		let expected_length: Compact<u32> = Decode::decode(input)?;
776
777		Self::decode_with_len(input, expected_length.0 as usize)
778	}
779}
780
781#[docify::export(unchecked_extrinsic_encode_impl)]
782impl<Address, Call, Signature, ExtensionV0, const MAX_CALL_SIZE: usize, ExtensionOtherVersions>
783	Encode
784	for UncheckedExtrinsic<
785		Address,
786		Call,
787		Signature,
788		ExtensionV0,
789		ExtensionOtherVersions,
790		MAX_CALL_SIZE,
791	>
792where
793	Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>: Encode,
794	Call: Encode,
795	ExtensionV0: Encode,
796	ExtensionOtherVersions: Encode,
797{
798	fn encode(&self) -> Vec<u8> {
799		let tmp = self.encode_without_prefix();
800
801		let compact_len = codec::Compact::<u32>(tmp.len() as u32);
802
803		// Allocate the output buffer with the correct length
804		let mut output = Vec::with_capacity(compact_len.size_hint() + tmp.len());
805
806		compact_len.encode_to(&mut output);
807		output.extend(tmp);
808
809		output
810	}
811}
812
813impl<Address, Call, Signature, ExtensionV0, const MAX_CALL_SIZE: usize, ExtensionOtherVersions>
814	EncodeLike
815	for UncheckedExtrinsic<
816		Address,
817		Call,
818		Signature,
819		ExtensionV0,
820		ExtensionOtherVersions,
821		MAX_CALL_SIZE,
822	>
823where
824	Self: Encode,
825{
826}
827
828#[cfg(feature = "serde")]
829impl<Address, Signature, Call, ExtensionV0, const MAX_CALL_SIZE: usize, ExtensionOtherVersions>
830	serde::Serialize
831	for UncheckedExtrinsic<
832		Address,
833		Call,
834		Signature,
835		ExtensionV0,
836		ExtensionOtherVersions,
837		MAX_CALL_SIZE,
838	>
839where
840	Address: Encode,
841	Signature: Encode,
842	Call: Encode,
843	ExtensionV0: Encode,
844	ExtensionOtherVersions: Encode + PipelineVersion,
845{
846	fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error>
847	where
848		S: ::serde::Serializer,
849	{
850		self.using_encoded(|bytes| seq.serialize_bytes(bytes))
851	}
852}
853
854#[cfg(feature = "serde")]
855impl<
856		'a,
857		Address,
858		Signature,
859		Call,
860		ExtensionV0,
861		const MAX_CALL_SIZE: usize,
862		ExtensionOtherVersions,
863	> serde::Deserialize<'a>
864	for UncheckedExtrinsic<
865		Address,
866		Call,
867		Signature,
868		ExtensionV0,
869		ExtensionOtherVersions,
870		MAX_CALL_SIZE,
871	>
872where
873	Address: DecodeWithMemTracking,
874	Signature: DecodeWithMemTracking,
875	Call: DecodeWithMemTracking,
876	ExtensionV0: DecodeWithMemTracking,
877	ExtensionOtherVersions: DecodeWithVersionWithMemTracking,
878{
879	fn deserialize<D>(de: D) -> Result<Self, D::Error>
880	where
881		D: serde::Deserializer<'a>,
882	{
883		let r = sp_core::bytes::deserialize(de)?;
884		Self::decode(&mut &r[..])
885			.map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
886	}
887}
888
889/// Something which holds the actual call and maybe its encoded form.
890pub struct CallAndMaybeEncoded<T> {
891	encoded: Option<Vec<u8>>,
892	call: T,
893}
894
895impl<T> CallAndMaybeEncoded<T> {
896	/// Converts `self` into the underlying call.
897	pub fn into_call(self) -> T {
898		self.call
899	}
900}
901
902impl<T> From<T> for CallAndMaybeEncoded<T> {
903	fn from(value: T) -> Self {
904		Self { call: value, encoded: None }
905	}
906}
907
908impl<T: Encode> Encode for CallAndMaybeEncoded<T> {
909	fn encode_to<O: codec::Output + ?Sized>(&self, dest: &mut O) {
910		match &self.encoded {
911			Some(enc) => dest.write(enc),
912			None => self.call.encode_to(dest),
913		}
914	}
915
916	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
917		match &self.encoded {
918			Some(enc) => f(&enc),
919			None => self.call.using_encoded(f),
920		}
921	}
922}
923
924/// A payload that has been signed for an unchecked extrinsics.
925///
926/// Note that the payload that we sign to produce unchecked extrinsic signature
927/// is going to be different than the `SignaturePayload` - so the thing the extrinsic
928/// actually contains.
929pub struct SignedPayload<Call: Dispatchable, ExtensionV0: TransactionExtension<Call>>(
930	(CallAndMaybeEncoded<Call>, ExtensionV0, ExtensionV0::Implicit),
931);
932
933impl<Call, ExtensionV0> SignedPayload<Call, ExtensionV0>
934where
935	Call: Encode + Dispatchable,
936	ExtensionV0: TransactionExtension<Call>,
937{
938	/// Create new `SignedPayload` for extrinsic format version 4.
939	///
940	/// This function may fail if `implicit` of `ExtensionV0` is not available.
941	pub fn new(
942		call: impl Into<CallAndMaybeEncoded<Call>>,
943		tx_ext: ExtensionV0,
944	) -> Result<Self, TransactionValidityError> {
945		let implicit = ExtensionV0::implicit(&tx_ext)?;
946		Ok(Self((call.into(), tx_ext, implicit)))
947	}
948
949	/// Create new `SignedPayload` from raw components.
950	pub fn from_raw(
951		call: impl Into<CallAndMaybeEncoded<Call>>,
952		tx_ext: ExtensionV0,
953		implicit: ExtensionV0::Implicit,
954	) -> Self {
955		Self((call.into(), tx_ext, implicit))
956	}
957
958	/// Deconstruct the payload into it's components.
959	pub fn deconstruct(self) -> (Call, ExtensionV0, ExtensionV0::Implicit) {
960		let (call, ext, implicit) = self.0;
961		(call.call, ext, implicit)
962	}
963}
964
965impl<Call, ExtensionV0> Encode for SignedPayload<Call, ExtensionV0>
966where
967	Call: Encode + Dispatchable,
968	ExtensionV0: TransactionExtension<Call>,
969{
970	/// Get an encoded version of this `blake2_256`-hashed payload.
971	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
972		self.0.using_encoded(|payload| {
973			if payload.len() > 256 {
974				f(&blake2_256(payload)[..])
975			} else {
976				f(payload)
977			}
978		})
979	}
980}
981
982impl<Call, ExtensionV0> EncodeLike for SignedPayload<Call, ExtensionV0>
983where
984	Call: Encode + Dispatchable,
985	ExtensionV0: TransactionExtension<Call>,
986{
987}
988
989impl<Address, Call, Signature, ExtensionV0, const MAX_CALL_SIZE: usize, ExtensionOtherVersions>
990	From<
991		UncheckedExtrinsic<
992			Address,
993			Call,
994			Signature,
995			ExtensionV0,
996			ExtensionOtherVersions,
997			MAX_CALL_SIZE,
998		>,
999	> for OpaqueExtrinsic
1000where
1001	Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>: Encode,
1002	Call: Encode,
1003	ExtensionV0: Encode,
1004	ExtensionOtherVersions: Encode + PipelineVersion,
1005{
1006	fn from(
1007		extrinsic: UncheckedExtrinsic<
1008			Address,
1009			Call,
1010			Signature,
1011			ExtensionV0,
1012			ExtensionOtherVersions,
1013			MAX_CALL_SIZE,
1014		>,
1015	) -> Self {
1016		Self::from_blob(extrinsic.encode_without_prefix())
1017	}
1018}
1019
1020impl<Address, Call, Signature, ExtensionV0, ExtensionOtherVersions, const MAX_CALL_SIZE: usize>
1021	LazyExtrinsic
1022	for UncheckedExtrinsic<
1023		Address,
1024		Call,
1025		Signature,
1026		ExtensionV0,
1027		ExtensionOtherVersions,
1028		MAX_CALL_SIZE,
1029	>
1030where
1031	Preamble<Address, Signature, ExtensionV0, ExtensionOtherVersions>: DecodeWithMemTracking,
1032	Call: DecodeWithMemTracking,
1033	ExtensionV0: DecodeWithMemTracking,
1034	ExtensionOtherVersions: DecodeWithVersionWithMemTracking + PipelineVersion,
1035{
1036	fn decode_unprefixed(data: &[u8]) -> Result<Self, codec::Error> {
1037		Self::decode_with_len(&mut &data[..], data.len())
1038	}
1039}
1040
1041#[cfg(test)]
1042mod legacy {
1043	use codec::{Compact, Decode, Encode, EncodeLike, Error, Input};
1044	use scale_info::{
1045		build::Fields, meta_type, Path, StaticTypeInfo, Type, TypeInfo, TypeParameter,
1046	};
1047
1048	pub type UncheckedSignaturePayloadV4<Address, Signature, Extra> = (Address, Signature, Extra);
1049
1050	#[derive(PartialEq, Eq, Clone, Debug)]
1051	pub struct UncheckedExtrinsicV4<Address, Call, Signature, Extra> {
1052		pub signature: Option<UncheckedSignaturePayloadV4<Address, Signature, Extra>>,
1053		pub function: Call,
1054	}
1055
1056	impl<Address, Call, Signature, Extra> TypeInfo
1057		for UncheckedExtrinsicV4<Address, Call, Signature, Extra>
1058	where
1059		Address: StaticTypeInfo,
1060		Call: StaticTypeInfo,
1061		Signature: StaticTypeInfo,
1062		Extra: StaticTypeInfo,
1063	{
1064		type Identity = UncheckedExtrinsicV4<Address, Call, Signature, Extra>;
1065
1066		fn type_info() -> Type {
1067			Type::builder()
1068				.path(Path::new("UncheckedExtrinsic", module_path!()))
1069				// Include the type parameter types, even though they are not used directly in any
1070				// of the described fields. These type definitions can be used by downstream
1071				// consumers to help construct the custom decoding from the opaque bytes (see
1072				// below).
1073				.type_params(vec![
1074					TypeParameter::new("Address", Some(meta_type::<Address>())),
1075					TypeParameter::new("Call", Some(meta_type::<Call>())),
1076					TypeParameter::new("Signature", Some(meta_type::<Signature>())),
1077					TypeParameter::new("Extra", Some(meta_type::<Extra>())),
1078				])
1079				.docs(&["OldUncheckedExtrinsic raw bytes, requires custom decoding routine"])
1080				// Because of the custom encoding, we can only accurately describe the encoding as
1081				// an opaque `Vec<u8>`. Downstream consumers will need to manually implement the
1082				// codec to encode/decode the `signature` and `function` fields.
1083				.composite(Fields::unnamed().field(|f| f.ty::<Vec<u8>>()))
1084		}
1085	}
1086
1087	impl<Address, Call, Signature, Extra> UncheckedExtrinsicV4<Address, Call, Signature, Extra> {
1088		pub fn new_signed(
1089			function: Call,
1090			signed: Address,
1091			signature: Signature,
1092			extra: Extra,
1093		) -> Self {
1094			Self { signature: Some((signed, signature, extra)), function }
1095		}
1096
1097		pub fn new_unsigned(function: Call) -> Self {
1098			Self { signature: None, function }
1099		}
1100	}
1101
1102	impl<Address, Call, Signature, Extra> Decode
1103		for UncheckedExtrinsicV4<Address, Call, Signature, Extra>
1104	where
1105		Address: Decode,
1106		Signature: Decode,
1107		Call: Decode,
1108		Extra: Decode,
1109	{
1110		fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
1111			// This is a little more complicated than usual since the binary format must be
1112			// compatible with SCALE's generic `Vec<u8>` type. Basically this just means accepting
1113			// that there will be a prefix of vector length.
1114			let expected_length: Compact<u32> = Decode::decode(input)?;
1115			let before_length = input.remaining_len()?;
1116
1117			let version = input.read_byte()?;
1118
1119			let is_signed = version & 0b1000_0000 != 0;
1120			let version = version & 0b0111_1111;
1121			if version != 4u8 {
1122				return Err("Invalid transaction version".into());
1123			}
1124
1125			let signature = is_signed.then(|| Decode::decode(input)).transpose()?;
1126			let function = Decode::decode(input)?;
1127
1128			if let Some((before_length, after_length)) =
1129				input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a)))
1130			{
1131				let length = before_length.saturating_sub(after_length);
1132
1133				if length != expected_length.0 as usize {
1134					return Err("Invalid length prefix".into());
1135				}
1136			}
1137
1138			Ok(Self { signature, function })
1139		}
1140	}
1141
1142	#[docify::export(unchecked_extrinsic_encode_impl)]
1143	impl<Address, Call, Signature, Extra> Encode
1144		for UncheckedExtrinsicV4<Address, Call, Signature, Extra>
1145	where
1146		Address: Encode,
1147		Signature: Encode,
1148		Call: Encode,
1149		Extra: Encode,
1150	{
1151		fn encode(&self) -> Vec<u8> {
1152			let mut tmp = Vec::with_capacity(core::mem::size_of::<Self>());
1153
1154			// 1 byte version id.
1155			match self.signature.as_ref() {
1156				Some(s) => {
1157					tmp.push(4u8 | 0b1000_0000);
1158					s.encode_to(&mut tmp);
1159				},
1160				None => {
1161					tmp.push(4u8 & 0b0111_1111);
1162				},
1163			}
1164			self.function.encode_to(&mut tmp);
1165
1166			let compact_len = codec::Compact::<u32>(tmp.len() as u32);
1167
1168			// Allocate the output buffer with the correct length
1169			let mut output = Vec::with_capacity(compact_len.size_hint() + tmp.len());
1170
1171			compact_len.encode_to(&mut output);
1172			output.extend(tmp);
1173
1174			output
1175		}
1176	}
1177
1178	impl<Address, Call, Signature, Extra> EncodeLike
1179		for UncheckedExtrinsicV4<Address, Call, Signature, Extra>
1180	where
1181		Address: Encode,
1182		Signature: Encode,
1183		Call: Encode,
1184		Extra: Encode,
1185	{
1186	}
1187}
1188
1189#[cfg(test)]
1190mod tests {
1191	use super::{legacy::UncheckedExtrinsicV4, *};
1192	use crate::{
1193		codec::{Decode, Encode},
1194		impl_tx_ext_default,
1195		testing::TestSignature as TestSig,
1196		traits::{FakeDispatchable, IdentityLookup, TransactionExtension},
1197	};
1198	use sp_io::hashing::blake2_256;
1199
1200	type TestContext = IdentityLookup<u64>;
1201	type TestAccountId = u64;
1202
1203	// Custom Call enum that supports sorting on decode
1204	#[derive(Debug, Clone, Eq, PartialEq, Encode, TypeInfo)]
1205	enum Call {
1206		Raw(Vec<u8>),
1207		Sort(Vec<u8>),
1208	}
1209
1210	impl Decode for Call {
1211		fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
1212			let variant = input.read_byte()?;
1213			match variant {
1214				0 => {
1215					let data = Vec::<u8>::decode(input)?;
1216					Ok(Call::Raw(data))
1217				},
1218				1 => {
1219					let mut data = Vec::<u8>::decode(input)?;
1220					// Sort the data on decode
1221					data.sort();
1222					Ok(Call::Sort(data))
1223				},
1224				_ => Err("Invalid Call variant".into()),
1225			}
1226		}
1227	}
1228
1229	impl DecodeWithMemTracking for Call {}
1230
1231	impl From<Call> for Vec<u8> {
1232		fn from(call: Call) -> Vec<u8> {
1233			match call {
1234				Call::Sort(data) | Call::Raw(data) => data,
1235			}
1236		}
1237	}
1238
1239	impl From<Vec<u8>> for FakeDispatchable<Call> {
1240		fn from(value: Vec<u8>) -> Self {
1241			Self(Call::Raw(value))
1242		}
1243	}
1244
1245	type TestCall = FakeDispatchable<Call>;
1246
1247	const TEST_ACCOUNT: TestAccountId = 0;
1248
1249	// NOTE: this is demonstration. One can simply use `()` for testing.
1250	#[derive(
1251		Debug,
1252		Encode,
1253		Decode,
1254		DecodeWithMemTracking,
1255		Clone,
1256		Eq,
1257		PartialEq,
1258		Ord,
1259		PartialOrd,
1260		TypeInfo,
1261	)]
1262	struct DummyExtension;
1263	impl TransactionExtension<TestCall> for DummyExtension {
1264		const IDENTIFIER: &'static str = "DummyExtension";
1265		type Implicit = ();
1266		type Val = ();
1267		type Pre = ();
1268		impl_tx_ext_default!(TestCall; weight validate prepare);
1269	}
1270
1271	type Ex = UncheckedExtrinsic<TestAccountId, TestCall, TestSig, DummyExtension>;
1272	type CEx = CheckedExtrinsic<TestAccountId, TestCall, DummyExtension>;
1273
1274	#[test]
1275	fn unsigned_codec_should_work() {
1276		let call: TestCall = Call::Raw(vec![0u8; 0]).into();
1277		let ux = Ex::new_bare(call);
1278		let encoded = ux.encode();
1279		assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux));
1280	}
1281
1282	#[test]
1283	fn invalid_length_prefix_is_detected() {
1284		let ux = Ex::new_bare(Call::Raw(vec![0u8; 0]).into());
1285		let mut encoded = ux.encode();
1286
1287		let length = Compact::<u32>::decode(&mut &encoded[..]).unwrap();
1288		Compact(length.0 + 10).encode_to(&mut &mut encoded[..1]);
1289
1290		assert_eq!(Ex::decode(&mut &encoded[..]), Err("Invalid length prefix".into()));
1291	}
1292
1293	#[test]
1294	fn transaction_codec_should_work() {
1295		let ux = Ex::new_transaction(vec![0u8; 0].into(), DummyExtension);
1296		let encoded = ux.encode();
1297		assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux));
1298	}
1299
1300	#[test]
1301	fn signed_codec_should_work() {
1302		let ux = Ex::new_signed(
1303			vec![0u8; 0].into(),
1304			TEST_ACCOUNT,
1305			TestSig(TEST_ACCOUNT, (vec![0u8; 0], DummyExtension).encode()),
1306			DummyExtension,
1307		);
1308		let encoded = ux.encode();
1309		assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux));
1310	}
1311
1312	#[test]
1313	fn large_signed_codec_should_work() {
1314		let ux = Ex::new_signed(
1315			vec![0u8; 0].into(),
1316			TEST_ACCOUNT,
1317			TestSig(
1318				TEST_ACCOUNT,
1319				(vec![0u8; 257], DummyExtension).using_encoded(blake2_256)[..].to_owned(),
1320			),
1321			DummyExtension,
1322		);
1323		let encoded = ux.encode();
1324		assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux));
1325	}
1326
1327	#[test]
1328	fn unsigned_check_should_work() {
1329		let ux = Ex::new_bare(vec![0u8; 0].into());
1330		assert!(ux.is_inherent());
1331		assert_eq!(
1332			<Ex as Checkable<TestContext>>::check(ux, &Default::default()),
1333			Ok(CEx { format: ExtrinsicFormat::Bare, function: vec![0u8; 0].into() }),
1334		);
1335	}
1336
1337	#[test]
1338	fn badly_signed_check_should_fail() {
1339		let ux = Ex::new_signed(
1340			vec![0u8; 0].into(),
1341			TEST_ACCOUNT,
1342			TestSig(TEST_ACCOUNT, vec![0u8; 0].into()),
1343			DummyExtension,
1344		);
1345		assert!(!ux.is_inherent());
1346		assert_eq!(
1347			<Ex as Checkable<TestContext>>::check(ux, &Default::default()),
1348			Err(InvalidTransaction::BadProof.into()),
1349		);
1350	}
1351
1352	#[test]
1353	fn transaction_check_should_work() {
1354		let ux = Ex::new_transaction(vec![0u8; 0].into(), DummyExtension);
1355		assert!(!ux.is_inherent());
1356		assert_eq!(
1357			<Ex as Checkable<TestContext>>::check(ux, &Default::default()),
1358			Ok(CEx {
1359				format: ExtrinsicFormat::General(ExtensionVariant::V0(DummyExtension)),
1360				function: vec![0u8; 0].into()
1361			}),
1362		);
1363	}
1364
1365	#[test]
1366	fn signed_check_should_work() {
1367		let sig_payload = SignedPayload::from_raw(
1368			FakeDispatchable::from(vec![0u8; 0]),
1369			DummyExtension,
1370			DummyExtension.implicit().unwrap(),
1371		);
1372		let ux = Ex::new_signed(
1373			vec![0u8; 0].into(),
1374			TEST_ACCOUNT,
1375			TestSig(TEST_ACCOUNT, sig_payload.encode()),
1376			DummyExtension,
1377		);
1378		assert!(!ux.is_inherent());
1379		assert_eq!(
1380			<Ex as Checkable<TestContext>>::check(ux, &Default::default()),
1381			Ok(CEx {
1382				format: ExtrinsicFormat::Signed(TEST_ACCOUNT, DummyExtension),
1383				function: Call::Raw(vec![0u8; 0]).into()
1384			}),
1385		);
1386	}
1387
1388	#[test]
1389	fn large_signed_check_uses_blake2_256_hashed_payload() {
1390		// A 257-byte call ensures the encoded `(call, ext, implicit)` tuple is > 256 bytes,
1391		// triggering the blake2_256 hashing branch in both `SignedPayload::using_encoded`
1392		// (used to build the signature here) and `check` (which re-derives the same
1393		// payload). The two paths must produce the same bytes for `verify` to succeed.
1394		let large_call_data = vec![0u8; 257];
1395		let call: TestCall = large_call_data.clone().into();
1396		let sig_payload = SignedPayload::from_raw(
1397			call.clone(),
1398			DummyExtension,
1399			DummyExtension.implicit().unwrap(),
1400		);
1401
1402		// Sanity-check the test setup: the *raw* encoded tuple is > 256 bytes, but
1403		// `SignedPayload::encode()` returns the 32-byte blake2_256 hash.
1404		let raw_payload = (call.clone(), DummyExtension, ()).encode();
1405		assert!(raw_payload.len() > 256);
1406		let signed_bytes = sig_payload.encode();
1407		assert_eq!(signed_bytes.len(), 32);
1408		assert_eq!(signed_bytes, blake2_256(&raw_payload).to_vec());
1409
1410		let ux =
1411			Ex::new_signed(call, TEST_ACCOUNT, TestSig(TEST_ACCOUNT, signed_bytes), DummyExtension);
1412		assert!(!ux.is_inherent());
1413		assert_eq!(
1414			<Ex as Checkable<TestContext>>::check(ux, &Default::default()),
1415			Ok(CEx {
1416				format: ExtrinsicFormat::Signed(TEST_ACCOUNT, DummyExtension),
1417				function: Call::Raw(large_call_data).into(),
1418			}),
1419		);
1420	}
1421
1422	#[test]
1423	fn large_signed_check_fails_if_signed_over_unhashed_payload() {
1424		// If the signer (incorrectly) signs the *raw* > 256 byte payload instead of the
1425		// blake2_256 hash, `check` must reject it with `BadProof` because `check` always
1426		// hashes payloads that exceed 256 bytes.
1427		let large_call_data = vec![0u8; 257];
1428		let call: TestCall = large_call_data.into();
1429		let raw_payload = (call.clone(), DummyExtension, ()).encode();
1430		assert!(raw_payload.len() > 256);
1431
1432		let ux =
1433			Ex::new_signed(call, TEST_ACCOUNT, TestSig(TEST_ACCOUNT, raw_payload), DummyExtension);
1434		assert_eq!(
1435			<Ex as Checkable<TestContext>>::check(ux, &Default::default()),
1436			Err(InvalidTransaction::BadProof.into()),
1437		);
1438	}
1439
1440	#[test]
1441	fn encoding_matches_vec() {
1442		let ex = Ex::new_bare(Call::Raw(vec![0u8; 0]).into());
1443		let encoded = ex.encode();
1444		let decoded = Ex::decode(&mut encoded.as_slice()).unwrap();
1445		assert_eq!(decoded, ex);
1446		let as_vec: Vec<u8> = Decode::decode(&mut encoded.as_slice()).unwrap();
1447		assert_eq!(as_vec.encode(), encoded);
1448	}
1449
1450	#[test]
1451	fn conversion_to_opaque() {
1452		let ux = Ex::new_bare(Call::Raw(vec![0u8; 0]).into());
1453		let encoded = ux.encode();
1454		let opaque: OpaqueExtrinsic = ux.into();
1455		let opaque_encoded = opaque.encode();
1456		assert_eq!(opaque_encoded, encoded);
1457	}
1458
1459	#[test]
1460	fn large_bad_prefix_should_work() {
1461		let encoded = (Compact::<u32>::from(u32::MAX), Preamble::<(), (), ()>::Bare(0)).encode();
1462		assert!(Ex::decode(&mut &encoded[..]).is_err());
1463	}
1464
1465	#[test]
1466	fn legacy_short_signed_encode_decode() {
1467		let call: TestCall = Call::Raw(vec![0u8; 4]).into();
1468		let signed = TEST_ACCOUNT;
1469		let extension = DummyExtension;
1470		let implicit = extension.implicit().unwrap();
1471		let legacy_signature = TestSig(TEST_ACCOUNT, (&call, &extension, &implicit).encode());
1472
1473		let old_ux =
1474			UncheckedExtrinsicV4::<TestAccountId, TestCall, TestSig, DummyExtension>::new_signed(
1475				call.clone(),
1476				signed,
1477				legacy_signature.clone(),
1478				extension.clone(),
1479			);
1480
1481		let encoded_old_ux = old_ux.encode();
1482		let decoded_old_ux = Ex::decode(&mut &encoded_old_ux[..]).unwrap();
1483
1484		assert_eq!(decoded_old_ux.function, call);
1485		assert_eq!(
1486			decoded_old_ux.preamble,
1487			Preamble::Signed(signed, legacy_signature.clone(), extension.clone())
1488		);
1489
1490		let new_ux =
1491			Ex::new_signed(call.clone(), signed, legacy_signature.clone(), extension.clone());
1492
1493		let new_checked = new_ux.check(&IdentityLookup::<TestAccountId>::default()).unwrap();
1494		let old_checked =
1495			decoded_old_ux.check(&IdentityLookup::<TestAccountId>::default()).unwrap();
1496		assert_eq!(new_checked, old_checked);
1497	}
1498
1499	#[test]
1500	fn legacy_long_signed_encode_decode() {
1501		let call: TestCall = Call::Raw(vec![0u8; 257]).into();
1502		let signed = TEST_ACCOUNT;
1503		let extension = DummyExtension;
1504		let implicit = extension.implicit().unwrap();
1505		let signature = TestSig(
1506			TEST_ACCOUNT,
1507			blake2_256(&(&call, DummyExtension, &implicit).encode()[..]).to_vec(),
1508		);
1509
1510		let old_ux =
1511			UncheckedExtrinsicV4::<TestAccountId, TestCall, TestSig, DummyExtension>::new_signed(
1512				call.clone(),
1513				signed,
1514				signature.clone(),
1515				extension.clone(),
1516			);
1517
1518		let encoded_old_ux = old_ux.encode();
1519		let decoded_old_ux = Ex::decode(&mut &encoded_old_ux[..]).unwrap();
1520
1521		assert_eq!(decoded_old_ux.function, call);
1522		assert_eq!(
1523			decoded_old_ux.preamble,
1524			Preamble::Signed(signed, signature.clone(), extension.clone())
1525		);
1526
1527		let new_ux = Ex::new_signed(call.clone(), signed, signature.clone(), extension.clone());
1528
1529		let new_checked = new_ux.check(&IdentityLookup::<TestAccountId>::default()).unwrap();
1530		let old_checked =
1531			decoded_old_ux.check(&IdentityLookup::<TestAccountId>::default()).unwrap();
1532		assert_eq!(new_checked, old_checked);
1533	}
1534
1535	#[test]
1536	fn legacy_unsigned_encode_decode() {
1537		let call: TestCall = Call::Raw(vec![0u8; 0]).into();
1538
1539		let old_ux =
1540			UncheckedExtrinsicV4::<TestAccountId, TestCall, TestSig, DummyExtension>::new_unsigned(
1541				call.clone(),
1542			);
1543
1544		let encoded_old_ux = old_ux.encode();
1545		let decoded_old_ux = Ex::decode(&mut &encoded_old_ux[..]).unwrap();
1546
1547		assert_eq!(decoded_old_ux.function, call);
1548		assert_eq!(decoded_old_ux.preamble, Preamble::Bare(LEGACY_EXTRINSIC_FORMAT_VERSION));
1549
1550		let new_legacy_ux = Ex::new_bare_legacy(call.clone());
1551		assert_eq!(encoded_old_ux, new_legacy_ux.encode());
1552
1553		let new_ux = Ex::new_bare(call.clone());
1554		let encoded_new_ux = new_ux.encode();
1555		let decoded_new_ux = Ex::decode(&mut &encoded_new_ux[..]).unwrap();
1556		assert_eq!(new_ux, decoded_new_ux);
1557
1558		let new_checked = new_ux.check(&IdentityLookup::<TestAccountId>::default()).unwrap();
1559		let old_checked =
1560			decoded_old_ux.check(&IdentityLookup::<TestAccountId>::default()).unwrap();
1561		assert_eq!(new_checked, old_checked);
1562	}
1563
1564	#[test]
1565	fn max_call_heap_size_should_be_checked() {
1566		// Should be able to decode an `UncheckedExtrinsic` that contains a call with
1567		// heap size < `MAX_CALL_HEAP_SIZE`
1568		let ux = Ex::new_bare(Call::Raw(vec![0u8; DEFAULT_MAX_CALL_SIZE]).into());
1569		let encoded = ux.encode();
1570		assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux));
1571
1572		// Otherwise should fail
1573		let ux = Ex::new_bare(Call::Raw(vec![0u8; DEFAULT_MAX_CALL_SIZE + 1]).into());
1574		let encoded = ux.encode();
1575		assert_eq!(
1576			Ex::decode(&mut &encoded[..]).unwrap_err().to_string(),
1577			"Could not decode `FakeDispatchable.0`:\n\tHeap memory limit exceeded while decoding\n"
1578		);
1579	}
1580
1581	/// Ensures that a decoded extrinsic encodes to the exact same encoded bytes from what it was
1582	/// decoded from.
1583	#[test]
1584	fn encoding_is_stable() {
1585		// Create a call with unsorted data
1586		let unsorted_data = vec![5u8, 3, 7, 1, 9, 2, 8, 4, 6, 0];
1587		let call = Call::Sort(unsorted_data.clone());
1588
1589		let unsorted_encoded = call.encode();
1590
1591		let sig_payload = SignedPayload::from_raw(
1592			FakeDispatchable::from(call.clone()),
1593			DummyExtension,
1594			DummyExtension.implicit().unwrap(),
1595		);
1596		let sig_payload_encoded = sig_payload.encode();
1597
1598		let ux = Ex::new_signed(
1599			call.into(),
1600			TEST_ACCOUNT,
1601			TestSig(TEST_ACCOUNT, sig_payload_encoded.clone()),
1602			DummyExtension,
1603		);
1604
1605		// Encode and decode the extrinsic
1606		// During decode, the Sort variant will sort the data
1607		let encoded = ux.encode();
1608		let decoded_ux = Ex::decode(&mut &encoded[..]).unwrap();
1609
1610		// The decoded call should have sorted data
1611		let mut expected_sorted_data = unsorted_data;
1612		expected_sorted_data.sort();
1613
1614		let expected_decoded_call =
1615			FakeDispatchable::from(Call::Sort(expected_sorted_data.clone()));
1616		assert_eq!(decoded_ux.function, expected_decoded_call);
1617
1618		// Verify that the decoded call encodes differently than the original
1619		let sorted_encoded = Call::Sort(expected_sorted_data).encode();
1620		assert_ne!(
1621			unsorted_encoded, sorted_encoded,
1622			"Sorted and unsorted should encode differently"
1623		);
1624
1625		// Ensure that we can verify the signature successfully.
1626		assert_eq!(
1627			<Ex as Checkable<TestContext>>::check(decoded_ux, &Default::default())
1628				.unwrap()
1629				.function,
1630			expected_decoded_call,
1631		)
1632	}
1633}