referrerpolicy=no-referrer-when-downgrade

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