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