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