From b5c95b15aca5f8c241ffed2137aecdbc70cc6871 Mon Sep 17 00:00:00 2001 From: gui Date: Thu, 12 Dec 2024 20:04:58 +0900 Subject: [PATCH 01/56] WIP --- .../primitives/runtime/src/generic/unchecked_extrinsic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index d8510a60a7893..279235c8a2984 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -117,11 +117,11 @@ where let address = Address::decode(input)?; let signature = Signature::decode(input)?; let ext = Extension::decode(input)?; - Self::Signed(address, signature, ext) + Self::Signed(address, signature, ext) // TODO TODO: decode using version }, (EXTRINSIC_FORMAT_VERSION, GENERAL_EXTRINSIC) => { let ext_version = ExtensionVersion::decode(input)?; - let ext = Extension::decode(input)?; + let ext = Extension::decode(input)?; // TODO TODO: decode using version Self::General(ext_version, ext) }, (_, _) => return Err("Invalid transaction version".into()), From 582cbb95d45a81208ae56dd23ea50b92812ab3f1 Mon Sep 17 00:00:00 2001 From: gui Date: Sun, 15 Dec 2024 14:26:51 +0900 Subject: [PATCH 02/56] WIP --- .../src/generic/unchecked_extrinsic.rs | 76 ++++++++++++++++--- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 279235c8a2984..c04372faa7242 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -73,7 +73,7 @@ impl SignaturePaylo /// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and /// holds any necessary specialized data. #[derive(Eq, PartialEq, Clone)] -pub enum Preamble { +pub enum Preamble { /// An extrinsic without a signature or any extension. This means it's either an inherent or /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with /// the general transaction which is without a signature but does have an extension). @@ -83,7 +83,7 @@ pub enum Preamble { Bare(ExtrinsicVersion), /// An old-school transaction extrinsic which includes a signature of some hard-coded crypto. /// Available only on extrinsic version 4. - Signed(Address, Signature, Extension), + Signed(Address, Signature, ExtensionV0), /// A new-school transaction extrinsic which does not include a signature by default. The /// origin authorization, through signatures or other means, is performed by the transaction /// extension in this extrinsic. Available starting with extrinsic version 5. @@ -96,10 +96,11 @@ const BARE_EXTRINSIC: u8 = 0b0000_0000; const SIGNED_EXTRINSIC: u8 = 0b1000_0000; const GENERAL_EXTRINSIC: u8 = 0b0100_0000; -impl Decode for Preamble +impl Decode for Preamble where Address: Decode, Signature: Decode, + ExtensionV0: Decode, Extension: Decode, { fn decode(input: &mut I) -> Result { @@ -116,8 +117,8 @@ where (LEGACY_EXTRINSIC_FORMAT_VERSION, SIGNED_EXTRINSIC) => { let address = Address::decode(input)?; let signature = Signature::decode(input)?; - let ext = Extension::decode(input)?; - Self::Signed(address, signature, ext) // TODO TODO: decode using version + let ext = ExtensionV0::decode(input)?; + Self::Signed(address, signature, ext) }, (EXTRINSIC_FORMAT_VERSION, GENERAL_EXTRINSIC) => { let ext_version = ExtensionVersion::decode(input)?; @@ -131,10 +132,11 @@ where } } -impl Encode for Preamble +impl Encode for Preamble where Address: Encode, Signature: Encode, + ExtensionV0: Encode, Extension: Encode, { fn size_hint(&self) -> usize { @@ -172,9 +174,9 @@ where } } -impl Preamble { +impl Preamble { /// Returns `Some` if this is a signed extrinsic, together with the relevant inner fields. - pub fn to_signed(self) -> Option<(Address, Signature, Extension)> { + pub fn to_signed(self) -> Option<(Address, Signature, ExtensionV0)> { match self { Self::Signed(a, s, e) => Some((a, s, e)), _ => None, @@ -182,9 +184,10 @@ impl Preamble { } } -impl fmt::Debug for Preamble +impl fmt::Debug for Preamble where Address: fmt::Debug, + ExtensionV0: fmt::Debug, Extension: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -228,6 +231,9 @@ pub struct UncheckedExtrinsic { pub function: Call, } +// TODO TODO: 2 possible implementation: +// 1. a new generic for the multi version extension. +// 2. no new generic, the multi version extension defines what is ExtensionV0. /// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded /// `Vec`, but requires some logic to extract the signature and payload. /// @@ -306,14 +312,18 @@ impl UncheckedExtrinsic Self { Self { preamble: Preamble::Signed(signed, signature, tx_ext), function } } +} +impl> UncheckedExtrinsic { /// New instance of an new-school unsigned transaction. + /// + /// This function is only available for `UncheckedExtrinsic` without multi version extension. pub fn new_transaction(function: Call, tx_ext: Extension) -> Self { Self { preamble: Preamble::General(EXTENSION_VERSION, tx_ext), function } } } -impl ExtrinsicLike +impl ExtrinsicLike for UncheckedExtrinsic { fn is_bare(&self) -> bool { @@ -406,6 +416,52 @@ impl; +// type TxExt = MultiVersionExtension<( +// ExtensionV1, +// ExtensionV2, +// )>; + +// // usage prop 2 +// type TxExtV1 = (CheckNonce, CheckNonce); +// type TxExt = MultiVersionExtension<( +// VersionedExtension<1, TxExtV1>, +// VersionedExtension<2, TxExtV2>, +// )>; +// +// OR +// +// type TxExtV1 = (1, (CheckNonce, CheckNonce)); +// type TxExt = MultiVersionExtension<( +// ExtensionV1, +// ExtensionV2, +// )>; + +// // usage prop 2 +// type TxExtV1 = (CheckNonce, CheckNonce); +// type TxExt = MultiVersionExtension<( +// (1, TxExtV1), +// (2, TxExtV2), +// )>; + + +impl Decode + for UncheckedExtrinsic +where + Address: Decode, + Signature: Decode, + Call: Decode, +{ + fn decode(input: &mut I) -> Result { + todo!(); + } +} + +// TODO TODO: here we want to decode differently based on the type `Extension`. +// If extension is MultiVersionExtension then we want to decode with a specific trait impl. impl Decode for UncheckedExtrinsic where From 32159f9657d6af5edff5bf42b8518a5361aa341f Mon Sep 17 00:00:00 2001 From: gui Date: Sun, 15 Dec 2024 22:51:31 +0900 Subject: [PATCH 03/56] WIP --- .../runtime/src/generic/checked_extrinsic.rs | 62 +++-- .../src/generic/unchecked_extrinsic.rs | 231 +++++++++++------- .../dispatch_transaction.rs | 1 + .../src/traits/transaction_extension/mod.rs | 86 ++++++- 4 files changed, 264 insertions(+), 116 deletions(-) diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 1842b1631621a..5c249d0da3229 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -21,17 +21,19 @@ use codec::Encode; use sp_weights::Weight; +use super::unchecked_extrinsic::ExtensionVersion; use crate::{ traits::{ - self, transaction_extension::TransactionExtension, AsTransactionAuthorizedOrigin, - DispatchInfoOf, DispatchTransaction, Dispatchable, MaybeDisplay, Member, - PostDispatchInfoOf, ValidateUnsigned, + self, + transaction_extension::{ + NotVersionedExtension, TransactionExtension, VersionedTransactionExtensionPipeline, + }, + AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, + MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned, }, transaction_validity::{TransactionSource, TransactionValidity}, }; -use super::unchecked_extrinsic::ExtensionVersion; - /// Default version of the [Extension](TransactionExtension) used to construct the inherited /// implication for legacy transactions. const DEFAULT_EXTENSION_VERSION: ExtensionVersion = 0; @@ -39,13 +41,13 @@ const DEFAULT_EXTENSION_VERSION: ExtensionVersion = 0; /// The kind of extrinsic this is, including any fields required of that kind. This is basically /// the full extrinsic except the `Call`. #[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] -pub enum ExtrinsicFormat { +pub enum ExtrinsicFormat { /// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or /// `ValidateUnsigned`, both deprecated, or alternatively a `ProvideInherent`. Bare, /// Extrinsic has a default `Origin` of `Signed(AccountId)` and must pass all /// `TransactionExtension`s regular checks and includes all extension data. - Signed(AccountId, Extension), + Signed(AccountId, ExtensionV0), /// Extrinsic has a default `Origin` of `None` and must pass all `TransactionExtension`s. /// regular checks and includes all extension data. General(ExtensionVersion, Extension), @@ -57,21 +59,27 @@ pub enum ExtrinsicFormat { /// This is typically passed into [`traits::Applyable::apply`], which should execute /// [`CheckedExtrinsic::function`], alongside all other bits and bobs. #[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] -pub struct CheckedExtrinsic { +pub struct CheckedExtrinsic< + AccountId, + Call, + ExtensionV0, + Extension = NotVersionedExtension, +> { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). - pub format: ExtrinsicFormat, + pub format: ExtrinsicFormat, /// The function that should be called. pub function: Call, } -impl traits::Applyable - for CheckedExtrinsic +impl traits::Applyable + for CheckedExtrinsic where AccountId: Member + MaybeDisplay, Call: Member + Dispatchable + Encode, - Extension: TransactionExtension, + ExtensionV0: TransactionExtension, + Extension: VersionedTransactionExtensionPipeline, RuntimeOrigin: From> + AsTransactionAuthorizedOrigin, { type Call = Call; @@ -86,7 +94,7 @@ where ExtrinsicFormat::Bare => { let inherent_validation = I::validate_unsigned(source, &self.function)?; #[allow(deprecated)] - let legacy_validation = Extension::bare_validate(&self.function, info, len)?; + let legacy_validation = ExtensionV0::bare_validate(&self.function, info, len)?; Ok(legacy_validation.combine_with(inherent_validation)) }, ExtrinsicFormat::Signed(ref signer, ref extension) => { @@ -102,9 +110,9 @@ where ) .map(|x| x.0) }, - ExtrinsicFormat::General(extension_version, ref extension) => extension - .validate_only(None.into(), &self.function, info, len, source, extension_version) - .map(|x| x.0), + ExtrinsicFormat::General(_extension_version, ref extension) => extension + .validate_only(None.into(), &self.function, info, len, source) // TODO TODO: needs validate + , } } @@ -118,13 +126,13 @@ where I::pre_dispatch(&self.function)?; // TODO: Separate logic from `TransactionExtension` into a new `InherentExtension` // interface. - Extension::bare_validate_and_prepare(&self.function, info, len)?; + ExtensionV0::bare_validate_and_prepare(&self.function, info, len)?; let res = self.function.dispatch(None.into()); let mut post_info = res.unwrap_or_else(|err| err.post_info); let pd_res = res.map(|_| ()).map_err(|e| e.error); // TODO: Separate logic from `TransactionExtension` into a new `InherentExtension` // interface. - Extension::bare_post_dispatch(info, &mut post_info, len, &pd_res)?; + ExtensionV0::bare_post_dispatch(info, &mut post_info, len, &pd_res)?; Ok(res) }, ExtrinsicFormat::Signed(signer, extension) => extension.dispatch_transaction( @@ -134,22 +142,28 @@ where len, DEFAULT_EXTENSION_VERSION, ), - ExtrinsicFormat::General(extension_version, extension) => extension - .dispatch_transaction(None.into(), self.function, info, len, extension_version), + ExtrinsicFormat::General(_extension_version, extension) => + extension.dispatch_transaction(None.into(), self.function, info, len), /* TODO TODO: + * needs dispatch */ } } } -impl> - CheckedExtrinsic +impl< + AccountId, + Call: Dispatchable, + ExtensionV0: TransactionExtension, + Extension: VersionedTransactionExtensionPipeline, + > CheckedExtrinsic { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. pub fn extension_weight(&self) -> Weight { match &self.format { ExtrinsicFormat::Bare => Weight::zero(), - ExtrinsicFormat::Signed(_, ext) | ExtrinsicFormat::General(_, ext) => - ext.weight(&self.function), + ExtrinsicFormat::Signed(_, ext) => ext.weight(&self.function), + ExtrinsicFormat::General(_, ext) => ext.weight(&self.function), /* TODO TODO: needs + * weight */ } } } diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index c04372faa7242..f8bc2ba883824 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -20,8 +20,13 @@ use crate::{ generic::{CheckedExtrinsic, ExtrinsicFormat}, traits::{ - self, transaction_extension::TransactionExtension, Checkable, Dispatchable, ExtrinsicLike, - ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, SignaturePayload, + self, + transaction_extension::{ + DecodeWithVersion, NotVersionedExtension, TransactionExtension, + VersionedTransactionExtensionPipeline, + }, + Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, + Member, SignaturePayload, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, @@ -73,7 +78,7 @@ impl SignaturePaylo /// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and /// holds any necessary specialized data. #[derive(Eq, PartialEq, Clone)] -pub enum Preamble { +pub enum Preamble> { /// An extrinsic without a signature or any extension. This means it's either an inherent or /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with /// the general transaction which is without a signature but does have an extension). @@ -96,12 +101,13 @@ const BARE_EXTRINSIC: u8 = 0b0000_0000; const SIGNED_EXTRINSIC: u8 = 0b1000_0000; const GENERAL_EXTRINSIC: u8 = 0b0100_0000; -impl Decode for Preamble +impl Decode + for Preamble where Address: Decode, Signature: Decode, ExtensionV0: Decode, - Extension: Decode, + Extension: DecodeWithVersion, { fn decode(input: &mut I) -> Result { let version_and_type = input.read_byte()?; @@ -122,7 +128,7 @@ where }, (EXTRINSIC_FORMAT_VERSION, GENERAL_EXTRINSIC) => { let ext_version = ExtensionVersion::decode(input)?; - let ext = Extension::decode(input)?; // TODO TODO: decode using version + let ext = Extension::decode_with_version(ext_version, input)?; Self::General(ext_version, ext) }, (_, _) => return Err("Invalid transaction version".into()), @@ -132,7 +138,8 @@ where } } -impl Encode for Preamble +impl Encode + for Preamble where Address: Encode, Signature: Encode, @@ -174,7 +181,9 @@ where } } -impl Preamble { +impl + Preamble +{ /// Returns `Some` if this is a signed extrinsic, together with the relevant inner fields. pub fn to_signed(self) -> Option<(Address, Signature, ExtensionV0)> { match self { @@ -184,7 +193,8 @@ impl Preamble fmt::Debug for Preamble +impl fmt::Debug + for Preamble where Address: fmt::Debug, ExtensionV0: fmt::Debug, @@ -223,10 +233,16 @@ where /// counterpart of this type after its signature (and other non-negotiable validity checks) have /// passed. #[derive(PartialEq, Eq, Clone, Debug)] -pub struct UncheckedExtrinsic { +pub struct UncheckedExtrinsic< + Address, + Call, + Signature, + ExtensionV0, + Extension = NotVersionedExtension, +> { /// Information regarding the type of extrinsic this is (inherent or transaction) as well as /// associated extension (`Extension`) data if it's a transaction and a possible signature. - pub preamble: Preamble, + pub preamble: Preamble, /// The function that should be called. pub function: Call, } @@ -238,12 +254,13 @@ pub struct UncheckedExtrinsic { /// `Vec`, but requires some logic to extract the signature and payload. /// /// See [`UncheckedExtrinsic::encode`] and [`UncheckedExtrinsic::decode`]. -impl TypeInfo - for UncheckedExtrinsic +impl TypeInfo + for UncheckedExtrinsic where Address: StaticTypeInfo, Call: StaticTypeInfo, Signature: StaticTypeInfo, + ExtensionV0: StaticTypeInfo, Extension: StaticTypeInfo, { type Identity = UncheckedExtrinsic; @@ -258,7 +275,8 @@ where TypeParameter::new("Address", Some(meta_type::
())), TypeParameter::new("Call", Some(meta_type::())), TypeParameter::new("Signature", Some(meta_type::())), - TypeParameter::new("Extra", Some(meta_type::())), + TypeParameter::new("Extra", Some(meta_type::())), + TypeParameter::new("GeneralExtra", Some(meta_type::())), ]) .docs(&["UncheckedExtrinsic raw bytes, requires custom decoding routine"]) // Because of the custom encoding, we can only accurately describe the encoding as an @@ -268,7 +286,9 @@ where } } -impl UncheckedExtrinsic { +impl + UncheckedExtrinsic +{ /// New instance of a bare (ne unsigned) extrinsic. This could be used for an inherent or an /// old-school "unsigned transaction" (which are new being deprecated in favour of general /// transactions). @@ -289,7 +309,10 @@ impl UncheckedExtrinsic) -> Self { + pub fn from_parts( + function: Call, + preamble: Preamble, + ) -> Self { Self { preamble, function } } @@ -308,23 +331,28 @@ impl UncheckedExtrinsic Self { Self { preamble: Preamble::Signed(signed, signature, tx_ext), function } } } -impl> UncheckedExtrinsic { +impl + UncheckedExtrinsic +{ /// New instance of an new-school unsigned transaction. /// /// This function is only available for `UncheckedExtrinsic` without multi version extension. pub fn new_transaction(function: Call, tx_ext: Extension) -> Self { - Self { preamble: Preamble::General(EXTENSION_VERSION, tx_ext), function } + Self { + preamble: Preamble::General(EXTENSION_VERSION, NotVersionedExtension(tx_ext)), + function, + } } } -impl ExtrinsicLike - for UncheckedExtrinsic +impl ExtrinsicLike + for UncheckedExtrinsic { fn is_bare(&self) -> bool { matches!(self.preamble, Preamble::Bare(_)) @@ -339,18 +367,18 @@ impl ExtrinsicLike // transactions by adding an extension to validate signatures, as they are currently validated in // the `Checkable` implementation for `Signed` transactions. -impl Checkable - for UncheckedExtrinsic +impl Checkable + for UncheckedExtrinsic where LookupSource: Member + MaybeDisplay, Call: Encode + Member + Dispatchable, Signature: Member + traits::Verify, ::Signer: IdentifyAccount, - Extension: Encode + TransactionExtension, + ExtensionV0: Encode + TransactionExtension, AccountId: Member + MaybeDisplay, Lookup: traits::Lookup, { - type Checked = CheckedExtrinsic; + type Checked = CheckedExtrinsic; fn check(self, lookup: &Lookup) -> Result { Ok(match self.preamble { @@ -396,6 +424,7 @@ where } } +// TODO TODO impl> ExtrinsicMetadata for UncheckedExtrinsic { @@ -403,21 +432,26 @@ impl> - UncheckedExtrinsic +impl< + Address, + Call: Dispatchable, + Signature, + ExtensionV0: TransactionExtension, + Extension: VersionedTransactionExtensionPipeline, + > UncheckedExtrinsic { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. pub fn extension_weight(&self) -> Weight { match &self.preamble { Preamble::Bare(_) => Weight::zero(), - Preamble::Signed(_, _, ext) | Preamble::General(_, ext) => ext.weight(&self.function), + Preamble::Signed(_, _, ext) => ext.weight(&self.function), + Preamble::General(_, ext) => ext.weight(&self.function), /* TODO TODO: needs weight + * function */ } } } -pub struct MultiVersionExtension; - // // usage prop 1 // type TxExtV1 = VersionedExtension<1, (CheckNonce, CheckNonce)>; // type TxExt = MultiVersionExtension<( @@ -425,12 +459,15 @@ pub struct MultiVersionExtension; // ExtensionV2, // )>; -// // usage prop 2 +// usage prop 2 // type TxExtV1 = (CheckNonce, CheckNonce); -// type TxExt = MultiVersionExtension<( -// VersionedExtension<1, TxExtV1>, -// VersionedExtension<2, TxExtV2>, -// )>; +// type TxExt = MultiVersionExtension< +// 1, +// ( +// VersionedExtension<1, TxExtV1>, +// VersionedExtension<2, TxExtV2>, +// ) +// >; // // OR // @@ -442,33 +479,46 @@ pub struct MultiVersionExtension; // // usage prop 2 // type TxExtV1 = (CheckNonce, CheckNonce); -// type TxExt = MultiVersionExtension<( -// (1, TxExtV1), -// (2, TxExtV2), -// )>; - - -impl Decode - for UncheckedExtrinsic -where - Address: Decode, - Signature: Decode, - Call: Decode, -{ - fn decode(input: &mut I) -> Result { - todo!(); - } -} - -// TODO TODO: here we want to decode differently based on the type `Extension`. -// If extension is MultiVersionExtension then we want to decode with a specific trait impl. -impl Decode - for UncheckedExtrinsic +// type TxExt = MultiVersionExtension< +// ( +// (1, TxExtV1), +// (2, TxExtV2), +// ) +// >; +// type UncheckedExtrinsic = UncheckedExtrinsic; +// +// // usage prop 2 +// type TxExtV1 = (CheckNonce, CheckNonce); +// type TxExt = MultiVersionExtension< +// ( +// (1, TxExtV1), +// (2, TxExtV2), +// ) +// >; +// type UncheckedExtrinsic = UncheckedExtrinsic; + +// impl Decode +// for UncheckedExtrinsic +// where +// Address: Decode, +// Signature: Decode, +// Call: Decode, +// { +// fn decode(input: &mut I) -> Result { +// todo!(); +// } +// } + +impl Decode + for UncheckedExtrinsic where Address: Decode, Signature: Decode, Call: Decode, - Extension: Decode, + ExtensionV0: Decode, + Extension: DecodeWithVersion, { fn decode(input: &mut I) -> Result { // This is a little more complicated than usual since the binary format must be compatible @@ -495,11 +545,12 @@ where } #[docify::export(unchecked_extrinsic_encode_impl)] -impl Encode - for UncheckedExtrinsic +impl Encode + for UncheckedExtrinsic where - Preamble: Encode, + Preamble: Encode, Call: Encode, + ExtensionV0: Encode, Extension: Encode, { fn encode(&self) -> Vec { @@ -518,19 +569,16 @@ where } } -impl EncodeLike - for UncheckedExtrinsic +impl EncodeLike + for UncheckedExtrinsic where - Address: Encode, - Signature: Encode, - Call: Encode + Dispatchable, - Extension: TransactionExtension, + Self: Encode, { } #[cfg(feature = "serde")] -impl serde::Serialize - for UncheckedExtrinsic +impl + serde::Serialize for UncheckedExtrinsic { fn serialize(&self, seq: S) -> Result where @@ -541,8 +589,14 @@ impl serde: } #[cfg(feature = "serde")] -impl<'a, Address: Decode, Signature: Decode, Call: Decode, Extension: Decode> serde::Deserialize<'a> - for UncheckedExtrinsic +impl< + 'a, + Address: Decode, + Signature: Decode, + Call: Decode, + ExtensionV0: Decode, + Extension: DecodeWithVersion, + > serde::Deserialize<'a> for UncheckedExtrinsic { fn deserialize(de: D) -> Result where @@ -559,39 +613,39 @@ impl<'a, Address: Decode, Signature: Decode, Call: Decode, Extension: Decode> se /// Note that the payload that we sign to produce unchecked extrinsic signature /// is going to be different than the `SignaturePayload` - so the thing the extrinsic /// actually contains. -pub struct SignedPayload>( - (Call, Extension, Extension::Implicit), +pub struct SignedPayload>( + (Call, ExtensionV0, ExtensionV0::Implicit), ); -impl SignedPayload +impl SignedPayload where Call: Encode + Dispatchable, - Extension: TransactionExtension, + ExtensionV0: TransactionExtension, { /// Create new `SignedPayload` for extrinsic format version 4. /// - /// This function may fail if `implicit` of `Extension` is not available. - pub fn new(call: Call, tx_ext: Extension) -> Result { - let implicit = Extension::implicit(&tx_ext)?; + /// This function may fail if `implicit` of `ExtensionV0` is not available. + pub fn new(call: Call, tx_ext: ExtensionV0) -> Result { + let implicit = ExtensionV0::implicit(&tx_ext)?; let raw_payload = (call, tx_ext, implicit); Ok(Self(raw_payload)) } /// Create new `SignedPayload` from raw components. - pub fn from_raw(call: Call, tx_ext: Extension, implicit: Extension::Implicit) -> Self { + pub fn from_raw(call: Call, tx_ext: ExtensionV0, implicit: ExtensionV0::Implicit) -> Self { Self((call, tx_ext, implicit)) } /// Deconstruct the payload into it's components. - pub fn deconstruct(self) -> (Call, Extension, Extension::Implicit) { + pub fn deconstruct(self) -> (Call, ExtensionV0, ExtensionV0::Implicit) { self.0 } } -impl Encode for SignedPayload +impl Encode for SignedPayload where Call: Encode + Dispatchable, - Extension: TransactionExtension, + ExtensionV0: TransactionExtension, { /// Get an encoded version of this `blake2_256`-hashed payload. fn using_encoded R>(&self, f: F) -> R { @@ -605,22 +659,25 @@ where } } -impl EncodeLike for SignedPayload +impl EncodeLike for SignedPayload where Call: Encode + Dispatchable, - Extension: TransactionExtension, + ExtensionV0: TransactionExtension, { } -impl - From> for OpaqueExtrinsic +impl + From> for OpaqueExtrinsic where Address: Encode, Signature: Encode, Call: Encode, + ExtensionV0: Encode, Extension: Encode, { - fn from(extrinsic: UncheckedExtrinsic) -> Self { + fn from( + extrinsic: UncheckedExtrinsic, + ) -> Self { Self::from_bytes(extrinsic.encode().as_slice()).expect( "both OpaqueExtrinsic and UncheckedExtrinsic have encoding that is compatible with \ raw Vec encoding; qed", diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs index 28030d12fc9f3..82f7e3522b62f 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs @@ -29,6 +29,7 @@ use super::*; /// provide transaction dispatching functionality. We avoid implementing this directly on the trait /// since we never want it to be overriden by the trait implementation. pub trait DispatchTransaction { + // TODO TODO: remove some redundant types here /// The origin type of the transaction. type Origin; /// The info type. diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index f8c5dc6a724eb..936d7521bd3f8 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -17,8 +17,13 @@ //! The transaction extension trait. +use super::{ + DispatchInfoOf, DispatchOriginOf, Dispatchable, ExtensionPostDispatchWeightHandler, + PostDispatchInfoOf, RefundWeight, +}; use crate::{ scale_info::{MetaType, StaticTypeInfo}, + traits::AsTransactionAuthorizedOrigin, transaction_validity::{ TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, }, @@ -26,23 +31,94 @@ use crate::{ }; use codec::{Codec, Decode, Encode}; use impl_trait_for_tuples::impl_for_tuples; +use scale_info::TypeInfo; #[doc(hidden)] pub use sp_std::marker::PhantomData; use sp_std::{self, fmt::Debug, prelude::*}; use sp_weights::Weight; use tuplex::{PopFront, PushBack}; -use super::{ - DispatchInfoOf, DispatchOriginOf, Dispatchable, ExtensionPostDispatchWeightHandler, - PostDispatchInfoOf, RefundWeight, -}; - mod as_transaction_extension; mod dispatch_transaction; #[allow(deprecated)] pub use as_transaction_extension::AsTransactionExtension; pub use dispatch_transaction::DispatchTransaction; +/// TODO TODO: doc +pub trait DecodeWithVersion: Sized { + /// TODO TODO: doc + fn decode_with_version( + extension_version: u8, + input: &mut I, + ) -> Result; +} + +/// TODO TODO: doc +// TODO TODO: or maybe name it DispatchTransactionWithExtensionVersion +pub trait VersionedTransactionExtensionPipeline: + Encode + DecodeWithVersion + Debug + StaticTypeInfo + Send + Sync + Clone +{ + /// TODO TODO: doc + fn validate_only( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result; + + /// TODO TODO: doc + fn dispatch_transaction( + self, + origin: DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo>; + /// TODO TODO: doc + fn weight(&self, call: &Call) -> Weight; +} + +/// TODO TODO: doc +#[derive(Encode, Decode, Clone, Debug, TypeInfo)] +pub struct NotVersionedExtension(pub Extension); + +impl< + Call: Dispatchable + Encode, + Extension: TransactionExtension, + > VersionedTransactionExtensionPipeline for NotVersionedExtension +{ + fn weight(&self, call: &Call) -> Weight { + self.0.weight(call) + } + fn validate_only( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result { + self.0.validate_only(origin, call, info, len, source, 0).map(|x| x.0) + } + fn dispatch_transaction( + self, + origin: DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + self.0.dispatch_transaction(origin, call, info, len, 0) + } +} + +impl DecodeWithVersion for NotVersionedExtension { + fn decode_with_version(_: u8, input: &mut I) -> Result { + Self::decode(input) + } +} + /// Shortcut for the result value of the `validate` function. pub type ValidateResult = Result<(ValidTransaction, Val, DispatchOriginOf), TransactionValidityError>; From 2350e93dbc43d3501449757e0ae95aa6438183c7 Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 16 Dec 2024 10:47:23 +0900 Subject: [PATCH 04/56] WIP --- .../src/traits/transaction_extension/mod.rs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index 936d7521bd3f8..686a1f1b1770f 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -81,6 +81,8 @@ pub trait VersionedTransactionExtensionPipeline: } /// TODO TODO: doc +// TODO TODO: maybe rename to version0 or something +// TODO TODO: maybe replace with type alias for VersionedExtension<0, Extension> #[derive(Encode, Decode, Clone, Debug, TypeInfo)] pub struct NotVersionedExtension(pub Extension); @@ -119,6 +121,55 @@ impl DecodeWithVersion for NotVersionedExtension { } } +/// TODO TODO: doc +#[derive(Encode, Clone, Debug, TypeInfo)] +pub struct VersionedExtension { + extension: Extension, +} + +impl DecodeWithVersion for VersionedExtension { + fn decode_with_version( + extension_version: u8, + input: &mut I, + ) -> Result { + if extension_version == VERSION { + Ok(VersionedExtension { + extension: Extension::decode(input)?, + }) + } else { + Err(codec::Error::from("Invalid extension version")) + } + } +} + +impl + Encode, + Extension: TransactionExtension, + > VersionedTransactionExtensionPipeline for VersionedExtension +{ + fn weight(&self, call: &Call) -> Weight { + self.extension.weight(call) + } + fn validate_only( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result { + self.extension.validate_only(origin, call, info, len, source, VERSION).map(|x| x.0) + } + fn dispatch_transaction( + self, + origin: DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + self.extension.dispatch_transaction(origin, call, info, len, VERSION) + } +} + /// Shortcut for the result value of the `validate` function. pub type ValidateResult = Result<(ValidTransaction, Val, DispatchOriginOf), TransactionValidityError>; From 143b50a5310c54c6785ccb5258b2b77339ab70e3 Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 16 Dec 2024 18:29:42 +0900 Subject: [PATCH 05/56] WIP --- .../runtime/src/generic/checked_extrinsic.rs | 28 +-- .../src/generic/unchecked_extrinsic.rs | 145 +++++++------ .../src/traits/transaction_extension/mod.rs | 195 ++++++++++++++---- 3 files changed, 250 insertions(+), 118 deletions(-) diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 5c249d0da3229..e2fa8697d29dd 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -26,7 +26,7 @@ use crate::{ traits::{ self, transaction_extension::{ - NotVersionedExtension, TransactionExtension, VersionedTransactionExtensionPipeline, + TransactionExtension, VersionedExtension, VersionedTransactionExtensionPipeline, }, AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned, @@ -41,13 +41,13 @@ const DEFAULT_EXTENSION_VERSION: ExtensionVersion = 0; /// The kind of extrinsic this is, including any fields required of that kind. This is basically /// the full extrinsic except the `Call`. #[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] -pub enum ExtrinsicFormat { +pub enum ExtrinsicFormat { /// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or /// `ValidateUnsigned`, both deprecated, or alternatively a `ProvideInherent`. Bare, /// Extrinsic has a default `Origin` of `Signed(AccountId)` and must pass all /// `TransactionExtension`s regular checks and includes all extension data. - Signed(AccountId, ExtensionV0), + Signed(AccountId, BaseExtension), /// Extrinsic has a default `Origin` of `None` and must pass all `TransactionExtension`s. /// regular checks and includes all extension data. General(ExtensionVersion, Extension), @@ -62,23 +62,23 @@ pub enum ExtrinsicFormat { pub struct CheckedExtrinsic< AccountId, Call, - ExtensionV0, - Extension = NotVersionedExtension, + BaseExtension, + Extension = VersionedExtension<0, BaseExtension>, > { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). - pub format: ExtrinsicFormat, + pub format: ExtrinsicFormat, /// The function that should be called. pub function: Call, } -impl traits::Applyable - for CheckedExtrinsic +impl traits::Applyable + for CheckedExtrinsic where AccountId: Member + MaybeDisplay, Call: Member + Dispatchable + Encode, - ExtensionV0: TransactionExtension, + BaseExtension: TransactionExtension, Extension: VersionedTransactionExtensionPipeline, RuntimeOrigin: From> + AsTransactionAuthorizedOrigin, { @@ -94,7 +94,7 @@ where ExtrinsicFormat::Bare => { let inherent_validation = I::validate_unsigned(source, &self.function)?; #[allow(deprecated)] - let legacy_validation = ExtensionV0::bare_validate(&self.function, info, len)?; + let legacy_validation = BaseExtension::bare_validate(&self.function, info, len)?; Ok(legacy_validation.combine_with(inherent_validation)) }, ExtrinsicFormat::Signed(ref signer, ref extension) => { @@ -126,13 +126,13 @@ where I::pre_dispatch(&self.function)?; // TODO: Separate logic from `TransactionExtension` into a new `InherentExtension` // interface. - ExtensionV0::bare_validate_and_prepare(&self.function, info, len)?; + BaseExtension::bare_validate_and_prepare(&self.function, info, len)?; let res = self.function.dispatch(None.into()); let mut post_info = res.unwrap_or_else(|err| err.post_info); let pd_res = res.map(|_| ()).map_err(|e| e.error); // TODO: Separate logic from `TransactionExtension` into a new `InherentExtension` // interface. - ExtensionV0::bare_post_dispatch(info, &mut post_info, len, &pd_res)?; + BaseExtension::bare_post_dispatch(info, &mut post_info, len, &pd_res)?; Ok(res) }, ExtrinsicFormat::Signed(signer, extension) => extension.dispatch_transaction( @@ -152,9 +152,9 @@ where impl< AccountId, Call: Dispatchable, - ExtensionV0: TransactionExtension, + BaseExtension: TransactionExtension, Extension: VersionedTransactionExtensionPipeline, - > CheckedExtrinsic + > CheckedExtrinsic { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index f8bc2ba883824..b2a4e006d759b 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -22,7 +22,7 @@ use crate::{ traits::{ self, transaction_extension::{ - DecodeWithVersion, NotVersionedExtension, TransactionExtension, + DecodeWithVersion, TransactionExtension, VersionedExtension, VersionedTransactionExtensionPipeline, }, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, @@ -78,7 +78,12 @@ impl SignaturePaylo /// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and /// holds any necessary specialized data. #[derive(Eq, PartialEq, Clone)] -pub enum Preamble> { +pub enum Preamble< + Address, + Signature, + BaseExtension, + Extension = VersionedExtension<0, BaseExtension>, +> { /// An extrinsic without a signature or any extension. This means it's either an inherent or /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with /// the general transaction which is without a signature but does have an extension). @@ -88,7 +93,7 @@ pub enum Preamble Decode - for Preamble +impl Decode + for Preamble where Address: Decode, Signature: Decode, - ExtensionV0: Decode, + BaseExtension: Decode, Extension: DecodeWithVersion, { fn decode(input: &mut I) -> Result { @@ -123,7 +128,7 @@ where (LEGACY_EXTRINSIC_FORMAT_VERSION, SIGNED_EXTRINSIC) => { let address = Address::decode(input)?; let signature = Signature::decode(input)?; - let ext = ExtensionV0::decode(input)?; + let ext = BaseExtension::decode(input)?; Self::Signed(address, signature, ext) }, (EXTRINSIC_FORMAT_VERSION, GENERAL_EXTRINSIC) => { @@ -138,12 +143,12 @@ where } } -impl Encode - for Preamble +impl Encode + for Preamble where Address: Encode, Signature: Encode, - ExtensionV0: Encode, + BaseExtension: Encode, Extension: Encode, { fn size_hint(&self) -> usize { @@ -181,11 +186,11 @@ where } } -impl - Preamble +impl + Preamble { /// Returns `Some` if this is a signed extrinsic, together with the relevant inner fields. - pub fn to_signed(self) -> Option<(Address, Signature, ExtensionV0)> { + pub fn to_signed(self) -> Option<(Address, Signature, BaseExtension)> { match self { Self::Signed(a, s, e) => Some((a, s, e)), _ => None, @@ -193,11 +198,11 @@ impl } } -impl fmt::Debug - for Preamble +impl fmt::Debug + for Preamble where Address: fmt::Debug, - ExtensionV0: fmt::Debug, + BaseExtension: fmt::Debug, Extension: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -237,30 +242,30 @@ pub struct UncheckedExtrinsic< Address, Call, Signature, - ExtensionV0, - Extension = NotVersionedExtension, + BaseExtension, + Extension = VersionedExtension<0, BaseExtension>, > { /// Information regarding the type of extrinsic this is (inherent or transaction) as well as /// associated extension (`Extension`) data if it's a transaction and a possible signature. - pub preamble: Preamble, + pub preamble: Preamble, /// The function that should be called. pub function: Call, } // TODO TODO: 2 possible implementation: // 1. a new generic for the multi version extension. -// 2. no new generic, the multi version extension defines what is ExtensionV0. +// 2. no new generic, the multi version extension defines what is BaseExtension. /// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded /// `Vec`, but requires some logic to extract the signature and payload. /// /// See [`UncheckedExtrinsic::encode`] and [`UncheckedExtrinsic::decode`]. -impl TypeInfo - for UncheckedExtrinsic +impl TypeInfo + for UncheckedExtrinsic where Address: StaticTypeInfo, Call: StaticTypeInfo, Signature: StaticTypeInfo, - ExtensionV0: StaticTypeInfo, + BaseExtension: StaticTypeInfo, Extension: StaticTypeInfo, { type Identity = UncheckedExtrinsic; @@ -275,7 +280,7 @@ where TypeParameter::new("Address", Some(meta_type::
())), TypeParameter::new("Call", Some(meta_type::())), TypeParameter::new("Signature", Some(meta_type::())), - TypeParameter::new("Extra", Some(meta_type::())), + TypeParameter::new("Extra", Some(meta_type::())), TypeParameter::new("GeneralExtra", Some(meta_type::())), ]) .docs(&["UncheckedExtrinsic raw bytes, requires custom decoding routine"]) @@ -286,8 +291,8 @@ where } } -impl - UncheckedExtrinsic +impl + UncheckedExtrinsic { /// New instance of a bare (ne unsigned) extrinsic. This could be used for an inherent or an /// old-school "unsigned transaction" (which are new being deprecated in favour of general @@ -311,7 +316,7 @@ impl /// Create an `UncheckedExtrinsic` from a `Preamble` and the actual `Call`. pub fn from_parts( function: Call, - preamble: Preamble, + preamble: Preamble, ) -> Self { Self { preamble, function } } @@ -331,7 +336,7 @@ impl function: Call, signed: Address, signature: Signature, - tx_ext: ExtensionV0, + tx_ext: BaseExtension, ) -> Self { Self { preamble: Preamble::Signed(signed, signature, tx_ext), function } } @@ -345,14 +350,14 @@ impl /// This function is only available for `UncheckedExtrinsic` without multi version extension. pub fn new_transaction(function: Call, tx_ext: Extension) -> Self { Self { - preamble: Preamble::General(EXTENSION_VERSION, NotVersionedExtension(tx_ext)), + preamble: Preamble::General(EXTENSION_VERSION, VersionedExtension::new(tx_ext)), function, } } } -impl ExtrinsicLike - for UncheckedExtrinsic +impl ExtrinsicLike + for UncheckedExtrinsic { fn is_bare(&self) -> bool { matches!(self.preamble, Preamble::Bare(_)) @@ -367,18 +372,18 @@ impl ExtrinsicLike // transactions by adding an extension to validate signatures, as they are currently validated in // the `Checkable` implementation for `Signed` transactions. -impl Checkable - for UncheckedExtrinsic +impl Checkable + for UncheckedExtrinsic where LookupSource: Member + MaybeDisplay, Call: Encode + Member + Dispatchable, Signature: Member + traits::Verify, ::Signer: IdentifyAccount, - ExtensionV0: Encode + TransactionExtension, + BaseExtension: Encode + TransactionExtension, AccountId: Member + MaybeDisplay, Lookup: traits::Lookup, { - type Checked = CheckedExtrinsic; + type Checked = CheckedExtrinsic; fn check(self, lookup: &Lookup) -> Result { Ok(match self.preamble { @@ -436,9 +441,9 @@ impl< Address, Call: Dispatchable, Signature, - ExtensionV0: TransactionExtension, + BaseExtension: TransactionExtension, Extension: VersionedTransactionExtensionPipeline, - > UncheckedExtrinsic + > UncheckedExtrinsic { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. @@ -511,13 +516,13 @@ impl< // } // } -impl Decode - for UncheckedExtrinsic +impl Decode + for UncheckedExtrinsic where Address: Decode, Signature: Decode, Call: Decode, - ExtensionV0: Decode, + BaseExtension: Decode, Extension: DecodeWithVersion, { fn decode(input: &mut I) -> Result { @@ -545,12 +550,12 @@ where } #[docify::export(unchecked_extrinsic_encode_impl)] -impl Encode - for UncheckedExtrinsic +impl Encode + for UncheckedExtrinsic where - Preamble: Encode, + Preamble: Encode, Call: Encode, - ExtensionV0: Encode, + BaseExtension: Encode, Extension: Encode, { fn encode(&self) -> Vec { @@ -569,16 +574,21 @@ where } } -impl EncodeLike - for UncheckedExtrinsic +impl EncodeLike + for UncheckedExtrinsic where Self: Encode, { } #[cfg(feature = "serde")] -impl - serde::Serialize for UncheckedExtrinsic +impl< + Address: Encode, + Signature: Encode, + Call: Encode, + BaseExtension: Encode, + Extension: Encode, + > serde::Serialize for UncheckedExtrinsic { fn serialize(&self, seq: S) -> Result where @@ -594,9 +604,10 @@ impl< Address: Decode, Signature: Decode, Call: Decode, - ExtensionV0: Decode, + BaseExtension: Decode, Extension: DecodeWithVersion, - > serde::Deserialize<'a> for UncheckedExtrinsic + > serde::Deserialize<'a> + for UncheckedExtrinsic { fn deserialize(de: D) -> Result where @@ -613,39 +624,39 @@ impl< /// Note that the payload that we sign to produce unchecked extrinsic signature /// is going to be different than the `SignaturePayload` - so the thing the extrinsic /// actually contains. -pub struct SignedPayload>( - (Call, ExtensionV0, ExtensionV0::Implicit), +pub struct SignedPayload>( + (Call, BaseExtension, BaseExtension::Implicit), ); -impl SignedPayload +impl SignedPayload where Call: Encode + Dispatchable, - ExtensionV0: TransactionExtension, + BaseExtension: TransactionExtension, { /// Create new `SignedPayload` for extrinsic format version 4. /// - /// This function may fail if `implicit` of `ExtensionV0` is not available. - pub fn new(call: Call, tx_ext: ExtensionV0) -> Result { - let implicit = ExtensionV0::implicit(&tx_ext)?; + /// This function may fail if `implicit` of `BaseExtension` is not available. + pub fn new(call: Call, tx_ext: BaseExtension) -> Result { + let implicit = BaseExtension::implicit(&tx_ext)?; let raw_payload = (call, tx_ext, implicit); Ok(Self(raw_payload)) } /// Create new `SignedPayload` from raw components. - pub fn from_raw(call: Call, tx_ext: ExtensionV0, implicit: ExtensionV0::Implicit) -> Self { + pub fn from_raw(call: Call, tx_ext: BaseExtension, implicit: BaseExtension::Implicit) -> Self { Self((call, tx_ext, implicit)) } /// Deconstruct the payload into it's components. - pub fn deconstruct(self) -> (Call, ExtensionV0, ExtensionV0::Implicit) { + pub fn deconstruct(self) -> (Call, BaseExtension, BaseExtension::Implicit) { self.0 } } -impl Encode for SignedPayload +impl Encode for SignedPayload where Call: Encode + Dispatchable, - ExtensionV0: TransactionExtension, + BaseExtension: TransactionExtension, { /// Get an encoded version of this `blake2_256`-hashed payload. fn using_encoded R>(&self, f: F) -> R { @@ -659,24 +670,24 @@ where } } -impl EncodeLike for SignedPayload +impl EncodeLike for SignedPayload where Call: Encode + Dispatchable, - ExtensionV0: TransactionExtension, + BaseExtension: TransactionExtension, { } -impl - From> for OpaqueExtrinsic +impl + From> for OpaqueExtrinsic where Address: Encode, Signature: Encode, Call: Encode, - ExtensionV0: Encode, + BaseExtension: Encode, Extension: Encode, { fn from( - extrinsic: UncheckedExtrinsic, + extrinsic: UncheckedExtrinsic, ) -> Self { Self::from_bytes(extrinsic.encode().as_slice()).expect( "both OpaqueExtrinsic and UncheckedExtrinsic have encoding that is compatible with \ diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index 686a1f1b1770f..a4b97b0a49ab7 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -25,7 +25,8 @@ use crate::{ scale_info::{MetaType, StaticTypeInfo}, traits::AsTransactionAuthorizedOrigin, transaction_validity::{ - TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + ValidTransaction, }, DispatchResult, }; @@ -81,68 +82,186 @@ pub trait VersionedTransactionExtensionPipeline: } /// TODO TODO: doc -// TODO TODO: maybe rename to version0 or something -// TODO TODO: maybe replace with type alias for VersionedExtension<0, Extension> -#[derive(Encode, Decode, Clone, Debug, TypeInfo)] -pub struct NotVersionedExtension(pub Extension); +#[derive(Encode, Clone, Debug, TypeInfo)] +pub struct VersionedExtension { + extension: Extension, +} -impl< - Call: Dispatchable + Encode, - Extension: TransactionExtension, - > VersionedTransactionExtensionPipeline for NotVersionedExtension +impl VersionedExtension { + /// Create a new versioned extension. + pub fn new(extension: Extension) -> Self { + Self { extension } + } +} + +impl DecodeWithVersion + for VersionedExtension { - fn weight(&self, call: &Call) -> Weight { - self.0.weight(call) + fn decode_with_version( + extension_version: u8, + input: &mut I, + ) -> Result { + if extension_version == VERSION { + Ok(VersionedExtension { extension: Extension::decode(input)? }) + } else { + Err(codec::Error::from("Invalid extension version")) + } + } +} + +impl Encode for MultiVersion { + fn size_hint(&self) -> usize { + match self { + MultiVersion::A(a) => a.size_hint(), + MultiVersion::B(b) => b.size_hint(), + } + } + fn encode(&self) -> Vec { + match self { + MultiVersion::A(a) => a.encode(), + MultiVersion::B(b) => b.encode(), + } + } + fn encode_to(&self, dest: &mut T) { + match self { + MultiVersion::A(a) => a.encode_to(dest), + MultiVersion::B(b) => b.encode_to(dest), + } + } + fn encoded_size(&self) -> usize { + match self { + MultiVersion::A(a) => a.encoded_size(), + MultiVersion::B(b) => b.encoded_size(), + } + } + fn using_encoded R>(&self, f: F) -> R { + match self { + MultiVersion::A(a) => a.using_encoded(f), + MultiVersion::B(b) => b.using_encoded(f), + } + } +} + +/// TODO TODO: doc +#[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] +struct InvalidVersion; + +/// TODO TODO: doc +#[allow(private_interfaces)] +#[derive(Clone, Debug, TypeInfo)] +pub enum MultiVersion { + /// TODO TODO: doc + A(A), + /// TODO TODO: doc + B(B), +} + +impl DecodeWithVersion for InvalidVersion { + fn decode_with_version( + _extension_version: u8, + _input: &mut I, + ) -> Result { + Err(codec::Error::from("Invalid extension version")) + } +} + +impl VersionedTransactionExtensionPipeline for InvalidVersion { + fn weight(&self, _call: &Call) -> Weight { + Weight::zero() } fn validate_only( &self, - origin: DispatchOriginOf, - call: &Call, - info: &DispatchInfoOf, - len: usize, - source: TransactionSource, + _origin: DispatchOriginOf, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + _source: TransactionSource, ) -> Result { - self.0.validate_only(origin, call, info, len, source, 0).map(|x| x.0) + Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))) } fn dispatch_transaction( self, - origin: DispatchOriginOf, - call: Call, - info: &DispatchInfoOf, - len: usize, + _origin: DispatchOriginOf, + _call: Call, + _info: &DispatchInfoOf, + _len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { - self.0.dispatch_transaction(origin, call, info, len, 0) + Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0)).into()) } } -impl DecodeWithVersion for NotVersionedExtension { - fn decode_with_version(_: u8, input: &mut I) -> Result { - Self::decode(input) - } +/// TODO TODO: doc +pub trait MultiVersionItem { + /// TODO TODO: doc + const VERSION: Option; } -/// TODO TODO: doc -#[derive(Encode, Clone, Debug, TypeInfo)] -pub struct VersionedExtension { - extension: Extension, +impl MultiVersionItem for VersionedExtension { + const VERSION: Option = Some(VERSION); } -impl DecodeWithVersion for VersionedExtension { +impl MultiVersionItem for InvalidVersion { + const VERSION: Option = None; +} + +impl + DecodeWithVersion for MultiVersion +{ fn decode_with_version( extension_version: u8, input: &mut I, ) -> Result { - if extension_version == VERSION { - Ok(VersionedExtension { - extension: Extension::decode(input)?, - }) + if A::VERSION == Some(extension_version) { + Ok(MultiVersion::A(A::decode_with_version(extension_version, input)?)) + } else if B::VERSION == Some(extension_version) { + Ok(MultiVersion::B(B::decode_with_version(extension_version, input)?)) } else { Err(codec::Error::from("Invalid extension version")) } } } -impl + Encode, +impl VersionedTransactionExtensionPipeline for MultiVersion +where + A: VersionedTransactionExtensionPipeline + MultiVersionItem, + B: VersionedTransactionExtensionPipeline + MultiVersionItem, +{ + fn weight(&self, call: &Call) -> Weight { + match self { + MultiVersion::A(a) => a.weight(call), + MultiVersion::B(b) => b.weight(call), + } + } + fn validate_only( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result { + match self { + MultiVersion::A(a) => a.validate_only(origin, call, info, len, source), + MultiVersion::B(b) => b.validate_only(origin, call, info, len, source), + } + } + fn dispatch_transaction( + self, + origin: DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + match self { + MultiVersion::A(a) => a.dispatch_transaction(origin, call, info, len), + MultiVersion::B(b) => b.dispatch_transaction(origin, call, info, len), + } + } +} + +impl< + const VERSION: u8, + Call: Dispatchable + Encode, Extension: TransactionExtension, > VersionedTransactionExtensionPipeline for VersionedExtension { @@ -157,7 +276,9 @@ impl Result { - self.extension.validate_only(origin, call, info, len, source, VERSION).map(|x| x.0) + self.extension + .validate_only(origin, call, info, len, source, VERSION) + .map(|x| x.0) } fn dispatch_transaction( self, From 17a8dc0334467c98cab1c1e26ec2ed0e09dfe32b Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 16 Dec 2024 19:36:09 +0900 Subject: [PATCH 06/56] cleanup --- .../runtime/src/generic/checked_extrinsic.rs | 9 +-- .../src/generic/unchecked_extrinsic.rs | 71 +++---------------- .../dispatch_transaction.rs | 1 - 3 files changed, 12 insertions(+), 69 deletions(-) diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index e2fa8697d29dd..48ca6ee44491a 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -111,8 +111,7 @@ where .map(|x| x.0) }, ExtrinsicFormat::General(_extension_version, ref extension) => extension - .validate_only(None.into(), &self.function, info, len, source) // TODO TODO: needs validate - , + .validate_only(None.into(), &self.function, info, len, source), } } @@ -143,8 +142,7 @@ where DEFAULT_EXTENSION_VERSION, ), ExtrinsicFormat::General(_extension_version, extension) => - extension.dispatch_transaction(None.into(), self.function, info, len), /* TODO TODO: - * needs dispatch */ + extension.dispatch_transaction(None.into(), self.function, info, len), } } } @@ -162,8 +160,7 @@ impl< match &self.format { ExtrinsicFormat::Bare => Weight::zero(), ExtrinsicFormat::Signed(_, ext) => ext.weight(&self.function), - ExtrinsicFormat::General(_, ext) => ext.weight(&self.function), /* TODO TODO: needs - * weight */ + ExtrinsicFormat::General(_, ext) => ext.weight(&self.function), } } } diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index b2a4e006d759b..71191d42fd8c2 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -429,14 +429,21 @@ where } } -// TODO TODO +// TODO TODO: metadata impl> ExtrinsicMetadata for UncheckedExtrinsic { const VERSIONS: &'static [u8] = &[LEGACY_EXTRINSIC_FORMAT_VERSION, EXTRINSIC_FORMAT_VERSION]; type TransactionExtensions = Extension; + // TODO TODO: maybe a new type TransactionExtension and BaseTransactionExtension } +// TODO TODO: + // /// For each supported version number, list the indexes, in order, of the extensions used. + // pub transaction_extensions_by_version: BTreeMap>, + // /// The transaction extensions in the order they appear in the extrinsic. + // pub transaction_extensions: Vec>, + impl< Address, Call: Dispatchable, @@ -451,71 +458,11 @@ impl< match &self.preamble { Preamble::Bare(_) => Weight::zero(), Preamble::Signed(_, _, ext) => ext.weight(&self.function), - Preamble::General(_, ext) => ext.weight(&self.function), /* TODO TODO: needs weight - * function */ + Preamble::General(_, ext) => ext.weight(&self.function), } } } -// // usage prop 1 -// type TxExtV1 = VersionedExtension<1, (CheckNonce, CheckNonce)>; -// type TxExt = MultiVersionExtension<( -// ExtensionV1, -// ExtensionV2, -// )>; - -// usage prop 2 -// type TxExtV1 = (CheckNonce, CheckNonce); -// type TxExt = MultiVersionExtension< -// 1, -// ( -// VersionedExtension<1, TxExtV1>, -// VersionedExtension<2, TxExtV2>, -// ) -// >; -// -// OR -// -// type TxExtV1 = (1, (CheckNonce, CheckNonce)); -// type TxExt = MultiVersionExtension<( -// ExtensionV1, -// ExtensionV2, -// )>; - -// // usage prop 2 -// type TxExtV1 = (CheckNonce, CheckNonce); -// type TxExt = MultiVersionExtension< -// ( -// (1, TxExtV1), -// (2, TxExtV2), -// ) -// >; -// type UncheckedExtrinsic = UncheckedExtrinsic; -// -// // usage prop 2 -// type TxExtV1 = (CheckNonce, CheckNonce); -// type TxExt = MultiVersionExtension< -// ( -// (1, TxExtV1), -// (2, TxExtV2), -// ) -// >; -// type UncheckedExtrinsic = UncheckedExtrinsic; - -// impl Decode -// for UncheckedExtrinsic -// where -// Address: Decode, -// Signature: Decode, -// Call: Decode, -// { -// fn decode(input: &mut I) -> Result { -// todo!(); -// } -// } - impl Decode for UncheckedExtrinsic where diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs index 82f7e3522b62f..28030d12fc9f3 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs @@ -29,7 +29,6 @@ use super::*; /// provide transaction dispatching functionality. We avoid implementing this directly on the trait /// since we never want it to be overriden by the trait implementation. pub trait DispatchTransaction { - // TODO TODO: remove some redundant types here /// The origin type of the transaction. type Origin; /// The info type. From a38fac382778bfef3e37f0a03ed3cdadce35ff32 Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 17 Dec 2024 12:51:39 +0900 Subject: [PATCH 07/56] WIP --- substrate/primitives/metadata-ir/src/types.rs | 5 +- .../runtime/src/generic/checked_extrinsic.rs | 66 +++-- .../src/generic/unchecked_extrinsic.rs | 230 +++++++++--------- .../primitives/runtime/src/traits/mod.rs | 5 +- .../src/traits/transaction_extension/mod.rs | 118 ++++++++- 5 files changed, 269 insertions(+), 155 deletions(-) diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index af217ffe16eeb..a9a19b6e6fc25 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -182,7 +182,10 @@ pub struct ExtrinsicMetadataIR { // TODO: metadata-v16: remove this, the `implicit` type can be found in `extensions::implicit`. pub extra_ty: T::Type, /// The transaction extensions in the order they appear in the extrinsic. - pub extensions: Vec>, + pub extensions: Vec>, /* TODO TODO: renme extension_v0 + * TODO TODO: + * transaction_extensions_by_version + * and transaction_extensions */ } impl IntoPortable for ExtrinsicMetadataIR { diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 48ca6ee44491a..e1dfec8cc5433 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -19,6 +19,7 @@ //! stage. use codec::Encode; +use sp_core::RuntimeDebug; use sp_weights::Weight; use super::unchecked_extrinsic::ExtensionVersion; @@ -26,7 +27,8 @@ use crate::{ traits::{ self, transaction_extension::{ - TransactionExtension, VersionedExtension, VersionedTransactionExtensionPipeline, + ExtensionVariant, InvalidVersion, TransactionExtension, + VersionedTransactionExtensionPipeline, }, AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned, @@ -34,23 +36,23 @@ use crate::{ transaction_validity::{TransactionSource, TransactionValidity}, }; -/// Default version of the [Extension](TransactionExtension) used to construct the inherited +/// Version 0 of the transaction extension version used to construct the inherited /// implication for legacy transactions. -const DEFAULT_EXTENSION_VERSION: ExtensionVersion = 0; +const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// The kind of extrinsic this is, including any fields required of that kind. This is basically /// the full extrinsic except the `Call`. -#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] -pub enum ExtrinsicFormat { +#[derive(PartialEq, Eq, Clone, RuntimeDebug)] +pub enum ExtrinsicFormat { /// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or /// `ValidateUnsigned`, both deprecated, or alternatively a `ProvideInherent`. Bare, /// Extrinsic has a default `Origin` of `Signed(AccountId)` and must pass all /// `TransactionExtension`s regular checks and includes all extension data. - Signed(AccountId, BaseExtension), + Signed(AccountId, ExtensionV0), /// Extrinsic has a default `Origin` of `None` and must pass all `TransactionExtension`s. /// regular checks and includes all extension data. - General(ExtensionVersion, Extension), + General(ExtensionVariant), } /// Definition of something that the external world might want to say; its existence implies that it @@ -59,27 +61,22 @@ pub enum ExtrinsicFormat { /// This is typically passed into [`traits::Applyable::apply`], which should execute /// [`CheckedExtrinsic::function`], alongside all other bits and bobs. #[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] -pub struct CheckedExtrinsic< - AccountId, - Call, - BaseExtension, - Extension = VersionedExtension<0, BaseExtension>, -> { +pub struct CheckedExtrinsic { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). - pub format: ExtrinsicFormat, + pub format: ExtrinsicFormat, /// The function that should be called. pub function: Call, } -impl traits::Applyable - for CheckedExtrinsic +impl traits::Applyable + for CheckedExtrinsic where AccountId: Member + MaybeDisplay, Call: Member + Dispatchable + Encode, - BaseExtension: TransactionExtension, - Extension: VersionedTransactionExtensionPipeline, + ExtensionV0: TransactionExtension, + ExtensionOtherVersions: VersionedTransactionExtensionPipeline, RuntimeOrigin: From> + AsTransactionAuthorizedOrigin, { type Call = Call; @@ -94,24 +91,17 @@ where ExtrinsicFormat::Bare => { let inherent_validation = I::validate_unsigned(source, &self.function)?; #[allow(deprecated)] - let legacy_validation = BaseExtension::bare_validate(&self.function, info, len)?; + let legacy_validation = ExtensionV0::bare_validate(&self.function, info, len)?; Ok(legacy_validation.combine_with(inherent_validation)) }, ExtrinsicFormat::Signed(ref signer, ref extension) => { let origin = Some(signer.clone()).into(); extension - .validate_only( - origin, - &self.function, - info, - len, - source, - DEFAULT_EXTENSION_VERSION, - ) + .validate_only(origin, &self.function, info, len, source, EXTENSION_V0_VERSION) .map(|x| x.0) }, - ExtrinsicFormat::General(_extension_version, ref extension) => extension - .validate_only(None.into(), &self.function, info, len, source), + ExtrinsicFormat::General(ref extension) => + extension.validate_only(None.into(), &self.function, info, len, source), } } @@ -125,13 +115,13 @@ where I::pre_dispatch(&self.function)?; // TODO: Separate logic from `TransactionExtension` into a new `InherentExtension` // interface. - BaseExtension::bare_validate_and_prepare(&self.function, info, len)?; + ExtensionV0::bare_validate_and_prepare(&self.function, info, len)?; let res = self.function.dispatch(None.into()); let mut post_info = res.unwrap_or_else(|err| err.post_info); let pd_res = res.map(|_| ()).map_err(|e| e.error); // TODO: Separate logic from `TransactionExtension` into a new `InherentExtension` // interface. - BaseExtension::bare_post_dispatch(info, &mut post_info, len, &pd_res)?; + ExtensionV0::bare_post_dispatch(info, &mut post_info, len, &pd_res)?; Ok(res) }, ExtrinsicFormat::Signed(signer, extension) => extension.dispatch_transaction( @@ -139,9 +129,9 @@ where self.function, info, len, - DEFAULT_EXTENSION_VERSION, + EXTENSION_V0_VERSION, ), - ExtrinsicFormat::General(_extension_version, extension) => + ExtrinsicFormat::General(extension) => extension.dispatch_transaction(None.into(), self.function, info, len), } } @@ -149,10 +139,10 @@ where impl< AccountId, - Call: Dispatchable, - BaseExtension: TransactionExtension, - Extension: VersionedTransactionExtensionPipeline, - > CheckedExtrinsic + Call: Dispatchable + Encode, + ExtensionV0: TransactionExtension, + ExtensionOtherVersions: VersionedTransactionExtensionPipeline, + > CheckedExtrinsic { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. @@ -160,7 +150,7 @@ impl< match &self.format { ExtrinsicFormat::Bare => Weight::zero(), ExtrinsicFormat::Signed(_, ext) => ext.weight(&self.function), - ExtrinsicFormat::General(_, ext) => ext.weight(&self.function), + ExtrinsicFormat::General(ext) => ext.weight(&self.function), } } } diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 71191d42fd8c2..a2e14ff488aa4 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -22,11 +22,11 @@ use crate::{ traits::{ self, transaction_extension::{ - DecodeWithVersion, TransactionExtension, VersionedExtension, - VersionedTransactionExtensionPipeline, + DecodeWithVersion, ExtensionVariant, InvalidVersion, TransactionExtension, + VersionedExtension, VersionedTransactionExtensionPipeline, }, - Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, - Member, SignaturePayload, + AsTransactionAuthorizedOrigin, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, + IdentifyAccount, MaybeDisplay, Member, SignaturePayload, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, @@ -57,12 +57,9 @@ pub const EXTRINSIC_FORMAT_VERSION: ExtrinsicVersion = 5; /// compatibility reasons. It will be deprecated in favor of v5 extrinsics and an inherent/general /// transaction model. pub const LEGACY_EXTRINSIC_FORMAT_VERSION: ExtrinsicVersion = 4; -/// Current version of the [Extension](TransactionExtension) used in this -/// [extrinsic](UncheckedExtrinsic). -/// -/// This version needs to be bumped if there are breaking changes to the extension used in the -/// [UncheckedExtrinsic] implementation. -const EXTENSION_VERSION: ExtensionVersion = 0; +/// Version 0 of the transaction extension version used to construct the inherited +/// implication for legacy transactions. +const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// The `SignaturePayload` of `UncheckedExtrinsic`. pub type UncheckedSignaturePayload = (Address, Signature, Extension); @@ -78,12 +75,7 @@ impl SignaturePaylo /// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and /// holds any necessary specialized data. #[derive(Eq, PartialEq, Clone)] -pub enum Preamble< - Address, - Signature, - BaseExtension, - Extension = VersionedExtension<0, BaseExtension>, -> { +pub enum Preamble { /// An extrinsic without a signature or any extension. This means it's either an inherent or /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with /// the general transaction which is without a signature but does have an extension). @@ -93,11 +85,11 @@ pub enum Preamble< Bare(ExtrinsicVersion), /// An old-school transaction extrinsic which includes a signature of some hard-coded crypto. /// Available only on extrinsic version 4. - Signed(Address, Signature, BaseExtension), + Signed(Address, Signature, ExtensionV0), /// A new-school transaction extrinsic which does not include a signature by default. The /// origin authorization, through signatures or other means, is performed by the transaction /// extension in this extrinsic. Available starting with extrinsic version 5. - General(ExtensionVersion, Extension), + General(ExtensionVersion, ExtensionVariant), } const VERSION_MASK: u8 = 0b0011_1111; @@ -106,13 +98,13 @@ const BARE_EXTRINSIC: u8 = 0b0000_0000; const SIGNED_EXTRINSIC: u8 = 0b1000_0000; const GENERAL_EXTRINSIC: u8 = 0b0100_0000; -impl Decode - for Preamble +impl Decode + for Preamble where Address: Decode, Signature: Decode, - BaseExtension: Decode, - Extension: DecodeWithVersion, + ExtensionV0: Decode, + ExtensionOtherVersions: DecodeWithVersion, { fn decode(input: &mut I) -> Result { let version_and_type = input.read_byte()?; @@ -128,12 +120,16 @@ where (LEGACY_EXTRINSIC_FORMAT_VERSION, SIGNED_EXTRINSIC) => { let address = Address::decode(input)?; let signature = Signature::decode(input)?; - let ext = BaseExtension::decode(input)?; + let ext = ExtensionV0::decode(input)?; Self::Signed(address, signature, ext) }, (EXTRINSIC_FORMAT_VERSION, GENERAL_EXTRINSIC) => { let ext_version = ExtensionVersion::decode(input)?; - let ext = Extension::decode_with_version(ext_version, input)?; + let ext = + ExtensionVariant::::decode_with_version( + ext_version, + input, + )?; Self::General(ext_version, ext) }, (_, _) => return Err("Invalid transaction version".into()), @@ -143,13 +139,13 @@ where } } -impl Encode - for Preamble +impl Encode + for Preamble where Address: Encode, Signature: Encode, - BaseExtension: Encode, - Extension: Encode, + ExtensionV0: Encode, + ExtensionOtherVersions: Encode, { fn size_hint(&self) -> usize { match &self { @@ -186,11 +182,11 @@ where } } -impl - Preamble +impl + Preamble { /// Returns `Some` if this is a signed extrinsic, together with the relevant inner fields. - pub fn to_signed(self) -> Option<(Address, Signature, BaseExtension)> { + pub fn to_signed(self) -> Option<(Address, Signature, ExtensionV0)> { match self { Self::Signed(a, s, e) => Some((a, s, e)), _ => None, @@ -198,12 +194,12 @@ impl } } -impl fmt::Debug - for Preamble +impl fmt::Debug + for Preamble where Address: fmt::Debug, - BaseExtension: fmt::Debug, - Extension: fmt::Debug, + ExtensionV0: fmt::Debug, + ExtensionOtherVersions: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -242,33 +238,33 @@ pub struct UncheckedExtrinsic< Address, Call, Signature, - BaseExtension, - Extension = VersionedExtension<0, BaseExtension>, + ExtensionV0, + ExtensionOtherVersions = VersionedExtension<0, ExtensionV0>, > { /// Information regarding the type of extrinsic this is (inherent or transaction) as well as /// associated extension (`Extension`) data if it's a transaction and a possible signature. - pub preamble: Preamble, + pub preamble: Preamble, /// The function that should be called. pub function: Call, } // TODO TODO: 2 possible implementation: // 1. a new generic for the multi version extension. -// 2. no new generic, the multi version extension defines what is BaseExtension. +// 2. no new generic, the multi version extension defines what is ExtensionV0. /// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded /// `Vec`, but requires some logic to extract the signature and payload. /// /// See [`UncheckedExtrinsic::encode`] and [`UncheckedExtrinsic::decode`]. -impl TypeInfo - for UncheckedExtrinsic +impl TypeInfo + for UncheckedExtrinsic where Address: StaticTypeInfo, Call: StaticTypeInfo, Signature: StaticTypeInfo, - BaseExtension: StaticTypeInfo, - Extension: StaticTypeInfo, + ExtensionV0: StaticTypeInfo, + ExtensionOtherVersions: StaticTypeInfo, { - type Identity = UncheckedExtrinsic; + type Identity = UncheckedExtrinsic; fn type_info() -> Type { Type::builder() @@ -280,8 +276,11 @@ where TypeParameter::new("Address", Some(meta_type::
())), TypeParameter::new("Call", Some(meta_type::())), TypeParameter::new("Signature", Some(meta_type::())), - TypeParameter::new("Extra", Some(meta_type::())), - TypeParameter::new("GeneralExtra", Some(meta_type::())), + TypeParameter::new("Extra", Some(meta_type::())), + TypeParameter::new( + "GeneralExtensions", + Some(meta_type::>()), + ), ]) .docs(&["UncheckedExtrinsic raw bytes, requires custom decoding routine"]) // Because of the custom encoding, we can only accurately describe the encoding as an @@ -291,8 +290,8 @@ where } } -impl - UncheckedExtrinsic +impl + UncheckedExtrinsic { /// New instance of a bare (ne unsigned) extrinsic. This could be used for an inherent or an /// old-school "unsigned transaction" (which are new being deprecated in favour of general @@ -316,7 +315,7 @@ impl /// Create an `UncheckedExtrinsic` from a `Preamble` and the actual `Call`. pub fn from_parts( function: Call, - preamble: Preamble, + preamble: Preamble, ) -> Self { Self { preamble, function } } @@ -336,28 +335,28 @@ impl function: Call, signed: Address, signature: Signature, - tx_ext: BaseExtension, + tx_ext: ExtensionV0, ) -> Self { Self { preamble: Preamble::Signed(signed, signature, tx_ext), function } } } -impl - UncheckedExtrinsic +impl + UncheckedExtrinsic { /// New instance of an new-school unsigned transaction. /// /// This function is only available for `UncheckedExtrinsic` without multi version extension. - pub fn new_transaction(function: Call, tx_ext: Extension) -> Self { + pub fn new_transaction(function: Call, tx_ext: ExtensionV0) -> Self { Self { - preamble: Preamble::General(EXTENSION_VERSION, VersionedExtension::new(tx_ext)), + preamble: Preamble::General(EXTENSION_V0_VERSION, ExtensionVariant::V0(tx_ext)), function, } } } -impl ExtrinsicLike - for UncheckedExtrinsic +impl ExtrinsicLike + for UncheckedExtrinsic { fn is_bare(&self) -> bool { matches!(self.preamble, Preamble::Bare(_)) @@ -372,18 +371,19 @@ impl ExtrinsicLike // transactions by adding an extension to validate signatures, as they are currently validated in // the `Checkable` implementation for `Signed` transactions. -impl Checkable - for UncheckedExtrinsic +impl + Checkable + for UncheckedExtrinsic where LookupSource: Member + MaybeDisplay, Call: Encode + Member + Dispatchable, Signature: Member + traits::Verify, ::Signer: IdentifyAccount, - BaseExtension: Encode + TransactionExtension, + ExtensionV0: Encode + TransactionExtension, AccountId: Member + MaybeDisplay, Lookup: traits::Lookup, { - type Checked = CheckedExtrinsic; + type Checked = CheckedExtrinsic; fn check(self, lookup: &Lookup) -> Result { Ok(match self.preamble { @@ -397,8 +397,8 @@ where let (function, tx_ext, _) = raw_payload.deconstruct(); CheckedExtrinsic { format: ExtrinsicFormat::Signed(signed, tx_ext), function } }, - Preamble::General(extension_version, tx_ext) => CheckedExtrinsic { - format: ExtrinsicFormat::General(extension_version, tx_ext), + Preamble::General(_ext_version, tx_ext) => CheckedExtrinsic { + format: ExtrinsicFormat::General(tx_ext), function: self.function, }, Preamble::Bare(_) => @@ -419,8 +419,8 @@ where function: self.function, } }, - Preamble::General(extension_version, tx_ext) => CheckedExtrinsic { - format: ExtrinsicFormat::General(extension_version, tx_ext), + Preamble::General(tx_ext) => CheckedExtrinsic { + format: ExtrinsicFormat::General(tx_ext), function: self.function, }, Preamble::Bare(_) => @@ -430,27 +430,21 @@ where } // TODO TODO: metadata -impl> - ExtrinsicMetadata for UncheckedExtrinsic +impl ExtrinsicMetadata + for UncheckedExtrinsic { const VERSIONS: &'static [u8] = &[LEGACY_EXTRINSIC_FORMAT_VERSION, EXTRINSIC_FORMAT_VERSION]; - type TransactionExtensions = Extension; - // TODO TODO: maybe a new type TransactionExtension and BaseTransactionExtension + type TransactionExtensionV0 = ExtensionV0; + type TransactionExtensions = ExtensionVariant; } -// TODO TODO: - // /// For each supported version number, list the indexes, in order, of the extensions used. - // pub transaction_extensions_by_version: BTreeMap>, - // /// The transaction extensions in the order they appear in the extrinsic. - // pub transaction_extensions: Vec>, - impl< Address, - Call: Dispatchable, + Call: Dispatchable + Encode, Signature, - BaseExtension: TransactionExtension, - Extension: VersionedTransactionExtensionPipeline, - > UncheckedExtrinsic + ExtensionV0: TransactionExtension, + ExtensionOtherVersions: VersionedTransactionExtensionPipeline, + > UncheckedExtrinsic { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. @@ -463,14 +457,14 @@ impl< } } -impl Decode - for UncheckedExtrinsic +impl Decode + for UncheckedExtrinsic where Address: Decode, Signature: Decode, Call: Decode, - BaseExtension: Decode, - Extension: DecodeWithVersion, + ExtensionV0: Decode, + ExtensionOtherVersions: DecodeWithVersion, { fn decode(input: &mut I) -> Result { // This is a little more complicated than usual since the binary format must be compatible @@ -497,13 +491,13 @@ where } #[docify::export(unchecked_extrinsic_encode_impl)] -impl Encode - for UncheckedExtrinsic +impl Encode + for UncheckedExtrinsic where - Preamble: Encode, + Preamble: Encode, Call: Encode, - BaseExtension: Encode, - Extension: Encode, + ExtensionV0: Encode, + ExtensionOtherVersions: Encode, { fn encode(&self) -> Vec { let mut tmp = self.preamble.encode(); @@ -521,8 +515,8 @@ where } } -impl EncodeLike - for UncheckedExtrinsic +impl EncodeLike + for UncheckedExtrinsic where Self: Encode, { @@ -533,9 +527,10 @@ impl< Address: Encode, Signature: Encode, Call: Encode, - BaseExtension: Encode, - Extension: Encode, - > serde::Serialize for UncheckedExtrinsic + ExtensionV0: Encode, + ExtensionOtherVersions: Encode, + > serde::Serialize + for UncheckedExtrinsic { fn serialize(&self, seq: S) -> Result where @@ -551,10 +546,10 @@ impl< Address: Decode, Signature: Decode, Call: Decode, - BaseExtension: Decode, - Extension: DecodeWithVersion, + ExtensionV0: Decode, + ExtensionOtherVersions: DecodeWithVersion, > serde::Deserialize<'a> - for UncheckedExtrinsic + for UncheckedExtrinsic { fn deserialize(de: D) -> Result where @@ -571,39 +566,39 @@ impl< /// Note that the payload that we sign to produce unchecked extrinsic signature /// is going to be different than the `SignaturePayload` - so the thing the extrinsic /// actually contains. -pub struct SignedPayload>( - (Call, BaseExtension, BaseExtension::Implicit), +pub struct SignedPayload>( + (Call, ExtensionV0, ExtensionV0::Implicit), ); -impl SignedPayload +impl SignedPayload where Call: Encode + Dispatchable, - BaseExtension: TransactionExtension, + ExtensionV0: TransactionExtension, { /// Create new `SignedPayload` for extrinsic format version 4. /// - /// This function may fail if `implicit` of `BaseExtension` is not available. - pub fn new(call: Call, tx_ext: BaseExtension) -> Result { - let implicit = BaseExtension::implicit(&tx_ext)?; + /// This function may fail if `implicit` of `ExtensionV0` is not available. + pub fn new(call: Call, tx_ext: ExtensionV0) -> Result { + let implicit = ExtensionV0::implicit(&tx_ext)?; let raw_payload = (call, tx_ext, implicit); Ok(Self(raw_payload)) } /// Create new `SignedPayload` from raw components. - pub fn from_raw(call: Call, tx_ext: BaseExtension, implicit: BaseExtension::Implicit) -> Self { + pub fn from_raw(call: Call, tx_ext: ExtensionV0, implicit: ExtensionV0::Implicit) -> Self { Self((call, tx_ext, implicit)) } /// Deconstruct the payload into it's components. - pub fn deconstruct(self) -> (Call, BaseExtension, BaseExtension::Implicit) { + pub fn deconstruct(self) -> (Call, ExtensionV0, ExtensionV0::Implicit) { self.0 } } -impl Encode for SignedPayload +impl Encode for SignedPayload where Call: Encode + Dispatchable, - BaseExtension: TransactionExtension, + ExtensionV0: TransactionExtension, { /// Get an encoded version of this `blake2_256`-hashed payload. fn using_encoded R>(&self, f: F) -> R { @@ -617,24 +612,31 @@ where } } -impl EncodeLike for SignedPayload +impl EncodeLike for SignedPayload where Call: Encode + Dispatchable, - BaseExtension: TransactionExtension, + ExtensionV0: TransactionExtension, { } -impl - From> for OpaqueExtrinsic +impl + From> + for OpaqueExtrinsic where Address: Encode, Signature: Encode, Call: Encode, - BaseExtension: Encode, - Extension: Encode, + ExtensionV0: Encode, + ExtensionOtherVersions: Encode, { fn from( - extrinsic: UncheckedExtrinsic, + extrinsic: UncheckedExtrinsic< + Address, + Call, + Signature, + ExtensionV0, + ExtensionOtherVersions, + >, ) -> Self { Self::from_bytes(extrinsic.encode().as_slice()).expect( "both OpaqueExtrinsic and UncheckedExtrinsic have encoding that is compatible with \ @@ -907,7 +909,7 @@ mod tests { assert_eq!( >::check(ux, &Default::default()), Ok(CEx { - format: ExtrinsicFormat::General(0, DummyExtension), + format: ExtrinsicFormat::General(ExtensionVariant::V0(DummyExtension)), function: vec![0u8; 0].into() }), ); diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index cfcc3e5a354d6..dcea714ca90f5 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -1415,7 +1415,10 @@ pub trait ExtrinsicMetadata { /// By format we mean the encoded representation of the `Extrinsic`. const VERSIONS: &'static [u8]; - /// Transaction extensions attached to this `Extrinsic`. + /// The transaction extension version 0 attached to this `Extrinsic`. + type TransactionExtensionV0; + + /// All transaction extension versions attached to this `Extrinsic`. type TransactionExtensions; } diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index a4b97b0a49ab7..d71fa96fbafa4 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -22,6 +22,7 @@ use super::{ PostDispatchInfoOf, RefundWeight, }; use crate::{ + generic::ExtensionVersion, scale_info::{MetaType, StaticTypeInfo}, traits::AsTransactionAuthorizedOrigin, transaction_validity::{ @@ -33,6 +34,7 @@ use crate::{ use codec::{Codec, Decode, Encode}; use impl_trait_for_tuples::impl_for_tuples; use scale_info::TypeInfo; +use sp_core::RuntimeDebug; #[doc(hidden)] pub use sp_std::marker::PhantomData; use sp_std::{self, fmt::Debug, prelude::*}; @@ -45,6 +47,118 @@ mod dispatch_transaction; pub use as_transaction_extension::AsTransactionExtension; pub use dispatch_transaction::DispatchTransaction; +// TODO TODO: rewrite the bounds to bounds usage instead of expectation of bounds. +// TODO TODO: implement metadata for Versioned tx ext pipeline + +/// Version 0 of the transaction extension version used to construct the inherited +/// implication for legacy transactions. +const EXTENSION_V0_VERSION: ExtensionVersion = 0; + +#[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] +pub enum ExtensionVariant { + V0(ExtensionV0), + Other(ExtensionOtherVersions), +} + +impl Encode + for ExtensionVariant +{ + fn encode(&self) -> Vec { + match self { + ExtensionVariant::V0(ext) => ext.encode(), + ExtensionVariant::Other(ext) => ext.encode(), + } + } + fn size_hint(&self) -> usize { + match self { + ExtensionVariant::V0(ext) => ext.size_hint(), + ExtensionVariant::Other(ext) => ext.size_hint(), + } + } + fn encode_to(&self, dest: &mut T) { + match self { + ExtensionVariant::V0(ext) => ext.encode_to(dest), + ExtensionVariant::Other(ext) => ext.encode_to(dest), + } + } + fn encoded_size(&self) -> usize { + match self { + ExtensionVariant::V0(ext) => ext.encoded_size(), + ExtensionVariant::Other(ext) => ext.encoded_size(), + } + } + fn using_encoded R>(&self, f: F) -> R { + match self { + ExtensionVariant::V0(ext) => ext.using_encoded(f), + ExtensionVariant::Other(ext) => ext.using_encoded(f), + } + } +} + +impl DecodeWithVersion + for ExtensionVariant +{ + fn decode_with_version( + extension_version: u8, + input: &mut I, + ) -> Result { + match extension_version { + EXTENSION_V0_VERSION => Ok(ExtensionVariant::V0(Decode::decode(input)?)), + _ => Ok(ExtensionVariant::Other(DecodeWithVersion::decode_with_version( + extension_version, + input, + )?)), + } + } +} + +impl< + Call: Dispatchable + Encode, + ExtensionV0: TransactionExtension, + ExtensionOtherVersions: VersionedTransactionExtensionPipeline, + > VersionedTransactionExtensionPipeline + for ExtensionVariant +where + ::RuntimeOrigin: AsTransactionAuthorizedOrigin, +{ + fn weight(&self, call: &Call) -> Weight { + match self { + ExtensionVariant::V0(ext) => ext.weight(call), + ExtensionVariant::Other(ext) => ext.weight(call), + } + } + fn validate_only( + &self, + origin: super::DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result< + crate::transaction_validity::ValidTransaction, + crate::transaction_validity::TransactionValidityError, + > { + match self { + ExtensionVariant::V0(ext) => ext + .validate_only(origin, call, info, len, source, EXTENSION_V0_VERSION) + .map(|x| x.0), + ExtensionVariant::Other(ext) => ext.validate_only(origin, call, info, len, source), + } + } + fn dispatch_transaction( + self, + origin: super::DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + match self { + ExtensionVariant::V0(ext) => + ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION), + ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), + } + } +} /// TODO TODO: doc pub trait DecodeWithVersion: Sized { /// TODO TODO: doc @@ -144,7 +258,7 @@ impl Encode for MultiVersion { /// TODO TODO: doc #[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] -struct InvalidVersion; +pub struct InvalidVersion; /// TODO TODO: doc #[allow(private_interfaces)] @@ -200,6 +314,8 @@ impl MultiVersionItem for VersionedExtension = Some(VERSION); } +// TODO TODO: think about how to define the bare extrinsic transaction extension, and how to define +// the signed extrinsic transaction extension. impl MultiVersionItem for InvalidVersion { const VERSION: Option = None; } From 3f657ac89312e425eb768a25fbe5e1a26661f27e Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 17 Dec 2024 20:20:01 +0900 Subject: [PATCH 08/56] WIP --- substrate/bin/node/testing/src/bench.rs | 4 +- substrate/bin/node/testing/src/keyring.rs | 4 +- substrate/frame/revive/src/evm/runtime.rs | 1 + .../src/construct_runtime/expand/metadata.rs | 22 +++++ substrate/frame/support/src/dispatch.rs | 22 +++-- .../frame/transaction-payment/src/tests.rs | 2 +- substrate/primitives/metadata-ir/src/lib.rs | 2 + substrate/primitives/metadata-ir/src/types.rs | 14 +-- .../runtime/src/generic/checked_extrinsic.rs | 17 ++-- .../src/generic/unchecked_extrinsic.rs | 29 +++--- .../primitives/runtime/src/traits/mod.rs | 8 +- .../src/traits/transaction_extension/mod.rs | 90 ++++++++++++++++--- 12 files changed, 154 insertions(+), 61 deletions(-) diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index 35f041ef04453..a1c46e112f9df 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -601,8 +601,8 @@ impl BenchKeyring { function: xt.function, } .into(), - ExtrinsicFormat::General(ext_version, tx_ext) => generic::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::General(ext_version, tx_ext), + ExtrinsicFormat::General(tx_ext) => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(todo!(), tx_ext), function: xt.function, } .into(), diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index e5b0299f01a83..b7ce8ad036792 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -134,8 +134,8 @@ pub fn sign( function: xt.function, } .into(), - ExtrinsicFormat::General(ext_version, tx_ext) => generic::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::General(ext_version, tx_ext), + ExtrinsicFormat::General(tx_ext) => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(todo!(), tx_ext), function: xt.function, } .into(), diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 24b75de835698..9608c53332f6e 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -99,6 +99,7 @@ impl ExtrinsicMetadata E::Extension, >::VERSIONS; type TransactionExtensions = E::Extension; + type TransactionExtensionsVersions = sp_runtime::traits::transaction_extension::ExtensionVariant; } impl ExtrinsicCall diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index 0b3bd51688651..5d58697312ad1 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -115,6 +115,19 @@ pub fn expand_runtime_metadata( use #scrate::__private::metadata_ir::InternalImplRuntimeApis; + + let mut versioned_extensions_metadata = #scrate::sp_runtime::traits::transaction_extension::VersionedTransactionExtensionsMetadataBuilder::new(); + + < + < + #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata + >::TransactionExtensionsVersions + as + #scrate::sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipeline::< + <#runtime as #system_path::Config>::RuntimeCall + > + >::build_metadata(&mut versioned_extensions_metadata); + #scrate::__private::metadata_ir::MetadataIR { pallets: #scrate::__private::vec![ #(#pallets),* ], extrinsic: #scrate::__private::metadata_ir::ExtrinsicMetadataIR { @@ -140,6 +153,15 @@ pub fn expand_runtime_metadata( implicit: meta.implicit, }) .collect(), + extensions_by_version: versioned_extensions_metadata.by_version, + extensions_in_versions: versioned_extensions_metadata.in_versions + .into_iter() + .map(|meta| #scrate::__private::metadata_ir::TransactionExtensionMetadataIR { + identifier: meta.identifier, + ty: meta.ty, + implicit: meta.implicit, + }) + .collect(), }, ty: #scrate::__private::scale_info::meta_type::<#runtime>(), apis: (&rt).runtime_metadata(), diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 483a3dce77f6a..94fec9a316916 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -380,10 +380,12 @@ where } /// Implementation for unchecked extrinsic. -impl> GetDispatchInfo - for UncheckedExtrinsic +impl GetDispatchInfo + for UncheckedExtrinsic where Call: GetDispatchInfo + Dispatchable, + ExtensionV0: TransactionExtension, + sp_runtime::traits::transaction_extension::ExtensionVariant: sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipeline, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -393,10 +395,12 @@ where } /// Implementation for checked extrinsic. -impl> GetDispatchInfo - for CheckedExtrinsic +impl GetDispatchInfo + for CheckedExtrinsic where - Call: GetDispatchInfo, + Call: GetDispatchInfo + Dispatchable, + ExtensionV0: TransactionExtension, + sp_runtime::traits::transaction_extension::ExtensionVariant: sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipeline, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -1536,7 +1540,7 @@ mod extension_weight_tests { // First testcase let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0)); let xt = CheckedExtrinsic { - format: ExtrinsicFormat::Signed(0, ext.clone()), + format: ExtrinsicFormat::<_, _>::Signed(0, ext.clone()), function: call.clone(), }; assert_eq!(xt.extension_weight(), Weight::from_parts(600, 0)); @@ -1551,7 +1555,7 @@ mod extension_weight_tests { // Second testcase let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200)); let xt = CheckedExtrinsic { - format: ExtrinsicFormat::Signed(0, ext), + format: ExtrinsicFormat::<_, _>::Signed(0, ext), function: call.clone(), }; let post_info = xt.apply::(&info, 0).unwrap().unwrap(); @@ -1561,7 +1565,7 @@ mod extension_weight_tests { // Third testcase let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200)); let xt = CheckedExtrinsic { - format: ExtrinsicFormat::Signed(0, ext), + format: ExtrinsicFormat::<_, _>::Signed(0, ext), function: call.clone(), }; let post_info = xt.apply::(&info, 0).unwrap().unwrap(); @@ -1571,7 +1575,7 @@ mod extension_weight_tests { // Fourth testcase let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300)); let xt = CheckedExtrinsic { - format: ExtrinsicFormat::Signed(0, ext), + format: ExtrinsicFormat::<_, _>::Signed(0, ext), function: call.clone(), }; let post_info = xt.apply::(&info, 0).unwrap().unwrap(); diff --git a/substrate/frame/transaction-payment/src/tests.rs b/substrate/frame/transaction-payment/src/tests.rs index bde1bf64728e4..30b49d97e5b80 100644 --- a/substrate/frame/transaction-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/src/tests.rs @@ -281,7 +281,7 @@ fn query_info_and_fee_details_works() { let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); let origin = 111111; let extra = (); - let xt = UncheckedExtrinsic::new_signed(call.clone(), origin, (), extra); + let xt = UncheckedExtrinsic::<_, _, _, _>::new_signed(call.clone(), origin, (), extra); let info = xt.get_dispatch_info(); let ext = xt.encode(); let len = ext.len() as u32; diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index dc01f7eaadb33..1e6fb7668931e 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -114,6 +114,8 @@ mod test { signature_ty: meta_type::<()>(), extra_ty: meta_type::<()>(), extensions: vec![], + extensions_by_version: vec![], + extensions_in_versions: vec![], }, ty: meta_type::<()>(), apis: vec![], diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index a9a19b6e6fc25..fa1347faf37a0 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -181,11 +181,13 @@ pub struct ExtrinsicMetadataIR { /// The type of the outermost Extra/Extensions enum. // TODO: metadata-v16: remove this, the `implicit` type can be found in `extensions::implicit`. pub extra_ty: T::Type, - /// The transaction extensions in the order they appear in the extrinsic. - pub extensions: Vec>, /* TODO TODO: renme extension_v0 - * TODO TODO: - * transaction_extensions_by_version - * and transaction_extensions */ + /// The transaction extensions in the order they appear in the extrinsic for the version 0. + pub extensions: Vec>, + /// The transaction extensions for each version as a list of index in reference to item in + /// `transaction_extensions` field below. + pub extensions_by_version: Vec<(u8, Vec)>, + /// The list of all transaction extensions used. + pub extensions_in_versions: Vec>, } impl IntoPortable for ExtrinsicMetadataIR { @@ -200,6 +202,8 @@ impl IntoPortable for ExtrinsicMetadataIR { signature_ty: registry.register_type(&self.signature_ty), extra_ty: registry.register_type(&self.extra_ty), extensions: registry.map_into_portable(self.extensions), + extensions_by_version: self.extensions_by_version, + extensions_in_versions: registry.map_into_portable(self.extensions_in_versions), } } } diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index e1dfec8cc5433..a6c4addd12f8a 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -21,7 +21,6 @@ use codec::Encode; use sp_core::RuntimeDebug; use sp_weights::Weight; - use super::unchecked_extrinsic::ExtensionVersion; use crate::{ traits::{ @@ -43,7 +42,7 @@ const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// The kind of extrinsic this is, including any fields required of that kind. This is basically /// the full extrinsic except the `Call`. #[derive(PartialEq, Eq, Clone, RuntimeDebug)] -pub enum ExtrinsicFormat { +pub enum ExtrinsicFormat { /// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or /// `ValidateUnsigned`, both deprecated, or alternatively a `ProvideInherent`. Bare, @@ -60,7 +59,7 @@ pub enum ExtrinsicFormat { /// /// This is typically passed into [`traits::Applyable::apply`], which should execute /// [`CheckedExtrinsic::function`], alongside all other bits and bobs. -#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] +#[derive(PartialEq, Eq, Clone, RuntimeDebug)] pub struct CheckedExtrinsic { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). @@ -137,12 +136,12 @@ where } } -impl< - AccountId, - Call: Dispatchable + Encode, - ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersionedTransactionExtensionPipeline, - > CheckedExtrinsic +impl + CheckedExtrinsic +where + Call: Dispatchable, + ExtensionV0: TransactionExtension, + ExtensionVariant: VersionedTransactionExtensionPipeline, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index a2e14ff488aa4..d7236f52f1b6f 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -23,9 +23,9 @@ use crate::{ self, transaction_extension::{ DecodeWithVersion, ExtensionVariant, InvalidVersion, TransactionExtension, - VersionedExtension, VersionedTransactionExtensionPipeline, + VersionedTransactionExtensionPipeline, }, - AsTransactionAuthorizedOrigin, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, + Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, SignaturePayload, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, @@ -239,7 +239,7 @@ pub struct UncheckedExtrinsic< Call, Signature, ExtensionV0, - ExtensionOtherVersions = VersionedExtension<0, ExtensionV0>, + ExtensionOtherVersions = InvalidVersion, > { /// Information regarding the type of extrinsic this is (inherent or transaction) as well as /// associated extension (`Extension`) data if it's a transaction and a possible signature. @@ -339,11 +339,7 @@ impl ) -> Self { Self { preamble: Preamble::Signed(signed, signature, tx_ext), function } } -} -impl - UncheckedExtrinsic -{ /// New instance of an new-school unsigned transaction. /// /// This function is only available for `UncheckedExtrinsic` without multi version extension. @@ -419,7 +415,7 @@ where function: self.function, } }, - Preamble::General(tx_ext) => CheckedExtrinsic { + Preamble::General(_, tx_ext) => CheckedExtrinsic { format: ExtrinsicFormat::General(tx_ext), function: self.function, }, @@ -434,17 +430,16 @@ impl { const VERSIONS: &'static [u8] = &[LEGACY_EXTRINSIC_FORMAT_VERSION, EXTRINSIC_FORMAT_VERSION]; - type TransactionExtensionV0 = ExtensionV0; - type TransactionExtensions = ExtensionVariant; + type TransactionExtensions = ExtensionV0; + type TransactionExtensionsVersions = ExtensionVariant; } -impl< - Address, - Call: Dispatchable + Encode, - Signature, - ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersionedTransactionExtensionPipeline, - > UncheckedExtrinsic +impl + UncheckedExtrinsic +where + Call: Dispatchable, + ExtensionV0: TransactionExtension, + ExtensionVariant: VersionedTransactionExtensionPipeline, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index dcea714ca90f5..adebc3fb3a06f 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -1415,11 +1415,11 @@ pub trait ExtrinsicMetadata { /// By format we mean the encoded representation of the `Extrinsic`. const VERSIONS: &'static [u8]; - /// The transaction extension version 0 attached to this `Extrinsic`. - type TransactionExtensionV0; - - /// All transaction extension versions attached to this `Extrinsic`. + /// The transaction extensions version 0 attached to this `Extrinsic`. type TransactionExtensions; + + /// All version of transaction extensions attached to this `Extrinsic`. + type TransactionExtensionsVersions; } /// Extract the hashing type for a block. diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index d71fa96fbafa4..9cb8f97a6e336 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -54,9 +54,12 @@ pub use dispatch_transaction::DispatchTransaction; /// implication for legacy transactions. const EXTENSION_V0_VERSION: ExtensionVersion = 0; +/// TODO TODO: doc #[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] pub enum ExtensionVariant { + /// TODO TODO: doc V0(ExtensionV0), + /// TODO TODO: doc Other(ExtensionOtherVersions), } @@ -119,8 +122,14 @@ impl< > VersionedTransactionExtensionPipeline for ExtensionVariant where - ::RuntimeOrigin: AsTransactionAuthorizedOrigin, + // TODO TODO: remove this bound: maybe remove the function dispatch transaction from the trait + // and just implement the DispatchTransaction trait for all types + // ::RuntimeOrigin: AsTransactionAuthorizedOrigin, { + // TODO TODO: maybe this can be const. + fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder) { + ExtensionOtherVersions::build_metadata(builder); + } fn weight(&self, call: &Call) -> Weight { match self { ExtensionVariant::V0(ext) => ext.weight(call), @@ -138,12 +147,13 @@ where crate::transaction_validity::ValidTransaction, crate::transaction_validity::TransactionValidityError, > { - match self { - ExtensionVariant::V0(ext) => ext - .validate_only(origin, call, info, len, source, EXTENSION_V0_VERSION) - .map(|x| x.0), - ExtensionVariant::Other(ext) => ext.validate_only(origin, call, info, len, source), - } + todo!(); + // match self { + // ExtensionVariant::V0(ext) => ext + // .validate_only(origin, call, info, len, source, EXTENSION_V0_VERSION) + // .map(|x| x.0), + // ExtensionVariant::Other(ext) => ext.validate_only(origin, call, info, len, source), + // } } fn dispatch_transaction( self, @@ -152,11 +162,12 @@ where info: &DispatchInfoOf, len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { - match self { - ExtensionVariant::V0(ext) => - ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION), - ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), - } + todo!(); + // match self { + // ExtensionVariant::V0(ext) => + // ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION), + // ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), + // } } } /// TODO TODO: doc @@ -168,11 +179,56 @@ pub trait DecodeWithVersion: Sized { ) -> Result; } +/// A type to build the metadata for the transaction extensions. +pub struct VersionedTransactionExtensionsMetadataBuilder { + /// The transaction extensions by version and its list of items as vec of index into the vec + /// below. + pub by_version: Vec<(u8, Vec)>, + /// The list of all transaction extension item used. + pub in_versions: Vec, +} + +impl VersionedTransactionExtensionsMetadataBuilder { + /// Create a new empty metadata builder. + pub fn new() -> Self { + Self { by_version: Vec::new(), in_versions: Vec::new() } + } + + /// A function to add a versioned transaction extension to the metadata builder. + pub fn push_versioned_extension( + &mut self, + ext_version: u8, + ext_items: Vec, + ) { + debug_assert!( + self.by_version.iter().all(|(v, _)| *v != ext_version), + "Duplicate definition for transaction extension version: {}", ext_version + ); + + let mut ext_item_indices = Vec::with_capacity(ext_items.len()); + for ext_item in ext_items { + let ext_item_index = match self.in_versions.iter().position(|ext| ext.identifier == ext_item.identifier) { + Some(index) => index, + None => { + self.in_versions.push(ext_item); + self.in_versions.len() - 1 + } + }; + ext_item_indices.push(ext_item_index as u32); + } + self.by_version.push((ext_version, ext_item_indices)); + } + +} + /// TODO TODO: doc // TODO TODO: or maybe name it DispatchTransactionWithExtensionVersion pub trait VersionedTransactionExtensionPipeline: Encode + DecodeWithVersion + Debug + StaticTypeInfo + Send + Sync + Clone { + /// TODO TODO: doc + fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder); + /// TODO TODO: doc fn validate_only( &self, @@ -280,6 +336,9 @@ impl DecodeWithVersion for InvalidVersion { } impl VersionedTransactionExtensionPipeline for InvalidVersion { + fn build_metadata(_builder: &mut VersionedTransactionExtensionsMetadataBuilder) { + // Do nothing. + } fn weight(&self, _call: &Call) -> Weight { Weight::zero() } @@ -342,6 +401,10 @@ where A: VersionedTransactionExtensionPipeline + MultiVersionItem, B: VersionedTransactionExtensionPipeline + MultiVersionItem, { + fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder) { + A::build_metadata(builder); + B::build_metadata(builder); + } fn weight(&self, call: &Call) -> Weight { match self { MultiVersion::A(a) => a.weight(call), @@ -381,6 +444,9 @@ impl< Extension: TransactionExtension, > VersionedTransactionExtensionPipeline for VersionedExtension { + fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder) { + builder.push_versioned_extension(VERSION, Extension::metadata()); + } fn weight(&self, call: &Call) -> Weight { self.extension.weight(call) } From 06da89ba208986fa68971246dcbb9a9ba4869315 Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 18 Dec 2024 12:30:03 +0900 Subject: [PATCH 09/56] Structure done: todo: renames and format --- substrate/bin/node/testing/src/bench.rs | 2 +- substrate/bin/node/testing/src/keyring.rs | 2 +- substrate/frame/support/src/dispatch.rs | 4 +- .../runtime/src/generic/checked_extrinsic.rs | 3 +- .../src/generic/unchecked_extrinsic.rs | 37 +++--- .../src/traits/transaction_extension/mod.rs | 113 +++++++++++++++--- 6 files changed, 125 insertions(+), 36 deletions(-) diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index a1c46e112f9df..4cb8603cb09ca 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -602,7 +602,7 @@ impl BenchKeyring { } .into(), ExtrinsicFormat::General(tx_ext) => generic::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::General(todo!(), tx_ext), + preamble: sp_runtime::generic::Preamble::General(tx_ext), function: xt.function, } .into(), diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index b7ce8ad036792..f00876049c952 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -135,7 +135,7 @@ pub fn sign( } .into(), ExtrinsicFormat::General(tx_ext) => generic::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::General(todo!(), tx_ext), + preamble: sp_runtime::generic::Preamble::General(tx_ext), function: xt.function, } .into(), diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 94fec9a316916..591707801d9b0 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -385,7 +385,7 @@ impl GetDispatchI where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::transaction_extension::ExtensionVariant: sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipeline, + sp_runtime::traits::transaction_extension::ExtensionVariant: sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipelineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -400,7 +400,7 @@ impl GetDispatchInfo where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::transaction_extension::ExtensionVariant: sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipeline, + sp_runtime::traits::transaction_extension::ExtensionVariant: sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipelineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index a6c4addd12f8a..58b6909ab3f8d 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -28,6 +28,7 @@ use crate::{ transaction_extension::{ ExtensionVariant, InvalidVersion, TransactionExtension, VersionedTransactionExtensionPipeline, + VersionedTransactionExtensionPipelineWeight, }, AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned, @@ -141,7 +142,7 @@ impl where Call: Dispatchable, ExtensionV0: TransactionExtension, - ExtensionVariant: VersionedTransactionExtensionPipeline, + ExtensionVariant: VersionedTransactionExtensionPipelineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index d7236f52f1b6f..f331b3dc627a0 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -24,6 +24,8 @@ use crate::{ transaction_extension::{ DecodeWithVersion, ExtensionVariant, InvalidVersion, TransactionExtension, VersionedTransactionExtensionPipeline, + VersionedTransactionExtensionPipelineWeight, + VersionedTransactionExtensionPipelineVersion, }, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, SignaturePayload, @@ -75,7 +77,7 @@ impl SignaturePaylo /// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and /// holds any necessary specialized data. #[derive(Eq, PartialEq, Clone)] -pub enum Preamble { +pub enum Preamble { // TODO TODO: if we bounds version trait then we can get rid of the ExtensionVersion field /// An extrinsic without a signature or any extension. This means it's either an inherent or /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with /// the general transaction which is without a signature but does have an extension). @@ -89,7 +91,7 @@ pub enum Preamble), + General(ExtensionVariant), } const VERSION_MASK: u8 = 0b0011_1111; @@ -130,7 +132,7 @@ where ext_version, input, )?; - Self::General(ext_version, ext) + Self::General(ext) }, (_, _) => return Err("Invalid transaction version".into()), }; @@ -145,7 +147,7 @@ where Address: Encode, Signature: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode, + ExtensionOtherVersions: Encode + VersionedTransactionExtensionPipelineVersion, { fn size_hint(&self) -> usize { match &self { @@ -155,9 +157,8 @@ where .saturating_add(address.size_hint()) .saturating_add(signature.size_hint()) .saturating_add(ext.size_hint()), - Preamble::General(ext_version, ext) => EXTRINSIC_FORMAT_VERSION + Preamble::General(ext) => EXTRINSIC_FORMAT_VERSION .size_hint() - .saturating_add(ext_version.size_hint()) .saturating_add(ext.size_hint()), } } @@ -173,9 +174,9 @@ where signature.encode_to(dest); ext.encode_to(dest); }, - Preamble::General(ext_version, ext) => { + Preamble::General(ext) => { (EXTRINSIC_FORMAT_VERSION | GENERAL_EXTRINSIC).encode_to(dest); - ext_version.encode_to(dest); + ext.version().encode_to(dest); ext.encode_to(dest); }, } @@ -205,8 +206,8 @@ where match self { Self::Bare(_) => write!(f, "Bare"), Self::Signed(address, _, tx_ext) => write!(f, "Signed({:?}, {:?})", address, tx_ext), - Self::General(ext_version, tx_ext) => - write!(f, "General({:?}, {:?})", ext_version, tx_ext), + Self::General(tx_ext) => + write!(f, "General({:?})", tx_ext), } } } @@ -345,7 +346,7 @@ impl /// This function is only available for `UncheckedExtrinsic` without multi version extension. pub fn new_transaction(function: Call, tx_ext: ExtensionV0) -> Self { Self { - preamble: Preamble::General(EXTENSION_V0_VERSION, ExtensionVariant::V0(tx_ext)), + preamble: Preamble::General(ExtensionVariant::V0(tx_ext)), function, } } @@ -393,7 +394,7 @@ where let (function, tx_ext, _) = raw_payload.deconstruct(); CheckedExtrinsic { format: ExtrinsicFormat::Signed(signed, tx_ext), function } }, - Preamble::General(_ext_version, tx_ext) => CheckedExtrinsic { + Preamble::General(tx_ext) => CheckedExtrinsic { format: ExtrinsicFormat::General(tx_ext), function: self.function, }, @@ -415,7 +416,7 @@ where function: self.function, } }, - Preamble::General(_, tx_ext) => CheckedExtrinsic { + Preamble::General(tx_ext) => CheckedExtrinsic { format: ExtrinsicFormat::General(tx_ext), function: self.function, }, @@ -439,7 +440,9 @@ impl where Call: Dispatchable, ExtensionV0: TransactionExtension, - ExtensionVariant: VersionedTransactionExtensionPipeline, + // TODO TODO: redo the bound directly on the generic used to make it clearer that it is + // implemented on AlwaysInvalid + ExtensionVariant: VersionedTransactionExtensionPipelineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. @@ -447,7 +450,7 @@ where match &self.preamble { Preamble::Bare(_) => Weight::zero(), Preamble::Signed(_, _, ext) => ext.weight(&self.function), - Preamble::General(_, ext) => ext.weight(&self.function), + Preamble::General(ext) => ext.weight(&self.function), } } } @@ -523,7 +526,7 @@ impl< Signature: Encode, Call: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode, + ExtensionOtherVersions: Encode + VersionedTransactionExtensionPipelineVersion, > serde::Serialize for UncheckedExtrinsic { @@ -622,7 +625,7 @@ where Signature: Encode, Call: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode, + ExtensionOtherVersions: Encode + VersionedTransactionExtensionPipelineVersion, { fn from( extrinsic: UncheckedExtrinsic< diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index 9cb8f97a6e336..0d56eb431d678 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -63,6 +63,15 @@ pub enum ExtensionVariant { Other(ExtensionOtherVersions), } +impl VersionedTransactionExtensionPipelineVersion for ExtensionVariant { + fn version(&self) -> u8 { + match self { + ExtensionVariant::V0(_) => EXTENSION_V0_VERSION, + ExtensionVariant::Other(ext) => ext.version(), + } + } +} + impl Encode for ExtensionVariant { @@ -115,6 +124,10 @@ impl DecodeWithV } } +pub trait VersionedTransactionExtensionPipelineWeight { + fn weight(&self, call: &Call) -> Weight; +} + impl< Call: Dispatchable + Encode, ExtensionV0: TransactionExtension, @@ -124,7 +137,7 @@ impl< where // TODO TODO: remove this bound: maybe remove the function dispatch transaction from the trait // and just implement the DispatchTransaction trait for all types - // ::RuntimeOrigin: AsTransactionAuthorizedOrigin, + ::RuntimeOrigin: AsTransactionAuthorizedOrigin, { // TODO TODO: maybe this can be const. fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder) { @@ -147,13 +160,12 @@ where crate::transaction_validity::ValidTransaction, crate::transaction_validity::TransactionValidityError, > { - todo!(); - // match self { - // ExtensionVariant::V0(ext) => ext - // .validate_only(origin, call, info, len, source, EXTENSION_V0_VERSION) - // .map(|x| x.0), - // ExtensionVariant::Other(ext) => ext.validate_only(origin, call, info, len, source), - // } + match self { + ExtensionVariant::V0(ext) => ext + .validate_only(origin, call, info, len, source, EXTENSION_V0_VERSION) + .map(|x| x.0), + ExtensionVariant::Other(ext) => ext.validate_only(origin, call, info, len, source), + } } fn dispatch_transaction( self, @@ -162,14 +174,29 @@ where info: &DispatchInfoOf, len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { - todo!(); - // match self { - // ExtensionVariant::V0(ext) => - // ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION), - // ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), - // } + match self { + ExtensionVariant::V0(ext) => + ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION), + ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), + } } } + +impl< + Call: Dispatchable + Encode, + ExtensionV0: TransactionExtension, + ExtensionOtherVersions: VersionedTransactionExtensionPipelineWeight, + > VersionedTransactionExtensionPipelineWeight + for ExtensionVariant +{ + fn weight(&self, call: &Call) -> Weight { + match self { + ExtensionVariant::V0(ext) => ext.weight(call), + ExtensionVariant::Other(ext) => ext.weight(call), + } + } +} + /// TODO TODO: doc pub trait DecodeWithVersion: Sized { /// TODO TODO: doc @@ -279,6 +306,17 @@ impl DecodeWithVersion } } +impl VersionedTransactionExtensionPipelineVersion + for MultiVersion +{ + fn version(&self) -> u8 { + match self { + MultiVersion::A(a) => a.version(), + MultiVersion::B(b) => b.version(), + } + } +} + impl Encode for MultiVersion { fn size_hint(&self) -> usize { match self { @@ -363,6 +401,28 @@ impl VersionedTransactionExtensionPipeline for Invalid } } +pub trait VersionedTransactionExtensionPipelineVersion { + fn version(&self) -> u8; +} + +impl VersionedTransactionExtensionPipelineVersion for InvalidVersion { + fn version(&self) -> u8 { + 0 + } +} + +impl VersionedTransactionExtensionPipelineVersion for VersionedExtension { + fn version(&self) -> u8 { + VERSION + } +} + +impl VersionedTransactionExtensionPipelineWeight for InvalidVersion { + fn weight(&self, call: &Call) -> Weight { + Weight::zero() + } +} + /// TODO TODO: doc pub trait MultiVersionItem { /// TODO TODO: doc @@ -396,6 +456,19 @@ impl VersionedTransactionExtensionPipelineWeight for MultiVersion +where + A: VersionedTransactionExtensionPipelineWeight + MultiVersionItem, + B: VersionedTransactionExtensionPipelineWeight + MultiVersionItem, +{ + fn weight(&self, call: &Call) -> Weight { + match self { + MultiVersion::A(a) => a.weight(call), + MultiVersion::B(b) => b.weight(call), + } + } +} + impl VersionedTransactionExtensionPipeline for MultiVersion where A: VersionedTransactionExtensionPipeline + MultiVersionItem, @@ -473,6 +546,18 @@ impl< } } +impl< + const VERSION: u8, + Call: Dispatchable, + Extension: TransactionExtension, + > VersionedTransactionExtensionPipelineWeight for VersionedExtension +{ + fn weight(&self, call: &Call) -> Weight { + self.extension.weight(call) + } +} + + /// Shortcut for the result value of the `validate` function. pub type ValidateResult = Result<(ValidTransaction, Val, DispatchOriginOf), TransactionValidityError>; From cfddfa111a86379982881c9a19b785d923255fa7 Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 23 Dec 2024 19:32:23 +0900 Subject: [PATCH 10/56] renames --- substrate/frame/revive/src/evm/runtime.rs | 6 +- .../src/construct_runtime/expand/metadata.rs | 5 +- substrate/frame/support/src/dispatch.rs | 10 +- .../runtime/src/generic/checked_extrinsic.rs | 15 +- .../src/generic/unchecked_extrinsic.rs | 35 ++- .../src/traits/transaction_extension/mod.rs | 204 +++++++++--------- 6 files changed, 141 insertions(+), 134 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 9608c53332f6e..c7ddac2ad0ece 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -99,7 +99,11 @@ impl ExtrinsicMetadata E::Extension, >::VERSIONS; type TransactionExtensions = E::Extension; - type TransactionExtensionsVersions = sp_runtime::traits::transaction_extension::ExtensionVariant; + type TransactionExtensionsVersions = + sp_runtime::traits::transaction_extension::ExtensionVariant< + E::Extension, + sp_runtime::traits::transaction_extension::InvalidVersion, + >; } impl ExtrinsicCall diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index 5d58697312ad1..f5103a9778144 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -116,14 +116,15 @@ pub fn expand_runtime_metadata( use #scrate::__private::metadata_ir::InternalImplRuntimeApis; - let mut versioned_extensions_metadata = #scrate::sp_runtime::traits::transaction_extension::VersionedTransactionExtensionsMetadataBuilder::new(); + let mut versioned_extensions_metadata = + #scrate::sp_runtime::traits::transaction_extension::VersTxExtLineMetadataBuilder::new(); < < #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata >::TransactionExtensionsVersions as - #scrate::sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipeline::< + #scrate::sp_runtime::traits::transaction_extension::VersTxExtLine::< <#runtime as #system_path::Config>::RuntimeCall > >::build_metadata(&mut versioned_extensions_metadata); diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 591707801d9b0..7edb3be8f7b57 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -385,7 +385,10 @@ impl GetDispatchI where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::transaction_extension::ExtensionVariant: sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipelineWeight, + sp_runtime::traits::transaction_extension::ExtensionVariant< + ExtensionV0, + ExtensionOtherVersions, + >: sp_runtime::traits::transaction_extension::VersTxExtLineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -400,7 +403,10 @@ impl GetDispatchInfo where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::transaction_extension::ExtensionVariant: sp_runtime::traits::transaction_extension::VersionedTransactionExtensionPipelineWeight, + sp_runtime::traits::transaction_extension::ExtensionVariant< + ExtensionV0, + ExtensionOtherVersions, + >: sp_runtime::traits::transaction_extension::VersTxExtLineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 58b6909ab3f8d..92fe4cfb9be3c 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -18,23 +18,22 @@ //! Generic implementation of an extrinsic that has passed the verification //! stage. -use codec::Encode; -use sp_core::RuntimeDebug; -use sp_weights::Weight; use super::unchecked_extrinsic::ExtensionVersion; use crate::{ traits::{ self, transaction_extension::{ - ExtensionVariant, InvalidVersion, TransactionExtension, - VersionedTransactionExtensionPipeline, - VersionedTransactionExtensionPipelineWeight, + ExtensionVariant, InvalidVersion, TransactionExtension, VersTxExtLine, + VersTxExtLineWeight, }, AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned, }, transaction_validity::{TransactionSource, TransactionValidity}, }; +use codec::Encode; +use sp_core::RuntimeDebug; +use sp_weights::Weight; /// Version 0 of the transaction extension version used to construct the inherited /// implication for legacy transactions. @@ -76,7 +75,7 @@ where AccountId: Member + MaybeDisplay, Call: Member + Dispatchable + Encode, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersionedTransactionExtensionPipeline, + ExtensionOtherVersions: VersTxExtLine, RuntimeOrigin: From> + AsTransactionAuthorizedOrigin, { type Call = Call; @@ -142,7 +141,7 @@ impl where Call: Dispatchable, ExtensionV0: TransactionExtension, - ExtensionVariant: VersionedTransactionExtensionPipelineWeight, + ExtensionVariant: VersTxExtLineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index f331b3dc627a0..a2c7c0a2e0435 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -23,12 +23,10 @@ use crate::{ self, transaction_extension::{ DecodeWithVersion, ExtensionVariant, InvalidVersion, TransactionExtension, - VersionedTransactionExtensionPipeline, - VersionedTransactionExtensionPipelineWeight, - VersionedTransactionExtensionPipelineVersion, + VersTxExtLineVersion, VersTxExtLineWeight, }, - Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, - IdentifyAccount, MaybeDisplay, Member, SignaturePayload, + Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, + Member, SignaturePayload, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, @@ -59,9 +57,6 @@ pub const EXTRINSIC_FORMAT_VERSION: ExtrinsicVersion = 5; /// compatibility reasons. It will be deprecated in favor of v5 extrinsics and an inherent/general /// transaction model. pub const LEGACY_EXTRINSIC_FORMAT_VERSION: ExtrinsicVersion = 4; -/// Version 0 of the transaction extension version used to construct the inherited -/// implication for legacy transactions. -const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// The `SignaturePayload` of `UncheckedExtrinsic`. pub type UncheckedSignaturePayload = (Address, Signature, Extension); @@ -77,7 +72,8 @@ impl SignaturePaylo /// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and /// holds any necessary specialized data. #[derive(Eq, PartialEq, Clone)] -pub enum Preamble { // TODO TODO: if we bounds version trait then we can get rid of the ExtensionVersion field +pub enum Preamble { + // TODO TODO: if we bounds version trait then we can get rid of the ExtensionVersion field /// An extrinsic without a signature or any extension. This means it's either an inherent or /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with /// the general transaction which is without a signature but does have an extension). @@ -147,7 +143,7 @@ where Address: Encode, Signature: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode + VersionedTransactionExtensionPipelineVersion, + ExtensionOtherVersions: Encode + VersTxExtLineVersion, { fn size_hint(&self) -> usize { match &self { @@ -157,9 +153,8 @@ where .saturating_add(address.size_hint()) .saturating_add(signature.size_hint()) .saturating_add(ext.size_hint()), - Preamble::General(ext) => EXTRINSIC_FORMAT_VERSION - .size_hint() - .saturating_add(ext.size_hint()), + Preamble::General(ext) => + EXTRINSIC_FORMAT_VERSION.size_hint().saturating_add(ext.size_hint()), } } @@ -206,8 +201,7 @@ where match self { Self::Bare(_) => write!(f, "Bare"), Self::Signed(address, _, tx_ext) => write!(f, "Signed({:?}, {:?})", address, tx_ext), - Self::General(tx_ext) => - write!(f, "General({:?})", tx_ext), + Self::General(tx_ext) => write!(f, "General({:?})", tx_ext), } } } @@ -345,10 +339,7 @@ impl /// /// This function is only available for `UncheckedExtrinsic` without multi version extension. pub fn new_transaction(function: Call, tx_ext: ExtensionV0) -> Self { - Self { - preamble: Preamble::General(ExtensionVariant::V0(tx_ext)), - function, - } + Self { preamble: Preamble::General(ExtensionVariant::V0(tx_ext)), function } } } @@ -442,7 +433,7 @@ where ExtensionV0: TransactionExtension, // TODO TODO: redo the bound directly on the generic used to make it clearer that it is // implemented on AlwaysInvalid - ExtensionVariant: VersionedTransactionExtensionPipelineWeight, + ExtensionVariant: VersTxExtLineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. @@ -526,7 +517,7 @@ impl< Signature: Encode, Call: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode + VersionedTransactionExtensionPipelineVersion, + ExtensionOtherVersions: Encode + VersTxExtLineVersion, > serde::Serialize for UncheckedExtrinsic { @@ -625,7 +616,7 @@ where Signature: Encode, Call: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode + VersionedTransactionExtensionPipelineVersion, + ExtensionOtherVersions: Encode + VersTxExtLineVersion, { fn from( extrinsic: UncheckedExtrinsic< diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index 0d56eb431d678..a4db3735cd91e 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -54,16 +54,23 @@ pub use dispatch_transaction::DispatchTransaction; /// implication for legacy transactions. const EXTENSION_V0_VERSION: ExtensionVersion = 0; -/// TODO TODO: doc +/// A versioned transaction extension pipeline defined with 2 variants: one for the version 0 and +/// one for other versions. +/// +/// The generic `ExtensionOtherVersions` must not re-define a transaction extension pipeline for the +/// version 0, it will be ignored and overwritten by `ExtensionV0`. +/// TODO TODO: find good name. or keep it private anyway. #[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] pub enum ExtensionVariant { - /// TODO TODO: doc + /// A transaction extension pipeline for the version 0. V0(ExtensionV0), - /// TODO TODO: doc + /// A transaction extension pipeline for other versions. Other(ExtensionOtherVersions), } -impl VersionedTransactionExtensionPipelineVersion for ExtensionVariant { +impl VersTxExtLineVersion + for ExtensionVariant +{ fn version(&self) -> u8 { match self { ExtensionVariant::V0(_) => EXTENSION_V0_VERSION, @@ -124,31 +131,28 @@ impl DecodeWithV } } -pub trait VersionedTransactionExtensionPipelineWeight { +/// The weight for an instance of a versioned transaction extension pipeline and a call. +/// +/// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to +/// rely only on it without bounding the whole trait [`VersTxExtLine`]. This is used by +/// [`crate::generic::UncheckedExtrinsic`] to be backward compatible with its previous version. +pub trait VersTxExtLineWeight { + /// Return the pre dispatch weight for the given versioned transaction extension pipeline and + /// call. fn weight(&self, call: &Call) -> Weight; } impl< Call: Dispatchable + Encode, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersionedTransactionExtensionPipeline, - > VersionedTransactionExtensionPipeline - for ExtensionVariant + ExtensionOtherVersions: VersTxExtLine, + > VersTxExtLine for ExtensionVariant where - // TODO TODO: remove this bound: maybe remove the function dispatch transaction from the trait - // and just implement the DispatchTransaction trait for all types ::RuntimeOrigin: AsTransactionAuthorizedOrigin, { - // TODO TODO: maybe this can be const. - fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder) { + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { ExtensionOtherVersions::build_metadata(builder); } - fn weight(&self, call: &Call) -> Weight { - match self { - ExtensionVariant::V0(ext) => ext.weight(call), - ExtensionVariant::Other(ext) => ext.weight(call), - } - } fn validate_only( &self, origin: super::DispatchOriginOf, @@ -185,9 +189,8 @@ where impl< Call: Dispatchable + Encode, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersionedTransactionExtensionPipelineWeight, - > VersionedTransactionExtensionPipelineWeight - for ExtensionVariant + ExtensionOtherVersions: VersTxExtLineWeight, + > VersTxExtLineWeight for ExtensionVariant { fn weight(&self, call: &Call) -> Weight { match self { @@ -197,25 +200,25 @@ impl< } } -/// TODO TODO: doc +/// A type that can be decoded from a specific version and a [`codec::Input`]. pub trait DecodeWithVersion: Sized { - /// TODO TODO: doc + /// Decode the type from the given version and input. fn decode_with_version( extension_version: u8, input: &mut I, ) -> Result; } -/// A type to build the metadata for the transaction extensions. -pub struct VersionedTransactionExtensionsMetadataBuilder { - /// The transaction extensions by version and its list of items as vec of index into the vec - /// below. +/// A type to build the metadata for the versioned transaction extension pipeline. +pub struct VersTxExtLineMetadataBuilder { + /// The transaction extension pipeline by version and its list of items as vec of index into + /// other field `in_versions`. pub by_version: Vec<(u8, Vec)>, /// The list of all transaction extension item used. pub in_versions: Vec, } -impl VersionedTransactionExtensionsMetadataBuilder { +impl VersTxExtLineMetadataBuilder { /// Create a new empty metadata builder. pub fn new() -> Self { Self { by_version: Vec::new(), in_versions: Vec::new() } @@ -229,34 +232,45 @@ impl VersionedTransactionExtensionsMetadataBuilder { ) { debug_assert!( self.by_version.iter().all(|(v, _)| *v != ext_version), - "Duplicate definition for transaction extension version: {}", ext_version + "Duplicate definition for transaction extension version: {}", + ext_version ); let mut ext_item_indices = Vec::with_capacity(ext_items.len()); for ext_item in ext_items { - let ext_item_index = match self.in_versions.iter().position(|ext| ext.identifier == ext_item.identifier) { - Some(index) => index, - None => { - self.in_versions.push(ext_item); - self.in_versions.len() - 1 - } - }; + let ext_item_index = + match self.in_versions.iter().position(|ext| ext.identifier == ext_item.identifier) + { + Some(index) => index, + None => { + self.in_versions.push(ext_item); + self.in_versions.len() - 1 + }, + }; ext_item_indices.push(ext_item_index as u32); } self.by_version.push((ext_version, ext_item_indices)); } - } -/// TODO TODO: doc -// TODO TODO: or maybe name it DispatchTransactionWithExtensionVersion -pub trait VersionedTransactionExtensionPipeline: - Encode + DecodeWithVersion + Debug + StaticTypeInfo + Send + Sync + Clone +/// A versioned transaction extension pipeline. +/// +/// This defines multiple version of a transaction extensions pipeline. +pub trait VersTxExtLine: + Encode + + DecodeWithVersion + + Debug + + StaticTypeInfo + + Send + + Sync + + Clone + + VersTxExtLineWeight + + VersTxExtLineVersion { - /// TODO TODO: doc - fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder); + /// Build the metadata for the versioned transaction extension pipeline. + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder); - /// TODO TODO: doc + /// Validate a transaction. fn validate_only( &self, origin: DispatchOriginOf, @@ -266,7 +280,7 @@ pub trait VersionedTransactionExtensionPipeline: source: TransactionSource, ) -> Result; - /// TODO TODO: doc + /// Dispatch a transaction. fn dispatch_transaction( self, origin: DispatchOriginOf, @@ -274,17 +288,16 @@ pub trait VersionedTransactionExtensionPipeline: info: &DispatchInfoOf, len: usize, ) -> crate::ApplyExtrinsicResultWithInfo>; - /// TODO TODO: doc - fn weight(&self, call: &Call) -> Weight; } -/// TODO TODO: doc +/// A transaction extension pipeline defined for a single version. #[derive(Encode, Clone, Debug, TypeInfo)] -pub struct VersionedExtension { - extension: Extension, +pub struct TxExtLineAtVers { + /// The transaction extension pipeline for the version `VERSION`. + pub extension: Extension, } -impl VersionedExtension { +impl TxExtLineAtVers { /// Create a new versioned extension. pub fn new(extension: Extension) -> Self { Self { extension } @@ -292,23 +305,21 @@ impl VersionedExtension { } impl DecodeWithVersion - for VersionedExtension + for TxExtLineAtVers { fn decode_with_version( extension_version: u8, input: &mut I, ) -> Result { if extension_version == VERSION { - Ok(VersionedExtension { extension: Extension::decode(input)? }) + Ok(TxExtLineAtVers { extension: Extension::decode(input)? }) } else { Err(codec::Error::from("Invalid extension version")) } } } -impl VersionedTransactionExtensionPipelineVersion - for MultiVersion -{ +impl VersTxExtLineVersion for MultiVersion { fn version(&self) -> u8 { match self { MultiVersion::A(a) => a.version(), @@ -350,17 +361,23 @@ impl Encode for MultiVersion { } } -/// TODO TODO: doc +/// An implementation of [`VersTxExtLine`] that consider any version invalid. #[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] pub struct InvalidVersion; -/// TODO TODO: doc +/// An implementation of [`VersTxExtLine`] that aggregated multiple transaction extension pipeline +/// of different versions. +/// +/// Each variant have its own version, duplicated version must be avoided, only the first used +/// version will be effective other duplicated version will be ignored. +/// +/// TODO TODO: example #[allow(private_interfaces)] #[derive(Clone, Debug, TypeInfo)] pub enum MultiVersion { - /// TODO TODO: doc + /// The first aggregated transaction extension pipeline of a specific version. A(A), - /// TODO TODO: doc + /// The second aggregated transaction extension pipeline of a specific version. B(B), } @@ -373,13 +390,10 @@ impl DecodeWithVersion for InvalidVersion { } } -impl VersionedTransactionExtensionPipeline for InvalidVersion { - fn build_metadata(_builder: &mut VersionedTransactionExtensionsMetadataBuilder) { +impl VersTxExtLine for InvalidVersion { + fn build_metadata(_builder: &mut VersTxExtLineMetadataBuilder) { // Do nothing. } - fn weight(&self, _call: &Call) -> Weight { - Weight::zero() - } fn validate_only( &self, _origin: DispatchOriginOf, @@ -401,40 +415,45 @@ impl VersionedTransactionExtensionPipeline for Invalid } } -pub trait VersionedTransactionExtensionPipelineVersion { +/// The version for an instance of a versioned transaction extension pipeline. +/// +/// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to +/// rely only on it without bounding the whole trait [`VersTxExtLine`]. This is used by +/// [`crate::generic::UncheckedExtrinsic`] to be backward compatible with its previous version. +pub trait VersTxExtLineVersion { + /// Return the version for the given versioned transaction extension pipeline. fn version(&self) -> u8; } -impl VersionedTransactionExtensionPipelineVersion for InvalidVersion { +impl VersTxExtLineVersion for InvalidVersion { fn version(&self) -> u8 { 0 } } -impl VersionedTransactionExtensionPipelineVersion for VersionedExtension { +impl VersTxExtLineVersion for TxExtLineAtVers { fn version(&self) -> u8 { VERSION } } -impl VersionedTransactionExtensionPipelineWeight for InvalidVersion { - fn weight(&self, call: &Call) -> Weight { +impl VersTxExtLineWeight for InvalidVersion { + fn weight(&self, _call: &Call) -> Weight { Weight::zero() } } -/// TODO TODO: doc +/// An item in [`MultiVersion`]. It represents a transaction extension pipeline of a specific +/// single version. pub trait MultiVersionItem { - /// TODO TODO: doc + /// The version of the transaction extension pipeline. const VERSION: Option; } -impl MultiVersionItem for VersionedExtension { +impl MultiVersionItem for TxExtLineAtVers { const VERSION: Option = Some(VERSION); } -// TODO TODO: think about how to define the bare extrinsic transaction extension, and how to define -// the signed extrinsic transaction extension. impl MultiVersionItem for InvalidVersion { const VERSION: Option = None; } @@ -456,10 +475,10 @@ impl VersionedTransactionExtensionPipelineWeight for MultiVersion +impl VersTxExtLineWeight for MultiVersion where - A: VersionedTransactionExtensionPipelineWeight + MultiVersionItem, - B: VersionedTransactionExtensionPipelineWeight + MultiVersionItem, + A: VersTxExtLineWeight + MultiVersionItem, + B: VersTxExtLineWeight + MultiVersionItem, { fn weight(&self, call: &Call) -> Weight { match self { @@ -469,21 +488,15 @@ where } } -impl VersionedTransactionExtensionPipeline for MultiVersion +impl VersTxExtLine for MultiVersion where - A: VersionedTransactionExtensionPipeline + MultiVersionItem, - B: VersionedTransactionExtensionPipeline + MultiVersionItem, + A: VersTxExtLine + MultiVersionItem, + B: VersTxExtLine + MultiVersionItem, { - fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder) { + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { A::build_metadata(builder); B::build_metadata(builder); } - fn weight(&self, call: &Call) -> Weight { - match self { - MultiVersion::A(a) => a.weight(call), - MultiVersion::B(b) => b.weight(call), - } - } fn validate_only( &self, origin: DispatchOriginOf, @@ -515,14 +528,11 @@ impl< const VERSION: u8, Call: Dispatchable + Encode, Extension: TransactionExtension, - > VersionedTransactionExtensionPipeline for VersionedExtension + > VersTxExtLine for TxExtLineAtVers { - fn build_metadata(builder: &mut VersionedTransactionExtensionsMetadataBuilder) { + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { builder.push_versioned_extension(VERSION, Extension::metadata()); } - fn weight(&self, call: &Call) -> Weight { - self.extension.weight(call) - } fn validate_only( &self, origin: DispatchOriginOf, @@ -546,18 +556,14 @@ impl< } } -impl< - const VERSION: u8, - Call: Dispatchable, - Extension: TransactionExtension, - > VersionedTransactionExtensionPipelineWeight for VersionedExtension +impl> + VersTxExtLineWeight for TxExtLineAtVers { fn weight(&self, call: &Call) -> Weight { self.extension.weight(call) } } - /// Shortcut for the result value of the `validate` function. pub type ValidateResult = Result<(ValidTransaction, Val, DispatchOriginOf), TransactionValidityError>; From 3aacd46b39d14645e6eca7679bcaace4bb2a01a8 Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 24 Dec 2024 13:17:49 +0900 Subject: [PATCH 11/56] reorganize --- .../src/construct_runtime/expand/metadata.rs | 4 +- substrate/frame/support/src/dispatch.rs | 8 +- .../runtime/src/generic/checked_extrinsic.rs | 10 +- .../src/generic/unchecked_extrinsic.rs | 10 +- .../primitives/runtime/src/traits/mod.rs | 2 + .../src/traits/transaction_extension/mod.rs | 526 +----------------- .../runtime/src/traits/vers_tx_ext/at_vers.rs | 106 ++++ .../runtime/src/traits/vers_tx_ext/invalid.rs | 82 +++ .../runtime/src/traits/vers_tx_ext/mod.rs | 151 +++++ .../runtime/src/traits/vers_tx_ext/multi.rs | 171 ++++++ .../runtime/src/traits/vers_tx_ext/variant.rs | 173 ++++++ 11 files changed, 698 insertions(+), 545 deletions(-) create mode 100644 substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs create mode 100644 substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs create mode 100644 substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs create mode 100644 substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs create mode 100644 substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index f5103a9778144..2b438254a6049 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -117,14 +117,14 @@ pub fn expand_runtime_metadata( let mut versioned_extensions_metadata = - #scrate::sp_runtime::traits::transaction_extension::VersTxExtLineMetadataBuilder::new(); + #scrate::sp_runtime::traits::VersTxExtLineMetadataBuilder::new(); < < #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata >::TransactionExtensionsVersions as - #scrate::sp_runtime::traits::transaction_extension::VersTxExtLine::< + #scrate::sp_runtime::traits::VersTxExtLine::< <#runtime as #system_path::Config>::RuntimeCall > >::build_metadata(&mut versioned_extensions_metadata); diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 7edb3be8f7b57..df823c7ec48ff 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -385,10 +385,10 @@ impl GetDispatchI where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::transaction_extension::ExtensionVariant< + sp_runtime::traits::ExtensionVariant< ExtensionV0, ExtensionOtherVersions, - >: sp_runtime::traits::transaction_extension::VersTxExtLineWeight, + >: sp_runtime::traits::VersTxExtLineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -403,10 +403,10 @@ impl GetDispatchInfo where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::transaction_extension::ExtensionVariant< + sp_runtime::traits::ExtensionVariant< ExtensionV0, ExtensionOtherVersions, - >: sp_runtime::traits::transaction_extension::VersTxExtLineWeight, + >: sp_runtime::traits::VersTxExtLineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 92fe4cfb9be3c..8997efa73abce 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -21,13 +21,9 @@ use super::unchecked_extrinsic::ExtensionVersion; use crate::{ traits::{ - self, - transaction_extension::{ - ExtensionVariant, InvalidVersion, TransactionExtension, VersTxExtLine, - VersTxExtLineWeight, - }, - AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, - MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned, + self, AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, + ExtensionVariant, InvalidVersion, MaybeDisplay, Member, PostDispatchInfoOf, + TransactionExtension, ValidateUnsigned, VersTxExtLine, VersTxExtLineWeight, }, transaction_validity::{TransactionSource, TransactionValidity}, }; diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index a2c7c0a2e0435..36eb79532abd1 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -20,13 +20,9 @@ use crate::{ generic::{CheckedExtrinsic, ExtrinsicFormat}, traits::{ - self, - transaction_extension::{ - DecodeWithVersion, ExtensionVariant, InvalidVersion, TransactionExtension, - VersTxExtLineVersion, VersTxExtLineWeight, - }, - Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, - Member, SignaturePayload, + self, Checkable, DecodeWithVersion, Dispatchable, ExtensionVariant, ExtrinsicLike, + ExtrinsicMetadata, IdentifyAccount, InvalidVersion, MaybeDisplay, Member, SignaturePayload, + TransactionExtension, VersTxExtLineVersion, VersTxExtLineWeight, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index adebc3fb3a06f..7e86e42cfdd7a 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -54,9 +54,11 @@ use std::fmt::Display; use std::str::FromStr; pub mod transaction_extension; +pub mod vers_tx_ext; pub use transaction_extension::{ DispatchTransaction, TransactionExtension, TransactionExtensionMetadata, ValidateResult, }; +pub use vers_tx_ext::*; /// A lazy value. pub trait Lazy { diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index a4db3735cd91e..076815e8c84fc 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -22,21 +22,14 @@ use super::{ PostDispatchInfoOf, RefundWeight, }; use crate::{ - generic::ExtensionVersion, scale_info::{MetaType, StaticTypeInfo}, - traits::AsTransactionAuthorizedOrigin, transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, - ValidTransaction, + TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, }, DispatchResult, }; use codec::{Codec, Decode, Encode}; use impl_trait_for_tuples::impl_for_tuples; -use scale_info::TypeInfo; -use sp_core::RuntimeDebug; -#[doc(hidden)] -pub use sp_std::marker::PhantomData; use sp_std::{self, fmt::Debug, prelude::*}; use sp_weights::Weight; use tuplex::{PopFront, PushBack}; @@ -47,523 +40,6 @@ mod dispatch_transaction; pub use as_transaction_extension::AsTransactionExtension; pub use dispatch_transaction::DispatchTransaction; -// TODO TODO: rewrite the bounds to bounds usage instead of expectation of bounds. -// TODO TODO: implement metadata for Versioned tx ext pipeline - -/// Version 0 of the transaction extension version used to construct the inherited -/// implication for legacy transactions. -const EXTENSION_V0_VERSION: ExtensionVersion = 0; - -/// A versioned transaction extension pipeline defined with 2 variants: one for the version 0 and -/// one for other versions. -/// -/// The generic `ExtensionOtherVersions` must not re-define a transaction extension pipeline for the -/// version 0, it will be ignored and overwritten by `ExtensionV0`. -/// TODO TODO: find good name. or keep it private anyway. -#[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] -pub enum ExtensionVariant { - /// A transaction extension pipeline for the version 0. - V0(ExtensionV0), - /// A transaction extension pipeline for other versions. - Other(ExtensionOtherVersions), -} - -impl VersTxExtLineVersion - for ExtensionVariant -{ - fn version(&self) -> u8 { - match self { - ExtensionVariant::V0(_) => EXTENSION_V0_VERSION, - ExtensionVariant::Other(ext) => ext.version(), - } - } -} - -impl Encode - for ExtensionVariant -{ - fn encode(&self) -> Vec { - match self { - ExtensionVariant::V0(ext) => ext.encode(), - ExtensionVariant::Other(ext) => ext.encode(), - } - } - fn size_hint(&self) -> usize { - match self { - ExtensionVariant::V0(ext) => ext.size_hint(), - ExtensionVariant::Other(ext) => ext.size_hint(), - } - } - fn encode_to(&self, dest: &mut T) { - match self { - ExtensionVariant::V0(ext) => ext.encode_to(dest), - ExtensionVariant::Other(ext) => ext.encode_to(dest), - } - } - fn encoded_size(&self) -> usize { - match self { - ExtensionVariant::V0(ext) => ext.encoded_size(), - ExtensionVariant::Other(ext) => ext.encoded_size(), - } - } - fn using_encoded R>(&self, f: F) -> R { - match self { - ExtensionVariant::V0(ext) => ext.using_encoded(f), - ExtensionVariant::Other(ext) => ext.using_encoded(f), - } - } -} - -impl DecodeWithVersion - for ExtensionVariant -{ - fn decode_with_version( - extension_version: u8, - input: &mut I, - ) -> Result { - match extension_version { - EXTENSION_V0_VERSION => Ok(ExtensionVariant::V0(Decode::decode(input)?)), - _ => Ok(ExtensionVariant::Other(DecodeWithVersion::decode_with_version( - extension_version, - input, - )?)), - } - } -} - -/// The weight for an instance of a versioned transaction extension pipeline and a call. -/// -/// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to -/// rely only on it without bounding the whole trait [`VersTxExtLine`]. This is used by -/// [`crate::generic::UncheckedExtrinsic`] to be backward compatible with its previous version. -pub trait VersTxExtLineWeight { - /// Return the pre dispatch weight for the given versioned transaction extension pipeline and - /// call. - fn weight(&self, call: &Call) -> Weight; -} - -impl< - Call: Dispatchable + Encode, - ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersTxExtLine, - > VersTxExtLine for ExtensionVariant -where - ::RuntimeOrigin: AsTransactionAuthorizedOrigin, -{ - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { - ExtensionOtherVersions::build_metadata(builder); - } - fn validate_only( - &self, - origin: super::DispatchOriginOf, - call: &Call, - info: &DispatchInfoOf, - len: usize, - source: TransactionSource, - ) -> Result< - crate::transaction_validity::ValidTransaction, - crate::transaction_validity::TransactionValidityError, - > { - match self { - ExtensionVariant::V0(ext) => ext - .validate_only(origin, call, info, len, source, EXTENSION_V0_VERSION) - .map(|x| x.0), - ExtensionVariant::Other(ext) => ext.validate_only(origin, call, info, len, source), - } - } - fn dispatch_transaction( - self, - origin: super::DispatchOriginOf, - call: Call, - info: &DispatchInfoOf, - len: usize, - ) -> crate::ApplyExtrinsicResultWithInfo> { - match self { - ExtensionVariant::V0(ext) => - ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION), - ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), - } - } -} - -impl< - Call: Dispatchable + Encode, - ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersTxExtLineWeight, - > VersTxExtLineWeight for ExtensionVariant -{ - fn weight(&self, call: &Call) -> Weight { - match self { - ExtensionVariant::V0(ext) => ext.weight(call), - ExtensionVariant::Other(ext) => ext.weight(call), - } - } -} - -/// A type that can be decoded from a specific version and a [`codec::Input`]. -pub trait DecodeWithVersion: Sized { - /// Decode the type from the given version and input. - fn decode_with_version( - extension_version: u8, - input: &mut I, - ) -> Result; -} - -/// A type to build the metadata for the versioned transaction extension pipeline. -pub struct VersTxExtLineMetadataBuilder { - /// The transaction extension pipeline by version and its list of items as vec of index into - /// other field `in_versions`. - pub by_version: Vec<(u8, Vec)>, - /// The list of all transaction extension item used. - pub in_versions: Vec, -} - -impl VersTxExtLineMetadataBuilder { - /// Create a new empty metadata builder. - pub fn new() -> Self { - Self { by_version: Vec::new(), in_versions: Vec::new() } - } - - /// A function to add a versioned transaction extension to the metadata builder. - pub fn push_versioned_extension( - &mut self, - ext_version: u8, - ext_items: Vec, - ) { - debug_assert!( - self.by_version.iter().all(|(v, _)| *v != ext_version), - "Duplicate definition for transaction extension version: {}", - ext_version - ); - - let mut ext_item_indices = Vec::with_capacity(ext_items.len()); - for ext_item in ext_items { - let ext_item_index = - match self.in_versions.iter().position(|ext| ext.identifier == ext_item.identifier) - { - Some(index) => index, - None => { - self.in_versions.push(ext_item); - self.in_versions.len() - 1 - }, - }; - ext_item_indices.push(ext_item_index as u32); - } - self.by_version.push((ext_version, ext_item_indices)); - } -} - -/// A versioned transaction extension pipeline. -/// -/// This defines multiple version of a transaction extensions pipeline. -pub trait VersTxExtLine: - Encode - + DecodeWithVersion - + Debug - + StaticTypeInfo - + Send - + Sync - + Clone - + VersTxExtLineWeight - + VersTxExtLineVersion -{ - /// Build the metadata for the versioned transaction extension pipeline. - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder); - - /// Validate a transaction. - fn validate_only( - &self, - origin: DispatchOriginOf, - call: &Call, - info: &DispatchInfoOf, - len: usize, - source: TransactionSource, - ) -> Result; - - /// Dispatch a transaction. - fn dispatch_transaction( - self, - origin: DispatchOriginOf, - call: Call, - info: &DispatchInfoOf, - len: usize, - ) -> crate::ApplyExtrinsicResultWithInfo>; -} - -/// A transaction extension pipeline defined for a single version. -#[derive(Encode, Clone, Debug, TypeInfo)] -pub struct TxExtLineAtVers { - /// The transaction extension pipeline for the version `VERSION`. - pub extension: Extension, -} - -impl TxExtLineAtVers { - /// Create a new versioned extension. - pub fn new(extension: Extension) -> Self { - Self { extension } - } -} - -impl DecodeWithVersion - for TxExtLineAtVers -{ - fn decode_with_version( - extension_version: u8, - input: &mut I, - ) -> Result { - if extension_version == VERSION { - Ok(TxExtLineAtVers { extension: Extension::decode(input)? }) - } else { - Err(codec::Error::from("Invalid extension version")) - } - } -} - -impl VersTxExtLineVersion for MultiVersion { - fn version(&self) -> u8 { - match self { - MultiVersion::A(a) => a.version(), - MultiVersion::B(b) => b.version(), - } - } -} - -impl Encode for MultiVersion { - fn size_hint(&self) -> usize { - match self { - MultiVersion::A(a) => a.size_hint(), - MultiVersion::B(b) => b.size_hint(), - } - } - fn encode(&self) -> Vec { - match self { - MultiVersion::A(a) => a.encode(), - MultiVersion::B(b) => b.encode(), - } - } - fn encode_to(&self, dest: &mut T) { - match self { - MultiVersion::A(a) => a.encode_to(dest), - MultiVersion::B(b) => b.encode_to(dest), - } - } - fn encoded_size(&self) -> usize { - match self { - MultiVersion::A(a) => a.encoded_size(), - MultiVersion::B(b) => b.encoded_size(), - } - } - fn using_encoded R>(&self, f: F) -> R { - match self { - MultiVersion::A(a) => a.using_encoded(f), - MultiVersion::B(b) => b.using_encoded(f), - } - } -} - -/// An implementation of [`VersTxExtLine`] that consider any version invalid. -#[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] -pub struct InvalidVersion; - -/// An implementation of [`VersTxExtLine`] that aggregated multiple transaction extension pipeline -/// of different versions. -/// -/// Each variant have its own version, duplicated version must be avoided, only the first used -/// version will be effective other duplicated version will be ignored. -/// -/// TODO TODO: example -#[allow(private_interfaces)] -#[derive(Clone, Debug, TypeInfo)] -pub enum MultiVersion { - /// The first aggregated transaction extension pipeline of a specific version. - A(A), - /// The second aggregated transaction extension pipeline of a specific version. - B(B), -} - -impl DecodeWithVersion for InvalidVersion { - fn decode_with_version( - _extension_version: u8, - _input: &mut I, - ) -> Result { - Err(codec::Error::from("Invalid extension version")) - } -} - -impl VersTxExtLine for InvalidVersion { - fn build_metadata(_builder: &mut VersTxExtLineMetadataBuilder) { - // Do nothing. - } - fn validate_only( - &self, - _origin: DispatchOriginOf, - _call: &Call, - _info: &DispatchInfoOf, - _len: usize, - _source: TransactionSource, - ) -> Result { - Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))) - } - fn dispatch_transaction( - self, - _origin: DispatchOriginOf, - _call: Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> crate::ApplyExtrinsicResultWithInfo> { - Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0)).into()) - } -} - -/// The version for an instance of a versioned transaction extension pipeline. -/// -/// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to -/// rely only on it without bounding the whole trait [`VersTxExtLine`]. This is used by -/// [`crate::generic::UncheckedExtrinsic`] to be backward compatible with its previous version. -pub trait VersTxExtLineVersion { - /// Return the version for the given versioned transaction extension pipeline. - fn version(&self) -> u8; -} - -impl VersTxExtLineVersion for InvalidVersion { - fn version(&self) -> u8 { - 0 - } -} - -impl VersTxExtLineVersion for TxExtLineAtVers { - fn version(&self) -> u8 { - VERSION - } -} - -impl VersTxExtLineWeight for InvalidVersion { - fn weight(&self, _call: &Call) -> Weight { - Weight::zero() - } -} - -/// An item in [`MultiVersion`]. It represents a transaction extension pipeline of a specific -/// single version. -pub trait MultiVersionItem { - /// The version of the transaction extension pipeline. - const VERSION: Option; -} - -impl MultiVersionItem for TxExtLineAtVers { - const VERSION: Option = Some(VERSION); -} - -impl MultiVersionItem for InvalidVersion { - const VERSION: Option = None; -} - -impl - DecodeWithVersion for MultiVersion -{ - fn decode_with_version( - extension_version: u8, - input: &mut I, - ) -> Result { - if A::VERSION == Some(extension_version) { - Ok(MultiVersion::A(A::decode_with_version(extension_version, input)?)) - } else if B::VERSION == Some(extension_version) { - Ok(MultiVersion::B(B::decode_with_version(extension_version, input)?)) - } else { - Err(codec::Error::from("Invalid extension version")) - } - } -} - -impl VersTxExtLineWeight for MultiVersion -where - A: VersTxExtLineWeight + MultiVersionItem, - B: VersTxExtLineWeight + MultiVersionItem, -{ - fn weight(&self, call: &Call) -> Weight { - match self { - MultiVersion::A(a) => a.weight(call), - MultiVersion::B(b) => b.weight(call), - } - } -} - -impl VersTxExtLine for MultiVersion -where - A: VersTxExtLine + MultiVersionItem, - B: VersTxExtLine + MultiVersionItem, -{ - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { - A::build_metadata(builder); - B::build_metadata(builder); - } - fn validate_only( - &self, - origin: DispatchOriginOf, - call: &Call, - info: &DispatchInfoOf, - len: usize, - source: TransactionSource, - ) -> Result { - match self { - MultiVersion::A(a) => a.validate_only(origin, call, info, len, source), - MultiVersion::B(b) => b.validate_only(origin, call, info, len, source), - } - } - fn dispatch_transaction( - self, - origin: DispatchOriginOf, - call: Call, - info: &DispatchInfoOf, - len: usize, - ) -> crate::ApplyExtrinsicResultWithInfo> { - match self { - MultiVersion::A(a) => a.dispatch_transaction(origin, call, info, len), - MultiVersion::B(b) => b.dispatch_transaction(origin, call, info, len), - } - } -} - -impl< - const VERSION: u8, - Call: Dispatchable + Encode, - Extension: TransactionExtension, - > VersTxExtLine for TxExtLineAtVers -{ - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { - builder.push_versioned_extension(VERSION, Extension::metadata()); - } - fn validate_only( - &self, - origin: DispatchOriginOf, - call: &Call, - info: &DispatchInfoOf, - len: usize, - source: TransactionSource, - ) -> Result { - self.extension - .validate_only(origin, call, info, len, source, VERSION) - .map(|x| x.0) - } - fn dispatch_transaction( - self, - origin: DispatchOriginOf, - call: Call, - info: &DispatchInfoOf, - len: usize, - ) -> crate::ApplyExtrinsicResultWithInfo> { - self.extension.dispatch_transaction(origin, call, info, len, VERSION) - } -} - -impl> - VersTxExtLineWeight for TxExtLineAtVers -{ - fn weight(&self, call: &Call) -> Weight { - self.extension.weight(call) - } -} - /// Shortcut for the result value of the `validate` function. pub type ValidateResult = Result<(ValidTransaction, Val, DispatchOriginOf), TransactionValidityError>; diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs new file mode 100644 index 0000000000000..3eaff726aed56 --- /dev/null +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -0,0 +1,106 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Type to define a versioned transaction extension pipeline for a specific version. + +use crate::{ + traits::{ + AsTransactionAuthorizedOrigin, DecodeWithVersion, DispatchInfoOf, DispatchOriginOf, + DispatchTransaction, Dispatchable, PostDispatchInfoOf, TransactionExtension, VersTxExtLine, + VersTxExtLineMetadataBuilder, VersTxExtLineVersion, VersTxExtLineWeight, + }, + transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, +}; +use codec::{Decode, Encode}; +use core::fmt::Debug; +use scale_info::TypeInfo; +use sp_weights::Weight; + +/// A transaction extension pipeline defined for a single version. +#[derive(Encode, Clone, Debug, TypeInfo)] +pub struct TxExtLineAtVers { + /// The transaction extension pipeline for the version `VERSION`. + pub extension: Extension, +} + +impl TxExtLineAtVers { + /// Create a new versioned extension. + pub fn new(extension: Extension) -> Self { + Self { extension } + } +} + +impl DecodeWithVersion + for TxExtLineAtVers +{ + fn decode_with_version( + extension_version: u8, + input: &mut I, + ) -> Result { + if extension_version == VERSION { + Ok(TxExtLineAtVers { extension: Extension::decode(input)? }) + } else { + Err(codec::Error::from("Invalid extension version")) + } + } +} + +impl VersTxExtLineVersion for TxExtLineAtVers { + fn version(&self) -> u8 { + VERSION + } +} + +impl< + const VERSION: u8, + Call: Dispatchable + Encode, + Extension: TransactionExtension, + > VersTxExtLine for TxExtLineAtVers +{ + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { + builder.push_versioned_extension(VERSION, Extension::metadata()); + } + fn validate_only( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result { + self.extension + .validate_only(origin, call, info, len, source, VERSION) + .map(|x| x.0) + } + fn dispatch_transaction( + self, + origin: DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + self.extension.dispatch_transaction(origin, call, info, len, VERSION) + } +} + +impl> + VersTxExtLineWeight for TxExtLineAtVers +{ + fn weight(&self, call: &Call) -> Weight { + self.extension.weight(call) + } +} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs new file mode 100644 index 0000000000000..c2b2c06be82cb --- /dev/null +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -0,0 +1,82 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of versioned transaction extension pipeline that is always invalid. + +use crate::{ + traits::{ + DecodeWithVersion, DispatchInfoOf, DispatchOriginOf, Dispatchable, PostDispatchInfoOf, + VersTxExtLine, VersTxExtLineMetadataBuilder, VersTxExtLineVersion, VersTxExtLineWeight, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction, + }, +}; +use codec::Encode; +use core::fmt::Debug; +use scale_info::TypeInfo; +use sp_weights::Weight; + +/// An implementation of [`VersTxExtLine`] that consider any version invalid. +#[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] +pub struct InvalidVersion; + +impl DecodeWithVersion for InvalidVersion { + fn decode_with_version( + _extension_version: u8, + _input: &mut I, + ) -> Result { + Err(codec::Error::from("Invalid extension version")) + } +} + +impl VersTxExtLine for InvalidVersion { + fn build_metadata(_builder: &mut VersTxExtLineMetadataBuilder) { + // Do nothing. + } + fn validate_only( + &self, + _origin: DispatchOriginOf, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + _source: TransactionSource, + ) -> Result { + Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))) + } + fn dispatch_transaction( + self, + _origin: DispatchOriginOf, + _call: Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0)).into()) + } +} + +impl VersTxExtLineVersion for InvalidVersion { + fn version(&self) -> u8 { + 0 + } +} + +impl VersTxExtLineWeight for InvalidVersion { + fn weight(&self, _call: &Call) -> Weight { + Weight::zero() + } +} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs new file mode 100644 index 0000000000000..1c39349d3f779 --- /dev/null +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -0,0 +1,151 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The traits and primitive types for versioned transaction extension pipelines. + +use crate::{ + scale_info::StaticTypeInfo, + traits::{ + DispatchInfoOf, DispatchOriginOf, Dispatchable, PostDispatchInfoOf, + TransactionExtensionMetadata, + }, + transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, +}; +use alloc::vec::Vec; +use codec::Encode; +use core::fmt::Debug; +use sp_weights::Weight; + +mod at_vers; +mod invalid; +mod multi; +mod variant; +pub use at_vers::*; +pub use invalid::*; +pub use multi::*; +pub use variant::*; + +/// The weight for an instance of a versioned transaction extension pipeline and a call. +/// +/// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to +/// rely only on it without bounding the whole trait [`VersTxExtLine`]. This is used by +/// [`crate::generic::UncheckedExtrinsic`] to be backward compatible with its previous version. +pub trait VersTxExtLineWeight { + /// Return the pre dispatch weight for the given versioned transaction extension pipeline and + /// call. + fn weight(&self, call: &Call) -> Weight; +} + +/// The version for an instance of a versioned transaction extension pipeline. +/// +/// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to +/// rely only on it without bounding the whole trait [`VersTxExtLine`]. This is used by +/// [`crate::generic::UncheckedExtrinsic`] to be backward compatible with its previous version. +pub trait VersTxExtLineVersion { + /// Return the version for the given versioned transaction extension pipeline. + fn version(&self) -> u8; +} + +/// A versioned transaction extension pipeline. +/// +/// This defines multiple version of a transaction extensions pipeline. +pub trait VersTxExtLine: + Encode + + DecodeWithVersion + + Debug + + StaticTypeInfo + + Send + + Sync + + Clone + + VersTxExtLineWeight + + VersTxExtLineVersion +{ + /// Build the metadata for the versioned transaction extension pipeline. + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder); + + /// Validate a transaction. + fn validate_only( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result; + + /// Dispatch a transaction. + fn dispatch_transaction( + self, + origin: DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo>; +} + +/// A type that can be decoded from a specific version and a [`codec::Input`]. +pub trait DecodeWithVersion: Sized { + /// Decode the type from the given version and input. + fn decode_with_version( + extension_version: u8, + input: &mut I, + ) -> Result; +} + +/// A type to build the metadata for the versioned transaction extension pipeline. +pub struct VersTxExtLineMetadataBuilder { + /// The transaction extension pipeline by version and its list of items as vec of index into + /// other field `in_versions`. + pub by_version: Vec<(u8, Vec)>, + /// The list of all transaction extension item used. + pub in_versions: Vec, +} + +impl VersTxExtLineMetadataBuilder { + /// Create a new empty metadata builder. + pub fn new() -> Self { + Self { by_version: Vec::new(), in_versions: Vec::new() } + } + + /// A function to add a versioned transaction extension to the metadata builder. + pub fn push_versioned_extension( + &mut self, + ext_version: u8, + ext_items: Vec, + ) { + debug_assert!( + self.by_version.iter().all(|(v, _)| *v != ext_version), + "Duplicate definition for transaction extension version: {}", + ext_version + ); + + let mut ext_item_indices = Vec::with_capacity(ext_items.len()); + for ext_item in ext_items { + let ext_item_index = + match self.in_versions.iter().position(|ext| ext.identifier == ext_item.identifier) + { + Some(index) => index, + None => { + self.in_versions.push(ext_item); + self.in_versions.len() - 1 + }, + }; + ext_item_indices.push(ext_item_index as u32); + } + self.by_version.push((ext_version, ext_item_indices)); + } +} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs new file mode 100644 index 0000000000000..ae34b1365d220 --- /dev/null +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -0,0 +1,171 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types and trait to aggregate multiple versioned transaction extension pipelines. + +use crate::{ + traits::{ + DecodeWithVersion, DispatchInfoOf, DispatchOriginOf, Dispatchable, InvalidVersion, + PostDispatchInfoOf, TxExtLineAtVers, VersTxExtLine, VersTxExtLineMetadataBuilder, + VersTxExtLineVersion, VersTxExtLineWeight, + }, + transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, +}; +use alloc::vec::Vec; +use codec::Encode; +use core::fmt::Debug; +use scale_info::TypeInfo; +use sp_weights::Weight; + +/// An item in [`MultiVersion`]. It represents a transaction extension pipeline of a specific +/// single version. +pub trait MultiVersionItem { + /// The version of the transaction extension pipeline. + const VERSION: Option; +} + +impl MultiVersionItem for InvalidVersion { + const VERSION: Option = None; +} + +impl MultiVersionItem for TxExtLineAtVers { + const VERSION: Option = Some(VERSION); +} + +/// An implementation of [`VersTxExtLine`] that aggregated multiple transaction extension pipeline +/// of different versions. +/// +/// Each variant have its own version, duplicated version must be avoided, only the first used +/// version will be effective other duplicated version will be ignored. +/// +/// TODO TODO: example +#[allow(private_interfaces)] +#[derive(Clone, Debug, TypeInfo)] +pub enum MultiVersion { + /// The first aggregated transaction extension pipeline of a specific version. + A(A), + /// The second aggregated transaction extension pipeline of a specific version. + B(B), +} + +impl VersTxExtLineVersion for MultiVersion { + fn version(&self) -> u8 { + match self { + MultiVersion::A(a) => a.version(), + MultiVersion::B(b) => b.version(), + } + } +} + +impl Encode for MultiVersion { + fn size_hint(&self) -> usize { + match self { + MultiVersion::A(a) => a.size_hint(), + MultiVersion::B(b) => b.size_hint(), + } + } + fn encode(&self) -> Vec { + match self { + MultiVersion::A(a) => a.encode(), + MultiVersion::B(b) => b.encode(), + } + } + fn encode_to(&self, dest: &mut T) { + match self { + MultiVersion::A(a) => a.encode_to(dest), + MultiVersion::B(b) => b.encode_to(dest), + } + } + fn encoded_size(&self) -> usize { + match self { + MultiVersion::A(a) => a.encoded_size(), + MultiVersion::B(b) => b.encoded_size(), + } + } + fn using_encoded R>(&self, f: F) -> R { + match self { + MultiVersion::A(a) => a.using_encoded(f), + MultiVersion::B(b) => b.using_encoded(f), + } + } +} + +impl + DecodeWithVersion for MultiVersion +{ + fn decode_with_version( + extension_version: u8, + input: &mut I, + ) -> Result { + if A::VERSION == Some(extension_version) { + Ok(MultiVersion::A(A::decode_with_version(extension_version, input)?)) + } else if B::VERSION == Some(extension_version) { + Ok(MultiVersion::B(B::decode_with_version(extension_version, input)?)) + } else { + Err(codec::Error::from("Invalid extension version")) + } + } +} + +impl VersTxExtLineWeight for MultiVersion +where + A: VersTxExtLineWeight + MultiVersionItem, + B: VersTxExtLineWeight + MultiVersionItem, +{ + fn weight(&self, call: &Call) -> Weight { + match self { + MultiVersion::A(a) => a.weight(call), + MultiVersion::B(b) => b.weight(call), + } + } +} + +impl VersTxExtLine for MultiVersion +where + A: VersTxExtLine + MultiVersionItem, + B: VersTxExtLine + MultiVersionItem, +{ + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { + A::build_metadata(builder); + B::build_metadata(builder); + } + fn validate_only( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result { + match self { + MultiVersion::A(a) => a.validate_only(origin, call, info, len, source), + MultiVersion::B(b) => b.validate_only(origin, call, info, len, source), + } + } + fn dispatch_transaction( + self, + origin: DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + match self { + MultiVersion::A(a) => a.dispatch_transaction(origin, call, info, len), + MultiVersion::B(b) => b.dispatch_transaction(origin, call, info, len), + } + } +} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs new file mode 100644 index 0000000000000..180f87fdfb901 --- /dev/null +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -0,0 +1,173 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of versioned transaction extension pipeline that aggregate a version 0 and +//! other versions. + +use crate::{ + generic::ExtensionVersion, + traits::{ + AsTransactionAuthorizedOrigin, DecodeWithVersion, DispatchInfoOf, DispatchTransaction, + Dispatchable, PostDispatchInfoOf, TransactionExtension, VersTxExtLine, + VersTxExtLineMetadataBuilder, VersTxExtLineVersion, VersTxExtLineWeight, + }, + transaction_validity::TransactionSource, +}; +use alloc::vec::Vec; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; +use sp_weights::Weight; + +/// Version 0 of the transaction extension version used to construct the inherited +/// implication for legacy transactions. +const EXTENSION_V0_VERSION: ExtensionVersion = 0; + +/// A versioned transaction extension pipeline defined with 2 variants: one for the version 0 and +/// one for other versions. +/// +/// The generic `ExtensionOtherVersions` must not re-define a transaction extension pipeline for the +/// version 0, it will be ignored and overwritten by `ExtensionV0`. +/// TODO TODO: find good name. or keep it private anyway. +#[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] +pub enum ExtensionVariant { + /// A transaction extension pipeline for the version 0. + V0(ExtensionV0), + /// A transaction extension pipeline for other versions. + Other(ExtensionOtherVersions), +} + +impl VersTxExtLineVersion + for ExtensionVariant +{ + fn version(&self) -> u8 { + match self { + ExtensionVariant::V0(_) => EXTENSION_V0_VERSION, + ExtensionVariant::Other(ext) => ext.version(), + } + } +} + +impl Encode + for ExtensionVariant +{ + fn encode(&self) -> Vec { + match self { + ExtensionVariant::V0(ext) => ext.encode(), + ExtensionVariant::Other(ext) => ext.encode(), + } + } + fn size_hint(&self) -> usize { + match self { + ExtensionVariant::V0(ext) => ext.size_hint(), + ExtensionVariant::Other(ext) => ext.size_hint(), + } + } + fn encode_to(&self, dest: &mut T) { + match self { + ExtensionVariant::V0(ext) => ext.encode_to(dest), + ExtensionVariant::Other(ext) => ext.encode_to(dest), + } + } + fn encoded_size(&self) -> usize { + match self { + ExtensionVariant::V0(ext) => ext.encoded_size(), + ExtensionVariant::Other(ext) => ext.encoded_size(), + } + } + fn using_encoded R>(&self, f: F) -> R { + match self { + ExtensionVariant::V0(ext) => ext.using_encoded(f), + ExtensionVariant::Other(ext) => ext.using_encoded(f), + } + } +} + +impl DecodeWithVersion + for ExtensionVariant +{ + fn decode_with_version( + extension_version: u8, + input: &mut I, + ) -> Result { + match extension_version { + EXTENSION_V0_VERSION => Ok(ExtensionVariant::V0(Decode::decode(input)?)), + _ => Ok(ExtensionVariant::Other(DecodeWithVersion::decode_with_version( + extension_version, + input, + )?)), + } + } +} + +impl< + Call: Dispatchable + Encode, + ExtensionV0: TransactionExtension, + ExtensionOtherVersions: VersTxExtLine, + > VersTxExtLine for ExtensionVariant +where + ::RuntimeOrigin: AsTransactionAuthorizedOrigin, +{ + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { + ExtensionOtherVersions::build_metadata(builder); + } + fn validate_only( + &self, + origin: super::DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result< + crate::transaction_validity::ValidTransaction, + crate::transaction_validity::TransactionValidityError, + > { + match self { + ExtensionVariant::V0(ext) => ext + .validate_only(origin, call, info, len, source, EXTENSION_V0_VERSION) + .map(|x| x.0), + ExtensionVariant::Other(ext) => ext.validate_only(origin, call, info, len, source), + } + } + fn dispatch_transaction( + self, + origin: super::DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + match self { + ExtensionVariant::V0(ext) => + ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION), + ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), + } + } +} + +impl< + Call: Dispatchable + Encode, + ExtensionV0: TransactionExtension, + ExtensionOtherVersions: VersTxExtLineWeight, + > VersTxExtLineWeight for ExtensionVariant +{ + fn weight(&self, call: &Call) -> Weight { + match self { + ExtensionVariant::V0(ext) => ext.weight(call), + ExtensionVariant::Other(ext) => ext.weight(call), + } + } +} From e060cacf9a4c7be1cd798684c6e830b8157ac7ff Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 24 Dec 2024 13:55:21 +0900 Subject: [PATCH 12/56] fixes --- substrate/frame/revive/src/evm/runtime.rs | 4 ++-- substrate/primitives/metadata-ir/src/lib.rs | 2 +- substrate/primitives/metadata-ir/src/types.rs | 8 +++---- .../primitives/metadata-ir/src/unstable.rs | 8 ++----- .../runtime/src/traits/vers_tx_ext/mod.rs | 22 +++++++++++-------- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index c7ddac2ad0ece..ba82aac2e1057 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -100,9 +100,9 @@ impl ExtrinsicMetadata >::VERSIONS; type TransactionExtensions = E::Extension; type TransactionExtensionsVersions = - sp_runtime::traits::transaction_extension::ExtensionVariant< + sp_runtime::traits::ExtensionVariant< E::Extension, - sp_runtime::traits::transaction_extension::InvalidVersion, + sp_runtime::traits::InvalidVersion, >; } diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index 1e6fb7668931e..9cbc5992c35cc 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -114,7 +114,7 @@ mod test { signature_ty: meta_type::<()>(), extra_ty: meta_type::<()>(), extensions: vec![], - extensions_by_version: vec![], + extensions_by_version: Default::default(), extensions_in_versions: vec![], }, ty: meta_type::<()>(), diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index fa1347faf37a0..c36ebc87e7a48 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -183,10 +183,10 @@ pub struct ExtrinsicMetadataIR { pub extra_ty: T::Type, /// The transaction extensions in the order they appear in the extrinsic for the version 0. pub extensions: Vec>, - /// The transaction extensions for each version as a list of index in reference to item in - /// `transaction_extensions` field below. - pub extensions_by_version: Vec<(u8, Vec)>, - /// The list of all transaction extensions used. + /// The transaction extensions for each version as a list of index in reference to items in + /// `extensions_in_versions` field. + pub extensions_by_version: BTreeMap>, + /// The list of all transaction extensions used in `extensions_by_version`. pub extensions_in_versions: Vec>, } diff --git a/substrate/primitives/metadata-ir/src/unstable.rs b/substrate/primitives/metadata-ir/src/unstable.rs index d46ce3ec6a7d4..a4c2ef72c5d0d 100644 --- a/substrate/primitives/metadata-ir/src/unstable.rs +++ b/substrate/primitives/metadata-ir/src/unstable.rs @@ -162,16 +162,12 @@ impl From for TransactionExtensionMetadata { impl From for ExtrinsicMetadata { fn from(ir: ExtrinsicMetadataIR) -> Self { - // Assume version 0 for all extensions. - let indexes = (0..ir.extensions.len()).map(|index| index as u32).collect(); - let transaction_extensions_by_version = [(0, indexes)].iter().cloned().collect(); - ExtrinsicMetadata { versions: ir.versions, address_ty: ir.address_ty, signature_ty: ir.signature_ty, - transaction_extensions_by_version, - transaction_extensions: ir.extensions.into_iter().map(Into::into).collect(), + transaction_extensions_by_version: ir.extensions_by_version, + transaction_extensions: ir.extensions_in_versions.into_iter().map(Into::into).collect(), } } } diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 1c39349d3f779..29fff67389e70 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -25,7 +25,7 @@ use crate::{ }, transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; -use alloc::vec::Vec; +use alloc::{collections::BTreeMap, vec::Vec}; use codec::Encode; use core::fmt::Debug; use sp_weights::Weight; @@ -110,7 +110,7 @@ pub trait DecodeWithVersion: Sized { pub struct VersTxExtLineMetadataBuilder { /// The transaction extension pipeline by version and its list of items as vec of index into /// other field `in_versions`. - pub by_version: Vec<(u8, Vec)>, + pub by_version: BTreeMap>, /// The list of all transaction extension item used. pub in_versions: Vec, } @@ -118,7 +118,7 @@ pub struct VersTxExtLineMetadataBuilder { impl VersTxExtLineMetadataBuilder { /// Create a new empty metadata builder. pub fn new() -> Self { - Self { by_version: Vec::new(), in_versions: Vec::new() } + Self { by_version: BTreeMap::new(), in_versions: Vec::new() } } /// A function to add a versioned transaction extension to the metadata builder. @@ -127,11 +127,15 @@ impl VersTxExtLineMetadataBuilder { ext_version: u8, ext_items: Vec, ) { - debug_assert!( - self.by_version.iter().all(|(v, _)| *v != ext_version), - "Duplicate definition for transaction extension version: {}", - ext_version - ); + if self.by_version.contains_key(&ext_version) { + log::warn!("Duplicate definition for transaction extension version: {}", ext_version); + debug_assert!( + false, + "Duplicate definition for transaction extension version: {}", + ext_version + ); + return + } let mut ext_item_indices = Vec::with_capacity(ext_items.len()); for ext_item in ext_items { @@ -146,6 +150,6 @@ impl VersTxExtLineMetadataBuilder { }; ext_item_indices.push(ext_item_index as u32); } - self.by_version.push((ext_version, ext_item_indices)); + self.by_version.insert(ext_version, ext_item_indices); } } From 2c1e2fcaaf0a0a204b243c6ff3523b590f4b472f Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 24 Dec 2024 14:20:23 +0900 Subject: [PATCH 13/56] description draft --- prdoc/pr_xxxx.prdoc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 prdoc/pr_xxxx.prdoc diff --git a/prdoc/pr_xxxx.prdoc b/prdoc/pr_xxxx.prdoc new file mode 100644 index 0000000000000..4f220c5ae0367 --- /dev/null +++ b/prdoc/pr_xxxx.prdoc @@ -0,0 +1,15 @@ +With general transactions, we can have different version of the transaction extension pipeline. Currently only `0` is used. This PR allows to define other versions. + +I added a new generic to `UncheckedExtrinsic`: `ExtensionOtherVersions = InvalidVersions`. By default this generic is bound to "no other versions", so less breaking change. + +The type needs to keep some definition for the pipeline for signed transactions and also for inherent extrinsics. For this reason I decided to introduce a new generic to allow to define only other versions. + +### Additional notes + +It is still a breaking change because type inference don't assume generic being the default one. So usage like `UncheckedExtrinsic::from_parts(...)` may need to be rewritten to `UncheckedExtrinsic::<_, _, _, _>::from_parts(...)`. + +Otherwise we can introduce a new type `UncheckedExtrinsicV2` and make `type UncheckedExtrinsic = UncheckedExtrincV2`. + +If the new type is not a good design we can also just reimplement the logic to a new type. We don't have to force enhancing the current type. + +// TODO TODO: usage, examples, doc, tests From 0cc8f0c6368d74c1dbbbf424f41a2c0146583926 Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 6 Jan 2025 11:10:30 +0900 Subject: [PATCH 14/56] refactor --- substrate/frame/revive/src/evm/runtime.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index ba82aac2e1057..3e207e02caa3e 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -99,11 +99,10 @@ impl ExtrinsicMetadata E::Extension, >::VERSIONS; type TransactionExtensions = E::Extension; - type TransactionExtensionsVersions = - sp_runtime::traits::ExtensionVariant< - E::Extension, - sp_runtime::traits::InvalidVersion, - >; + type TransactionExtensionsVersions = < + generic::UncheckedExtrinsic::, Signature, E::Extension> + as ExtrinsicMetadata + >::TransactionExtensionsVersions; } impl ExtrinsicCall From 049ec5de876a1a3a285d33d77d1c3a1a9b5b60a4 Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 6 Jan 2025 13:35:07 +0900 Subject: [PATCH 15/56] doc --- docs/mermaid/extrinsics.mmd | 9 +- .../runtime/src/generic/checked_extrinsic.rs | 18 ++++ .../src/generic/unchecked_extrinsic.rs | 84 +++++++++++++++---- 3 files changed, 93 insertions(+), 18 deletions(-) diff --git a/docs/mermaid/extrinsics.mmd b/docs/mermaid/extrinsics.mmd index 4afd4ab8f755d..06be32ecf9e39 100644 --- a/docs/mermaid/extrinsics.mmd +++ b/docs/mermaid/extrinsics.mmd @@ -1,5 +1,6 @@ flowchart TD - E(Extrinsic) ---> I(Inherent); - E --> T(Transaction) - T --> ST("Signed (aka. Transaction)") - T --> UT(Unsigned) + E(Extrinsic) ---> B(Bare); + E --> S(Signed Transaction) + E --> G(General Transaction) + B --> I(Inherent); + B --> U(Unsigned Transaction (deprecated)) diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index e73d38867903c..b29973a52eb2c 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -37,6 +37,14 @@ const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// The kind of extrinsic this is, including any fields required of that kind. This is basically /// the full extrinsic except the `Call`. +/// +/// Bare extrinsics and signed extrinsics are extended with the transaction extension version 0, +/// specified by the generic parameter `ExtensionV0`. +/// +/// General extrinsics support multiple transaction extension version, specified by both +/// `ExtensionV0` and `ExtensionOtherVersions`, by default `ExtensionOtherVersions` is set to +/// invalid version, making `ExtensionV0` the only supported version. If you want to support more +/// versions, you need to specify the `ExtensionOtherVersions` parameter. #[derive(PartialEq, Eq, Clone, RuntimeDebug)] pub enum ExtrinsicFormat { /// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or @@ -55,6 +63,14 @@ pub enum ExtrinsicFormat { /// Who this purports to be from and the number of extrinsics have come before @@ -136,6 +152,8 @@ impl where Call: Dispatchable, ExtensionV0: TransactionExtension, + // TODO TODO: redo the bound directly on the generic used to make it clearer that it is + // implemented on AlwaysInvalid ExtensionVariant: VersTxExtLineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 36eb79532abd1..6ea3551b06341 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -67,9 +67,16 @@ impl SignaturePaylo /// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and /// holds any necessary specialized data. +/// +/// Bare extrinsics and signed extrinsics are extended with the transaction extension version 0, +/// specified by the generic parameter `ExtensionV0`. +/// +/// General extrinsics support multiple transaction extension version, specified by both +/// `ExtensionV0` and `ExtensionOtherVersions`, by default `ExtensionOtherVersions` is set to +/// invalid version, making `ExtensionV0` the only supported version. If you want to support more +/// versions, you need to specify the `ExtensionOtherVersions` parameter. #[derive(Eq, PartialEq, Clone)] pub enum Preamble { - // TODO TODO: if we bounds version trait then we can get rid of the ExtensionVersion field /// An extrinsic without a signature or any extension. This means it's either an inherent or /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with /// the general transaction which is without a signature but does have an extension). @@ -207,16 +214,33 @@ where /// An extrinsic is formally described as any external data that is originating from the outside of /// the runtime and fed into the runtime as a part of the block-body. /// -/// Inherents are special types of extrinsics that are placed into the block by the block-builder. -/// They are unsigned because the assertion is that they are "inherently true" by virtue of getting -/// past all validators. +/// Prerequisite concepts: Inherents vs Transactions +/// * Inherents are special types of extrinsics that are placed into the block by the block-builder. +/// They are unsigned because the assertion is that they are "inherently true" by virtue of getting +/// past all validators. +/// * Transactions are all other statements provided by external entities that the chain deems values +/// and decided to include in the block. This value is typically in the form of fee payment, but it +/// could in principle be any other interaction. Transactions are either signed or unsigned. A +/// sensible transaction pool should ensure that only transactions that are worthwhile are +/// considered for block-building. +/// +/// Types of extrinsics: +/// - **Bare**: An extrinsic without a signature or any additional data. After being checked, bare +/// extrinsics can be applied, the apply logic is extended with `ExtensionV0`. +/// Bare extrinsics are typically used for inherent extrinsics. +/// Bare extrinsics are also used for some unsigned transactions, this feature will be deprecated, +/// see [transaction horizon](https://github.com/paritytech/polkadot-sdk/issues/2415). +/// - **Signed**: An extrinsic with a signature and extended with transaction extension +/// `ExtensionV0`. (transaction extension: [`TransactionExtension`]). +/// - **General**: An extrinsic extended with a versioned transaction extension. The transaction +/// extension is specified by both `ExtensionV0` and `ExtensionOtherVersions`. By default, +/// `ExtensionOtherVersions` is set to invalid version, making `ExtensionV0` the only supported +/// version. +/// General transaction is a generalization of signed transaction that doesn't hardcode a +/// signature, instead signature is to be set and checked by a transaction extension. +/// +/// #[cfg_attr(all(feature = "std", not(windows)), doc = simple_mermaid::mermaid!("../../docs/mermaid/extrinsics.mmd"))] /// -/// Transactions are all other statements provided by external entities that the chain deems values -/// and decided to include in the block. This value is typically in the form of fee payment, but it -/// could in principle be any other interaction. Transactions are either signed or unsigned. A -/// sensible transaction pool should ensure that only transactions that are worthwhile are -/// considered for block-building. -#[cfg_attr(all(feature = "std", not(windows)), doc = simple_mermaid::mermaid!("../../docs/mermaid/extrinsics.mmd"))] /// This type is by no means enforced within Substrate, but given its genericness, it is highly /// likely that for most use-cases it will suffice. Thus, the encoding of this type will dictate /// exactly what bytes should be sent to a runtime to transact with it. @@ -224,6 +248,42 @@ where /// This can be checked using [`Checkable`], yielding a [`CheckedExtrinsic`], which is the /// counterpart of this type after its signature (and other non-negotiable validity checks) have /// passed. +/// +/// # Usage: +/// +/// Usage with multiple version for general transaction. +/// ``` +/// use sp_runtime::{ +/// generic::UncheckedExtrinsic, +/// traits::{MultiVersion, TxExtLineAtVers}, +/// }; +/// +/// struct Signature; // Some signature scheme. +/// struct Call; // Some call type. +/// struct AccountId; // Type for account identifier that can sign a transaction. +/// +/// // Some implementation of `TransactionExtension`. +/// struct PaymentExt; +/// struct PaymentV2Ext; +/// struct SigV2Ext; +/// struct NonceExt; +/// struct NonceV2Ext; +/// +/// // Definition of the extrinsic. +/// type ExtensionV0 = (SigV2Ext, NonceExt, PaymentExt); +/// type ExtensionV1 = TxExtLineAtVers<1, (SigV2Ext, NonceExt, PaymentV2Ext)>; +/// type ExtensionV2 = TxExtLineAtVers<2, (SigV2Ext, NonceV2Ext, PaymentV2Ext)>; +/// +/// type OtherVersions = MultiVersion; +/// +/// type Extrinsic = UncheckedExtrinsic< +/// AccountId, +/// Call, +/// Signature, +/// ExtensionV0, +/// OtherVersions, +/// >; +/// ``` #[derive(PartialEq, Eq, Clone, Debug)] pub struct UncheckedExtrinsic< Address, @@ -239,9 +299,6 @@ pub struct UncheckedExtrinsic< pub function: Call, } -// TODO TODO: 2 possible implementation: -// 1. a new generic for the multi version extension. -// 2. no new generic, the multi version extension defines what is ExtensionV0. /// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded /// `Vec`, but requires some logic to extract the signature and payload. /// @@ -413,7 +470,6 @@ where } } -// TODO TODO: metadata impl ExtrinsicMetadata for UncheckedExtrinsic { From d9eb5b8e4ceed589dc449394c33019e99e80a98b Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 6 Jan 2025 17:17:18 +0900 Subject: [PATCH 16/56] tests + fmt --- substrate/frame/revive/src/evm/runtime.rs | 10 +- substrate/frame/support/src/dispatch.rs | 12 +- .../src/generic/unchecked_extrinsic.rs | 17 +- .../src/traits/transaction_extension/mod.rs | 1 + .../runtime/src/traits/vers_tx_ext/at_vers.rs | 200 +++++++++++- .../runtime/src/traits/vers_tx_ext/mod.rs | 59 ++++ .../runtime/src/traits/vers_tx_ext/multi.rs | 306 +++++++++++++++++- .../runtime/src/traits/vers_tx_ext/variant.rs | 265 ++++++++++++++- 8 files changed, 846 insertions(+), 24 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 3e207e02caa3e..586c426086ec4 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -99,10 +99,12 @@ impl ExtrinsicMetadata E::Extension, >::VERSIONS; type TransactionExtensions = E::Extension; - type TransactionExtensionsVersions = < - generic::UncheckedExtrinsic::, Signature, E::Extension> - as ExtrinsicMetadata - >::TransactionExtensionsVersions; + type TransactionExtensionsVersions = , + Signature, + E::Extension, + > as ExtrinsicMetadata>::TransactionExtensionsVersions; } impl ExtrinsicCall diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 9e69513e55300..bd40afd79a320 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -398,10 +398,8 @@ impl GetDispatchI where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::ExtensionVariant< - ExtensionV0, - ExtensionOtherVersions, - >: sp_runtime::traits::VersTxExtLineWeight, + sp_runtime::traits::ExtensionVariant: + sp_runtime::traits::VersTxExtLineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -416,10 +414,8 @@ impl GetDispatchInfo where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::ExtensionVariant< - ExtensionV0, - ExtensionOtherVersions, - >: sp_runtime::traits::VersTxExtLineWeight, + sp_runtime::traits::ExtensionVariant: + sp_runtime::traits::VersTxExtLineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 6ea3551b06341..1478a9759b8f1 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -216,13 +216,13 @@ where /// /// Prerequisite concepts: Inherents vs Transactions /// * Inherents are special types of extrinsics that are placed into the block by the block-builder. -/// They are unsigned because the assertion is that they are "inherently true" by virtue of getting -/// past all validators. -/// * Transactions are all other statements provided by external entities that the chain deems values -/// and decided to include in the block. This value is typically in the form of fee payment, but it -/// could in principle be any other interaction. Transactions are either signed or unsigned. A -/// sensible transaction pool should ensure that only transactions that are worthwhile are -/// considered for block-building. +/// They are unsigned because the assertion is that they are "inherently true" by virtue of +/// getting past all validators. +/// * Transactions are all other statements provided by external entities that the chain deems +/// values and decided to include in the block. This value is typically in the form of fee +/// payment, but it could in principle be any other interaction. Transactions are either signed or +/// unsigned. A sensible transaction pool should ensure that only transactions that are worthwhile +/// are considered for block-building. /// /// Types of extrinsics: /// - **Bare**: An extrinsic without a signature or any additional data. After being checked, bare @@ -235,8 +235,7 @@ where /// - **General**: An extrinsic extended with a versioned transaction extension. The transaction /// extension is specified by both `ExtensionV0` and `ExtensionOtherVersions`. By default, /// `ExtensionOtherVersions` is set to invalid version, making `ExtensionV0` the only supported -/// version. -/// General transaction is a generalization of signed transaction that doesn't hardcode a +/// version. General transaction is a generalization of signed transaction that doesn't hardcode a /// signature, instead signature is to be set and checked by a transaction extension. /// /// #[cfg_attr(all(feature = "std", not(windows)), doc = simple_mermaid::mermaid!("../../docs/mermaid/extrinsics.mmd"))] diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index 2abba8d20c7df..dd29a98c54a9b 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -524,6 +524,7 @@ macro_rules! impl_tx_ext_default { } /// Information about a [`TransactionExtension`] for the runtime metadata. +#[derive(Clone)] pub struct TransactionExtensionMetadata { /// The unique identifier of the [`TransactionExtension`]. pub identifier: &'static str, diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs index 3eaff726aed56..0270c074d1baa 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -31,7 +31,7 @@ use scale_info::TypeInfo; use sp_weights::Weight; /// A transaction extension pipeline defined for a single version. -#[derive(Encode, Clone, Debug, TypeInfo)] +#[derive(Encode, Clone, Debug, TypeInfo, PartialEq, Eq)] pub struct TxExtLineAtVers { /// The transaction extension pipeline for the version `VERSION`. pub extension: Extension, @@ -104,3 +104,201 @@ impl bool { + true + } + } + + impl Dispatchable for MockCall { + type RuntimeOrigin = MockOrigin; + type Config = (); + type Info = (); + type PostInfo = (); + + fn dispatch( + self, + origin: Self::RuntimeOrigin, + ) -> crate::DispatchResultWithInfo { + if origin.0 == 0 { + return Err(DispatchError::Other("origin is 0").into()) + } + Ok(Default::default()) + } + } + + // A trivial extension that sets a known weight and does minimal logic. + // We simply store an integer "token" and do check logic on it. + #[derive(PartialEq, Eq, Clone, Debug, Encode, Decode, TypeInfo)] + pub struct SimpleExtension { + /// The token for validation logic + pub token: u32, + /// The "weight" that this extension claims to cost. + pub w: u64, + } + + impl TransactionExtension for SimpleExtension { + const IDENTIFIER: &'static str = "SimpleExtension"; + + type Implicit = (); + fn implicit(&self) -> Result { + Ok(()) + } + + type Val = (); + type Pre = (); + + fn weight(&self, _call: &MockCall) -> Weight { + Weight::from_parts(self.w, 0) + } + + fn validate( + &self, + origin: MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Implication, + _source: TransactionSource, + ) -> ValidateResult { + // any origin is permitted, but if `token == 0` => invalid + if self.token == 0 { + Err(InvalidTransaction::Custom(1).into()) + } else { + Ok((ValidTransaction::default(), (), origin)) + } + } + + fn prepare( + self, + _val: Self::Val, + _origin: &MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } + + // This type represents the versioned extension pipeline for version=3. + pub type ExtV3 = TxExtLineAtVers<3, SimpleExtension>; + + // This type represents the versioned extension pipeline for version=10. + pub type ExtV10 = TxExtLineAtVers<10, SimpleExtension>; + + // --- Tests --- + + #[test] + fn decode_with_correct_version_succeeds() { + let ext_v3 = ExtV3 { extension: SimpleExtension { token: 55, w: 1234 } }; + let encoded = ext_v3.encode(); + + let decoded = ::decode_with_version(3, &mut &encoded[..]) + .expect("should decode fine with matching version"); + assert_eq!(decoded.extension.token, 55); + assert_eq!(decoded.extension.w, 1234); + } + + #[test] + fn decode_with_incorrect_version_fails() { + let ext_v3 = ExtV3 { extension: SimpleExtension { token: 55, w: 1234 } }; + let encoded = ext_v3.encode(); + + // Attempt decode with version=10 + let decode_err = ::decode_with_version(10, &mut &encoded[..]) + .expect_err("should fail decode due to invalid version"); + let decode_err_str = format!("{}", decode_err); + assert!(decode_err_str.contains("Invalid extension version")); + } + + #[test] + fn version_is_correct() { + let ext_v3 = ExtV3 { extension: SimpleExtension { token: 55, w: 1234 } }; + assert_eq!(ext_v3.version(), 3); + + let ext_v10 = ExtV10 { extension: SimpleExtension { token: 1, w: 1 } }; + assert_eq!(ext_v10.version(), 10); + } + + #[test] + fn pipeline_functions_work() { + let ext_v3 = ExtV3 { extension: SimpleExtension { token: 999, w: 50 } }; + + // test "weight" function + let call = MockCall(0x_f00); + assert_eq!(ext_v3.weight(&call).ref_time(), 50); + + // test validating logic + { + // token = 0 => invalid + let invalid_ext_v3 = ExtV3 { extension: SimpleExtension { token: 0, w: 10 } }; + let validity = invalid_ext_v3.validate_only( + MockOrigin(1), + &call, + &Default::default(), + 0, + TransactionSource::External, + ); + assert_eq!( + validity, + Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1))) + ); + } + + // ok scenario: token != 0 => OK + let validity_ok = ext_v3.validate_only( + MockOrigin(2), + &call, + &Default::default(), + 0, + TransactionSource::Local, + ); + assert!(validity_ok.is_ok()); + let valid = validity_ok.unwrap(); + assert_eq!(valid, ValidTransaction::default()); + } + + #[test] + fn dispatch_transaction_works() { + // This extension is valid => token=1 + let ext_v3 = ExtV3 { extension: SimpleExtension { token: 1, w: 10 } }; + let call = MockCall(123); + let info = Default::default(); + let len = 0usize; + + // dispatch => OK + let res = ext_v3.clone().dispatch_transaction(MockOrigin(1), call.clone(), &info, len); + let outcome = res.expect("valid since token=1 and origin=Some"); + assert!(outcome.is_ok(), "actual dispatch of call"); + assert_eq!(outcome.unwrap(), ()); + + // but if origin is None => the underlying call fails + let res_fail = ext_v3.dispatch_transaction(MockOrigin(0), call, &info, len); + let block_err = res_fail.expect("valid").expect_err("should fail"); + assert_eq!(block_err.error, DispatchError::Other("origin is 0")); + } +} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 29fff67389e70..88fafbee7ebdc 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -153,3 +153,62 @@ impl VersTxExtLineMetadataBuilder { self.by_version.insert(ext_version, ext_item_indices); } } + +#[cfg(test)] +mod tests { + use super::*; + use scale_info::meta_type; + + #[test] + fn test_metadata_builder() { + let mut builder = VersTxExtLineMetadataBuilder::new(); + + let ext_item_a = TransactionExtensionMetadata { + identifier: "ExtensionA", + ty: meta_type::(), + implicit: meta_type::<(u32, u8)>(), + }; + let ext_item_b = TransactionExtensionMetadata { + identifier: "ExtensionB", + ty: meta_type::(), + implicit: meta_type::(), + }; + + // Push version 1 with ExtensionA. + builder.push_versioned_extension(1, vec![ext_item_a.clone()]); + // Push version 2 with ExtensionB, then ExtensionA again. + builder.push_versioned_extension(2, vec![ext_item_b.clone(), ext_item_a.clone()]); + + // We now expect: + // - `by_version` to have two entries: {1: [], 2: []}. + // - `in_versions` to contain ExtensionA and ExtensionB in some order. + + // Check that by_version now has 2 distinct versions defined. + assert_eq!(builder.by_version.len(), 2); + + // Verify version 1 entries. + { + let v1_indices = builder.by_version.get(&1).expect("Version 1 must be present"); + assert_eq!(v1_indices.len(), 1, "Version 1 should have exactly one extension"); + // Since we only ever added ExtensionA for version 1, it must match. + assert_eq!(builder.in_versions[v1_indices[0] as usize].identifier, "ExtensionA"); + } + + // Verify version 2 entries. + { + let v2_indices = builder.by_version.get(&2).expect("Version 2 must be present"); + assert_eq!(v2_indices.len(), 2, "Version 2 should have exactly two extensions"); + // For version 2, we pushed B then A, so the index order should reflect that: + // - ExtensionB is new, so it should get appended at the end of `in_versions`. + // - ExtensionA was seen previously, so it should reuse the earlier index. + + // First index for version 2 should point to "ExtensionB". + assert_eq!(builder.in_versions[v2_indices[0] as usize].identifier, "ExtensionB"); + // Second index for version 2 should point back to "ExtensionA". + assert_eq!(builder.in_versions[v2_indices[1] as usize].identifier, "ExtensionA"); + } + + // There should be exactly 2 unique entries in `in_versions`: [ExtensionA, ExtensionB]. + assert_eq!(builder.in_versions.len(), 2); + } +} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs index ae34b1365d220..b0d5d263d399c 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -54,7 +54,7 @@ impl MultiVersionItem for TxExtLineAtVers { /// The first aggregated transaction extension pipeline of a specific version. A(A), @@ -169,3 +169,307 @@ where } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + traits::{ + AsTransactionAuthorizedOrigin, DecodeWithVersion, DispatchInfoOf, Dispatchable, + Implication, TransactionExtension, TransactionSource, ValidateResult, VersTxExtLine, + VersTxExtLineVersion, VersTxExtLineWeight, + }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, + DispatchError, + }; + use codec::{Decode, Encode}; + use core::fmt::Debug; + use scale_info::TypeInfo; + use sp_weights::Weight; + + // -------------------------------------------------------- + // A mock call type and origin used for testing + // -------------------------------------------------------- + #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo)] + pub struct MockCall(pub u32); + + #[derive(Clone, Debug)] + pub struct MockOrigin(pub u8); + + impl AsTransactionAuthorizedOrigin for MockOrigin { + fn is_transaction_authorized(&self) -> bool { + // Let's say any origin != 0 is authorized + self.0 != 0 + } + } + + impl Dispatchable for MockCall { + type RuntimeOrigin = MockOrigin; + type Config = (); + type Info = (); + type PostInfo = (); + + fn dispatch( + self, + origin: Self::RuntimeOrigin, + ) -> crate::DispatchResultWithInfo { + // If the origin is 0, dispatch fails. + // Also, if the call is 0, dispatch fails. + if origin.0 == 0 { + return Err(DispatchError::Other("Unauthorized origin=0").into()); + } + if self.0 == 0 { + return Err(DispatchError::Other("call=0").into()); + } + Ok(Default::default()) + } + } + + // -------------------------------------------------------- + // Let's define two single-version pipelines with versions 4 and 7 + // -------------------------------------------------------- + + // A single-version extension pipeline that "succeeds" only if token != 0 + #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo)] + pub struct SimpleExtensionV4 { + pub token: u8, + pub declared_weight: u64, + } + + impl TransactionExtension for SimpleExtensionV4 { + const IDENTIFIER: &'static str = "SimpleExtV4"; + type Implicit = (); + type Val = (); + type Pre = (); + + fn implicit(&self) -> Result { + Ok(()) + } + + fn weight(&self, _call: &MockCall) -> Weight { + Weight::from_parts(self.declared_weight, 0) + } + + fn validate( + &self, + origin: MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Implication, + _source: TransactionSource, + ) -> ValidateResult { + if self.token == 0 { + Err(InvalidTransaction::Custom(44).into()) + } else { + Ok((ValidTransaction::default(), (), origin)) + } + } + + fn prepare( + self, + _val: Self::Val, + _origin: &MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } + + pub type PipelineV4 = TxExtLineAtVers<4, SimpleExtensionV4>; + + // Another single-version extension pipeline, version=7 + #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo)] + pub struct SimpleExtensionV7 { + pub token: u8, + pub declared_weight: u64, + } + + impl TransactionExtension for SimpleExtensionV7 { + const IDENTIFIER: &'static str = "SimpleExtV7"; + type Implicit = (); + type Val = (); + type Pre = (); + + fn implicit(&self) -> Result { + Ok(()) + } + + fn weight(&self, _call: &MockCall) -> Weight { + Weight::from_parts(self.declared_weight, 0) + } + + fn validate( + &self, + origin: MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Implication, + _source: TransactionSource, + ) -> ValidateResult { + if self.token == 0 { + Err(InvalidTransaction::Custom(77).into()) + } else { + Ok((ValidTransaction::default(), (), origin)) + } + } + + fn prepare( + self, + _val: Self::Val, + _origin: &MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } + + pub type PipelineV7 = TxExtLineAtVers<7, SimpleExtensionV7>; + + // -------------------------------------------------------- + // Our MultiVersion definition under test + // -------------------------------------------------------- + + pub type MyMultiExt = MultiVersion; + + // -------------------------------------------------------- + // Actual tests + // -------------------------------------------------------- + + #[test] + fn decode_with_version_works_for_known_versions() { + // Build a pipeline for version=4 + let pipeline_v4 = PipelineV4::new(SimpleExtensionV4 { token: 99, declared_weight: 123 }); + let encoded_v4 = pipeline_v4.encode(); + let decoded_v4 = MyMultiExt::decode_with_version(4, &mut &encoded_v4[..]) + .expect("decode with version=4"); + let expected_v4 = MultiVersion::A(pipeline_v4); + assert_eq!(decoded_v4, expected_v4); + + // Build a pipeline for version=7 + let pipeline_v7 = PipelineV7::new(SimpleExtensionV7 { token: 55, declared_weight: 777 }); + let encoded_v7 = pipeline_v7.encode(); + let decoded_v7 = MyMultiExt::decode_with_version(7, &mut &encoded_v7[..]) + .expect("decode with version=7"); + let expected_v7 = MultiVersion::B(pipeline_v7); + assert_eq!(decoded_v7, expected_v7); + } + + #[test] + fn decode_with_unknown_version_fails() { + let pipeline_v4 = PipelineV4::new(SimpleExtensionV4 { token: 1, declared_weight: 100 }); + let encoded_v4 = pipeline_v4.encode(); + + // Attempt decode with version=123 => fails + let decode_err = MyMultiExt::decode_with_version(123, &mut &encoded_v4[..]) + .expect_err("decode must fail with unknown version=123"); + assert!(format!("{}", decode_err).contains("Invalid extension version")); + } + + #[test] + fn version_is_correct() { + // The variant "A" is always the first in our MultiVersion and is version=4 + let multi_a = + MyMultiExt::A(PipelineV4::new(SimpleExtensionV4 { token: 1, declared_weight: 10 })); + assert_eq!(multi_a.version(), 4); + + // The variant "B" is version=7 + let multi_b = + MyMultiExt::B(PipelineV7::new(SimpleExtensionV7 { token: 2, declared_weight: 20 })); + assert_eq!(multi_b.version(), 7); + } + + #[test] + fn weight_check_works() { + let multi_a = + MyMultiExt::A(PipelineV4::new(SimpleExtensionV4 { token: 1, declared_weight: 500 })); + let multi_b = + MyMultiExt::B(PipelineV7::new(SimpleExtensionV7 { token: 1, declared_weight: 999 })); + + let call = MockCall(0); + assert_eq!(multi_a.weight(&call).ref_time(), 500); + assert_eq!(multi_b.weight(&call).ref_time(), 999); + } + + #[test] + fn validate_only_logic_works() { + // A with token=0 => invalid + let invalid_a = + MyMultiExt::A(PipelineV4::new(SimpleExtensionV4 { token: 0, declared_weight: 123 })); + let call = MockCall(42); + let validity = invalid_a.validate_only( + MockOrigin(42), + &call, + &Default::default(), + 0, + TransactionSource::Local, + ); + assert_eq!( + validity, + Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(44))) + ); + + // B with token=0 => invalid + let invalid_b = + MyMultiExt::B(PipelineV7::new(SimpleExtensionV7 { token: 0, declared_weight: 456 })); + let validity_b = invalid_b.validate_only( + MockOrigin(42), + &call, + &Default::default(), + 0, + TransactionSource::Local, + ); + assert_eq!( + validity_b, + Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(77))) + ); + + // A with token=some => ok + let valid_a = + MyMultiExt::A(PipelineV4::new(SimpleExtensionV4 { token: 55, declared_weight: 10 })); + let result_ok_a = valid_a.validate_only( + MockOrigin(1), + &call, + &Default::default(), + 0, + TransactionSource::External, + ); + assert!(result_ok_a.is_ok(), "valid scenario for pipeline A"); + } + + #[test] + fn dispatch_transaction_works() { + // "A" with token != 0 => valid + let pipeline_a = PipelineV4::new(SimpleExtensionV4 { token: 33, declared_weight: 1 }); + let multi_a = MyMultiExt::A(pipeline_a); + let call_good = MockCall(42); + let result = multi_a + .dispatch_transaction(MockOrigin(9), call_good.clone(), &Default::default(), 0) + .expect("Should not fail validity"); + assert!(result.is_ok(), "Dispatch with origin=9 is ok if call != 0"); + assert_eq!(result.unwrap(), ()); + + // but call=0 => dispatch fails + let fail_res = + MyMultiExt::A(PipelineV4::new(SimpleExtensionV4 { token: 1, declared_weight: 10 })) + .dispatch_transaction(MockOrigin(9), MockCall(0), &Default::default(), 0) + .expect("Should be a valid transaction from viewpoint of extension"); + let block_err = fail_res.expect_err("actual dispatch error"); + assert_eq!(block_err.error, DispatchError::Other("call=0")); + + // "B" scenario + let pipeline_b = PipelineV7::new(SimpleExtensionV7 { token: 2, declared_weight: 99 }); + let multi_b = MyMultiExt::B(pipeline_b); + let outcome_ok = multi_b + .dispatch_transaction(MockOrigin(1), call_good, &Default::default(), 0) + .expect("Should pass validity"); + assert!(outcome_ok.is_ok()); + } +} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index 180f87fdfb901..cc07ed7bac403 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -42,7 +42,6 @@ const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// /// The generic `ExtensionOtherVersions` must not re-define a transaction extension pipeline for the /// version 0, it will be ignored and overwritten by `ExtensionV0`. -/// TODO TODO: find good name. or keep it private anyway. #[derive(PartialEq, Eq, Clone, RuntimeDebug, TypeInfo)] pub enum ExtensionVariant { /// A transaction extension pipeline for the version 0. @@ -171,3 +170,267 @@ impl< } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + traits::{ + AsTransactionAuthorizedOrigin, DispatchInfoOf, Dispatchable, Implication, + TransactionExtension, TransactionSource, TxExtLineAtVers, ValidateResult, + }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, + DispatchError, + }; + use codec::{Decode, Encode}; + use core::fmt::Debug; + use sp_weights::Weight; + + // -------------------------------------------------------------------- + // 1. Mock call and "origin" type + // -------------------------------------------------------------------- + + #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] + pub struct MockCall(pub u64); + #[derive(Debug)] + pub struct MockOrigin; + + impl Dispatchable for MockCall { + type RuntimeOrigin = MockOrigin; + type Config = (); + type Info = (); + type PostInfo = (); + + fn dispatch( + self, + _origin: Self::RuntimeOrigin, + ) -> crate::DispatchResultWithInfo { + if self.0 == 0 { + return Err(DispatchError::Other("call is 0").into()) + } + Ok(Default::default()) + } + } + + // We'll implement the AsTransactionAuthorizedOrigin for Option: + impl AsTransactionAuthorizedOrigin for MockOrigin { + fn is_transaction_authorized(&self) -> bool { + true + } + } + + // -------------------------------------------------------------------- + // 2. Mock Extension used as "ExtensionV0" + // -------------------------------------------------------------------- + + /// A trivial extension type for "old-school version 0". + #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo)] + pub struct ExtV0 { + pub success_token: bool, + pub w: u64, + } + + impl TransactionExtension for ExtV0 { + const IDENTIFIER: &'static str = "OldSchoolV0"; + type Implicit = (); + fn implicit(&self) -> Result { + Ok(()) + } + type Val = (); + type Pre = (); + + fn weight(&self, _call: &MockCall) -> Weight { + Weight::from_parts(self.w, 0) + } + + fn validate( + &self, + origin: MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Implication, + _source: TransactionSource, + ) -> ValidateResult { + if !self.success_token { + Err(InvalidTransaction::Custom(99).into()) + } else { + Ok((ValidTransaction::default(), (), origin)) + } + } + + fn prepare( + self, + _val: Self::Val, + _origin: &MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } + + // -------------------------------------------------------------------- + // 3. Another pipeline that is used for "Other" versions: We'll define a minimal versioned + // pipeline with one version + // -------------------------------------------------------------------- + + /// Another extension for "some version" pipeline. + #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo)] + pub struct OtherExtension { + pub token: u16, + pub w: u64, + } + + impl TransactionExtension for OtherExtension { + const IDENTIFIER: &'static str = "OtherExtension"; + type Implicit = (); + fn implicit(&self) -> Result { + Ok(()) + } + type Val = (); + type Pre = (); + + fn weight(&self, _call: &MockCall) -> Weight { + Weight::from_parts(self.w, 0) + } + + fn validate( + &self, + origin: MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Implication, + _source: TransactionSource, + ) -> ValidateResult { + // If 'token' is 0 => invalid. Else ok. + if self.token == 0 { + return Err(InvalidTransaction::Custom(7).into()) + } + Ok((ValidTransaction::default(), (), origin)) + } + + fn prepare( + self, + _val: Self::Val, + _origin: &MockOrigin, + _call: &MockCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } + + type ExtV2 = TxExtLineAtVers<2, OtherExtension>; + + // -------------------------------------------------------------------- + // Actual unit tests + // -------------------------------------------------------------------- + + type Variant = ExtensionVariant; + + #[test] + fn decode_v0() { + // If extension_version == 0 => decode as V0 + let v0_data = ExtV0 { success_token: true, w: 42 }.encode(); + let candidate = Variant::decode_with_version(0, &mut &v0_data[..]) + .expect("decode with v0 must succeed"); + let ExtensionVariant::V0(ext_v0) = candidate else { panic!("Expected V0 variant") }; + assert!(ext_v0.success_token); + assert_eq!(ext_v0.w, 42); + } + + #[test] + fn decode_other() { + // If extension_version == 2 => decode as Other + let pipeline = ExtV2::new(OtherExtension { token: 9, w: 888 }); + let encoded = pipeline.encode(); + let candidate = Variant::decode_with_version(2, &mut &encoded[..]) + .expect("decode with version=2 => 'Other'"); + let ExtensionVariant::Other(p) = candidate else { panic!("Expected Other variant") }; + assert_eq!(p.extension.token, 9); + assert_eq!(p.extension.w, 888); + } + + #[test] + fn version_check() { + let v0_var: Variant = ExtensionVariant::V0(ExtV0 { success_token: true, w: 1 }); + let other_var: Variant = + ExtensionVariant::Other(ExtV2::new(OtherExtension { token: 1, w: 1 })); + assert_eq!(v0_var.version(), 0); + assert_eq!(other_var.version(), 2); + } + + #[test] + fn weight_check() { + let v0_var: Variant = ExtensionVariant::V0(ExtV0 { success_token: true, w: 100 }); + let other_var: Variant = + ExtensionVariant::Other(ExtV2::new(OtherExtension { token: 2, w: 555 })); + let call = MockCall(123); + + assert_eq!(v0_var.weight(&call).ref_time(), 100); + assert_eq!(other_var.weight(&call).ref_time(), 555); + } + + #[test] + fn validate_only_works() { + { + // v0 + success_token => ok + let v0_var: Variant = ExtensionVariant::V0(ExtV0 { success_token: true, w: 100 }); + let call = MockCall(1); + let valid = v0_var.validate_only( + MockOrigin, + &call, + &Default::default(), + 0, + TransactionSource::External, + ); + assert!(valid.is_ok()); + } + { + // other => token=0 => fail + let var_other: Variant = + ExtensionVariant::Other(ExtV2::new(OtherExtension { token: 0, w: 5 })); + let call = MockCall(1); + let fail = var_other.validate_only( + MockOrigin, + &call, + &Default::default(), + 0, + TransactionSource::Local, + ); + assert_eq!(fail, Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(7)))); + } + } + + #[test] + fn dispatch_transaction_works() { + // We'll do "v0" scenario with success_token => true => valid + let v0_var: Variant = ExtensionVariant::V0(ExtV0 { success_token: true, w: 12 }); + let call = MockCall(42); + let result = v0_var.dispatch_transaction(MockOrigin, call.clone(), &Default::default(), 0); + let extrinsic_outcome = result.expect("Ok(ApplyExtrinsicResultWithInfo)"); + assert!(extrinsic_outcome.is_ok(), "call with origin Some => dispatch Ok"); + + // If call is 0 => call fails at dispatch + let err = Variant::V0(ExtV0 { success_token: true, w: 1 }) + .dispatch_transaction(MockOrigin, MockCall(0), &Default::default(), 0) + .expect("valid") + .expect_err("dispatch error"); + + assert_eq!(err.error, DispatchError::Other("call is 0")); + + // check scenario for "other" too + let var_other: Variant = + ExtensionVariant::Other(ExtV2::new(OtherExtension { token: 5, w: 55 })); + let outcome = var_other + .dispatch_transaction(MockOrigin, call, &Default::default(), 0) + .expect("Should be ok"); + assert!(outcome.is_ok()); + } +} From 8e326891980ea6566234ccceb4eaed1c020cd602 Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 6 Jan 2025 19:26:57 +0900 Subject: [PATCH 17/56] multi version support 26 versions --- substrate/frame/support/src/dispatch.rs | 2 + .../runtime/src/traits/vers_tx_ext/multi.rs | 261 ++++++++++-------- 2 files changed, 152 insertions(+), 111 deletions(-) diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index bd40afd79a320..db5dc88b9f570 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -1599,3 +1599,5 @@ mod extension_weight_tests { }); } } + +// TODO TODO: a full test with multiple version and stuff. diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs index b0d5d263d399c..8e91cffb53efc 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -46,128 +46,167 @@ impl MultiVersionItem for TxExtLineAtVers = Some(VERSION); } -/// An implementation of [`VersTxExtLine`] that aggregated multiple transaction extension pipeline -/// of different versions. -/// -/// Each variant have its own version, duplicated version must be avoided, only the first used -/// version will be effective other duplicated version will be ignored. -/// -/// TODO TODO: example -#[allow(private_interfaces)] -#[derive(PartialEq, Eq, Clone, Debug, TypeInfo)] -pub enum MultiVersion { - /// The first aggregated transaction extension pipeline of a specific version. - A(A), - /// The second aggregated transaction extension pipeline of a specific version. - B(B), -} - -impl VersTxExtLineVersion for MultiVersion { - fn version(&self) -> u8 { - match self { - MultiVersion::A(a) => a.version(), - MultiVersion::B(b) => b.version(), +macro_rules! declare_multi_version_enum { + ($( $variant:tt, )*) => { + + /// An implementation of [`VersTxExtLine`] that aggregate multiple versioned transaction + /// extension pipeline. + /// + /// It is an enum where each variant have its own version, duplicated version must be + /// avoided, only the first used version will be effective other duplicated version will be + /// ignored. + /// + /// Versioned transaction extension pipelines are configured using the generic parameters. + /// + /// # Example + /// + /// ``` + /// use sp_runtime::traits::{MultiVersion, TxExtLineAtVers}; + /// + /// struct PaymentExt; + /// struct PaymentExtV2; + /// struct NonceExt; + /// + /// type ExtV1 = TxExtLineAtVers<1, (NonceExt, PaymentExt)>; + /// type ExtV4 = TxExtLineAtVers<4, (NonceExt, PaymentExtV2)>; + /// + /// /// The transaction extension pipeline that supports both version 1 and 4. + /// type TransactionExtension = MultiVersion; + /// ``` + #[allow(private_interfaces)] + #[derive(PartialEq, Eq, Clone, Debug, TypeInfo)] + pub enum MultiVersion< + $( + $variant = InvalidVersion, + )* + > { + $( + /// The transaction extension pipeline of a specific version. + $variant($variant), + )* } - } -} -impl Encode for MultiVersion { - fn size_hint(&self) -> usize { - match self { - MultiVersion::A(a) => a.size_hint(), - MultiVersion::B(b) => b.size_hint(), - } - } - fn encode(&self) -> Vec { - match self { - MultiVersion::A(a) => a.encode(), - MultiVersion::B(b) => b.encode(), - } - } - fn encode_to(&self, dest: &mut T) { - match self { - MultiVersion::A(a) => a.encode_to(dest), - MultiVersion::B(b) => b.encode_to(dest), + impl<$( $variant: VersTxExtLineVersion, )*> VersTxExtLineVersion for MultiVersion<$( $variant, )*> { + fn version(&self) -> u8 { + match self { + $( + MultiVersion::$variant(v) => v.version(), + )* + } + } } - } - fn encoded_size(&self) -> usize { - match self { - MultiVersion::A(a) => a.encoded_size(), - MultiVersion::B(b) => b.encoded_size(), + + impl<$( $variant: Encode, )*> Encode for MultiVersion<$( $variant, )*> { + fn size_hint(&self) -> usize { + match self { + $( + MultiVersion::$variant(v) => v.size_hint(), + )* + } + } + fn encode(&self) -> Vec { + match self { + $( + MultiVersion::$variant(v) => v.encode(), + )* + } + } + fn encode_to(&self, dest: &mut CodecOutput) { + match self { + $( + MultiVersion::$variant(v) => v.encode_to(dest), + )* + } + } + fn encoded_size(&self) -> usize { + match self { + $( + MultiVersion::$variant(v) => v.encoded_size(), + )* + } + } + fn using_encoded FunctionResult>( + &self, + f: Function + ) -> FunctionResult { + match self { + $( + MultiVersion::$variant(v) => v.using_encoded(f), + )* + } + } } - } - fn using_encoded R>(&self, f: F) -> R { - match self { - MultiVersion::A(a) => a.using_encoded(f), - MultiVersion::B(b) => b.using_encoded(f), + + impl<$( $variant: DecodeWithVersion + MultiVersionItem, )*> + DecodeWithVersion for MultiVersion<$( $variant, )*> + { + fn decode_with_version( + extension_version: u8, + input: &mut CodecInput, + ) -> Result { + $( + if $variant::VERSION == Some(extension_version) { + return Ok(MultiVersion::$variant($variant::decode_with_version(extension_version, input)?)); + } + )* + + Err(codec::Error::from("Invalid extension version")) + } } - } -} -impl - DecodeWithVersion for MultiVersion -{ - fn decode_with_version( - extension_version: u8, - input: &mut I, - ) -> Result { - if A::VERSION == Some(extension_version) { - Ok(MultiVersion::A(A::decode_with_version(extension_version, input)?)) - } else if B::VERSION == Some(extension_version) { - Ok(MultiVersion::B(B::decode_with_version(extension_version, input)?)) - } else { - Err(codec::Error::from("Invalid extension version")) + impl<$( $variant: VersTxExtLineWeight + MultiVersionItem, )* Call: Dispatchable> + VersTxExtLineWeight for MultiVersion<$( $variant, )*> + { + fn weight(&self, call: &Call) -> Weight { + match self { + $( + MultiVersion::$variant(v) => v.weight(call), + )* + } + } } - } -} -impl VersTxExtLineWeight for MultiVersion -where - A: VersTxExtLineWeight + MultiVersionItem, - B: VersTxExtLineWeight + MultiVersionItem, -{ - fn weight(&self, call: &Call) -> Weight { - match self { - MultiVersion::A(a) => a.weight(call), - MultiVersion::B(b) => b.weight(call), + impl<$( $variant: VersTxExtLine + MultiVersionItem, )* Call: Dispatchable> + VersTxExtLine for MultiVersion<$( $variant, )*> + { + fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { + $( + $variant::build_metadata(builder); + )* + } + fn validate_only( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + source: TransactionSource, + ) -> Result { + match self { + $( + MultiVersion::$variant(v) => v.validate_only(origin, call, info, len, source), + )* + } + } + fn dispatch_transaction( + self, + origin: DispatchOriginOf, + call: Call, + info: &DispatchInfoOf, + len: usize, + ) -> crate::ApplyExtrinsicResultWithInfo> { + match self { + $( + MultiVersion::$variant(v) => v.dispatch_transaction(origin, call, info, len), + )* + } + } } - } + }; } -impl VersTxExtLine for MultiVersion -where - A: VersTxExtLine + MultiVersionItem, - B: VersTxExtLine + MultiVersionItem, -{ - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { - A::build_metadata(builder); - B::build_metadata(builder); - } - fn validate_only( - &self, - origin: DispatchOriginOf, - call: &Call, - info: &DispatchInfoOf, - len: usize, - source: TransactionSource, - ) -> Result { - match self { - MultiVersion::A(a) => a.validate_only(origin, call, info, len, source), - MultiVersion::B(b) => b.validate_only(origin, call, info, len, source), - } - } - fn dispatch_transaction( - self, - origin: DispatchOriginOf, - call: Call, - info: &DispatchInfoOf, - len: usize, - ) -> crate::ApplyExtrinsicResultWithInfo> { - match self { - MultiVersion::A(a) => a.dispatch_transaction(origin, call, info, len), - MultiVersion::B(b) => b.dispatch_transaction(origin, call, info, len), - } - } +declare_multi_version_enum! { + A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, } #[cfg(test)] From c6aa89077a589b979137f233f342f385c84ccb98 Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 7 Jan 2025 13:04:08 +0900 Subject: [PATCH 18/56] simplify bounds --- substrate/frame/support/src/dispatch.rs | 6 ++---- .../primitives/runtime/src/generic/checked_extrinsic.rs | 4 +--- .../primitives/runtime/src/generic/unchecked_extrinsic.rs | 4 +--- .../primitives/runtime/src/traits/vers_tx_ext/variant.rs | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index db5dc88b9f570..04c91b1485d67 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -398,8 +398,7 @@ impl GetDispatchI where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::ExtensionVariant: - sp_runtime::traits::VersTxExtLineWeight, + ExtensionOtherVersions: sp_runtime::traits::VersTxExtLineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -414,8 +413,7 @@ impl GetDispatchInfo where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - sp_runtime::traits::ExtensionVariant: - sp_runtime::traits::VersTxExtLineWeight, + ExtensionOtherVersions: sp_runtime::traits::VersTxExtLineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index b29973a52eb2c..6990036b403b2 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -152,9 +152,7 @@ impl where Call: Dispatchable, ExtensionV0: TransactionExtension, - // TODO TODO: redo the bound directly on the generic used to make it clearer that it is - // implemented on AlwaysInvalid - ExtensionVariant: VersTxExtLineWeight, + ExtensionOtherVersions: VersTxExtLineWeight { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 1478a9759b8f1..69e05e80134dd 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -482,9 +482,7 @@ impl where Call: Dispatchable, ExtensionV0: TransactionExtension, - // TODO TODO: redo the bound directly on the generic used to make it clearer that it is - // implemented on AlwaysInvalid - ExtensionVariant: VersTxExtLineWeight, + ExtensionOtherVersions: VersTxExtLineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index cc07ed7bac403..b3d3bf758b09d 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -158,7 +158,7 @@ where } impl< - Call: Dispatchable + Encode, + Call: Dispatchable, ExtensionV0: TransactionExtension, ExtensionOtherVersions: VersTxExtLineWeight, > VersTxExtLineWeight for ExtensionVariant From bfadf05c2bf3f02a7530cec9a73cae6c65600385 Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 7 Jan 2025 13:09:34 +0900 Subject: [PATCH 19/56] refactor test --- .../primitives/runtime/src/traits/vers_tx_ext/at_vers.rs | 7 +++---- .../primitives/runtime/src/traits/vers_tx_ext/multi.rs | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs index 0270c074d1baa..5199742dc11f9 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -291,10 +291,9 @@ mod tests { let len = 0usize; // dispatch => OK - let res = ext_v3.clone().dispatch_transaction(MockOrigin(1), call.clone(), &info, len); - let outcome = res.expect("valid since token=1 and origin=Some"); - assert!(outcome.is_ok(), "actual dispatch of call"); - assert_eq!(outcome.unwrap(), ()); + ext_v3.clone().dispatch_transaction(MockOrigin(1), call.clone(), &info, len) + .expect("valid dispatch") + .expect("should be OK"); // but if origin is None => the underlying call fails let res_fail = ext_v3.dispatch_transaction(MockOrigin(0), call, &info, len); diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs index 8e91cffb53efc..102040a3e12a6 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -489,11 +489,10 @@ mod tests { let pipeline_a = PipelineV4::new(SimpleExtensionV4 { token: 33, declared_weight: 1 }); let multi_a = MyMultiExt::A(pipeline_a); let call_good = MockCall(42); - let result = multi_a + multi_a .dispatch_transaction(MockOrigin(9), call_good.clone(), &Default::default(), 0) - .expect("Should not fail validity"); - assert!(result.is_ok(), "Dispatch with origin=9 is ok if call != 0"); - assert_eq!(result.unwrap(), ()); + .expect("Should not fail validity") + .expect("Success"); // but call=0 => dispatch fails let fail_res = From dc7944f00fe5354711ad5e553f9ae75403e11b3c Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 7 Jan 2025 18:40:15 +0900 Subject: [PATCH 20/56] remove unneeded bounds --- substrate/frame/support/src/traits/misc.rs | 31 ++++++---------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index 0dc3abdce956c..629d989f0f842 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -926,13 +926,8 @@ pub trait ExtrinsicCall: sp_runtime::traits::ExtrinsicLike { fn call(&self) -> &Self::Call; } -impl ExtrinsicCall - for sp_runtime::generic::UncheckedExtrinsic -where - Address: TypeInfo, - Call: TypeInfo, - Signature: TypeInfo, - Extra: TypeInfo, +impl ExtrinsicCall + for sp_runtime::generic::UncheckedExtrinsic { type Call = Call; @@ -947,13 +942,8 @@ pub trait InherentBuilder: ExtrinsicCall { fn new_inherent(call: Self::Call) -> Self; } -impl InherentBuilder - for sp_runtime::generic::UncheckedExtrinsic -where - Address: TypeInfo, - Call: TypeInfo, - Signature: TypeInfo, - Extra: TypeInfo, +impl InherentBuilder + for sp_runtime::generic::UncheckedExtrinsic { fn new_inherent(call: Self::Call) -> Self { Self::new_bare(call) @@ -976,23 +966,18 @@ pub trait SignedTransactionBuilder: ExtrinsicCall { ) -> Self; } -impl SignedTransactionBuilder - for sp_runtime::generic::UncheckedExtrinsic -where - Address: TypeInfo, - Call: TypeInfo, - Signature: TypeInfo, - Extension: TypeInfo, +impl SignedTransactionBuilder + for sp_runtime::generic::UncheckedExtrinsic { type Address = Address; type Signature = Signature; - type Extension = Extension; + type Extension = ExtensionV0; fn new_signed_transaction( call: Self::Call, signed: Address, signature: Signature, - tx_ext: Extension, + tx_ext: ExtensionV0, ) -> Self { Self::new_signed(call, signed, signature, tx_ext) } From ad9e9bacc4955fbe55f26783406fc9bd2b3c1156 Mon Sep 17 00:00:00 2001 From: gui Date: Tue, 7 Jan 2025 18:40:22 +0900 Subject: [PATCH 21/56] more tests --- substrate/frame/support/src/dispatch.rs | 2 - substrate/frame/support/src/traits/misc.rs | 24 +- .../test/tests/tx_ext_multi_version.rs | 254 ++++++++++++++++++ .../runtime/src/generic/checked_extrinsic.rs | 2 +- .../runtime/src/traits/vers_tx_ext/at_vers.rs | 4 +- .../runtime/src/traits/vers_tx_ext/variant.rs | 5 +- 6 files changed, 283 insertions(+), 8 deletions(-) create mode 100644 substrate/frame/support/test/tests/tx_ext_multi_version.rs diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 04c91b1485d67..9a2c82f041674 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -1597,5 +1597,3 @@ mod extension_weight_tests { }); } } - -// TODO TODO: a full test with multiple version and stuff. diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index 629d989f0f842..c8918abfec4ad 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -927,7 +927,13 @@ pub trait ExtrinsicCall: sp_runtime::traits::ExtrinsicLike { } impl ExtrinsicCall - for sp_runtime::generic::UncheckedExtrinsic + for sp_runtime::generic::UncheckedExtrinsic< + Address, + Call, + Signature, + ExtensionV0, + ExtensionOtherVersions, + > { type Call = Call; @@ -943,7 +949,13 @@ pub trait InherentBuilder: ExtrinsicCall { } impl InherentBuilder - for sp_runtime::generic::UncheckedExtrinsic + for sp_runtime::generic::UncheckedExtrinsic< + Address, + Call, + Signature, + ExtensionV0, + ExtensionOtherVersions, + > { fn new_inherent(call: Self::Call) -> Self { Self::new_bare(call) @@ -967,7 +979,13 @@ pub trait SignedTransactionBuilder: ExtrinsicCall { } impl SignedTransactionBuilder - for sp_runtime::generic::UncheckedExtrinsic + for sp_runtime::generic::UncheckedExtrinsic< + Address, + Call, + Signature, + ExtensionV0, + ExtensionOtherVersions, + > { type Address = Address; type Signature = Signature; diff --git a/substrate/frame/support/test/tests/tx_ext_multi_version.rs b/substrate/frame/support/test/tests/tx_ext_multi_version.rs new file mode 100644 index 0000000000000..0f78147a00c9c --- /dev/null +++ b/substrate/frame/support/test/tests/tx_ext_multi_version.rs @@ -0,0 +1,254 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Test that FRAME support multiple version for transaction extension. + +use codec::{Decode, Encode, MaxEncodedLen}; +use core::fmt::Debug; +use frame_metadata::RuntimeMetadata; +use frame_support::{ + construct_runtime, derive_impl, + dispatch::{DispatchInfo, GetDispatchInfo, PostDispatchInfo}, + pallet_prelude::Weight, + parameter_types, + traits::{Get, OnFinalize, OnInitialize, PalletInfo as _}, + weights::RuntimeDbWeight, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + DispatchEventInfo, +}; +use scale_info::TypeInfo; +use sp_core::{hashing::blake2_256, sr25519, H256}; +use sp_io::TestExternalities; +use sp_runtime::{ + generic, + generic::Preamble, + testing::UintAuthorityId, + traits::{ + Applyable, AsTransactionAuthorizedOrigin, BlakeTwo256, Block as BlockT, Checkable, + Checkable as _, DecodeWithVersion, DispatchInfoOf, DispatchOriginOf, DispatchTransaction, + Dispatchable, ExtensionVariant, ExtrinsicLike, IdentifyAccount, IdentityLookup, NumberFor, + SaturatedConversion, TransactionExtension, ValidateUnsigned, Verify, VersTxExtLine, + VersTxExtLineWeight, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionSource as Source, + TransactionValidityError, TransactionValidityError as TvErr, ValidTransaction, + }, + ApplyExtrinsicResultWithInfo, DispatchError, DispatchErrorWithPostInfo, DispatchResult, + ModuleError, MultiSignature, RuntimeAppPublic, RuntimeDebug, +}; +use sp_version::RuntimeVersion; + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo)] +pub struct SimpleExt { + pub token: u8, +} + +const SIMPLE_EXT_IDS: [&str; 8] = [ + "SimpleExt0", + "SimpleExt1", + "SimpleExt2", + "SimpleExt3", + "SimpleExt4", + "SimpleExt5", + "SimpleExt6", + "SimpleExt7", +]; + +impl TransactionExtension for SimpleExt { + const IDENTIFIER: &'static str = SIMPLE_EXT_IDS[N as usize]; + type Implicit = (); + type Val = (); + type Pre = (); + + fn implicit(&self) -> Result { + Ok(()) + } + + fn weight(&self, _call: &RuntimeCall) -> Weight { + Weight::from_parts(N as u64 + 10, 0) + } + + fn validate( + &self, + origin: RuntimeOrigin, + _call: &RuntimeCall, + _info: &DispatchInfo, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl sp_runtime::traits::Implication, + _source: TransactionSource, + ) -> sp_runtime::traits::ValidateResult { + if self.token == 0 { + return Err(InvalidTransaction::Custom(N as u8).into()) + } + Ok((ValidTransaction::default(), (), frame_system::Origin::::Signed(100).into())) + } + + fn prepare( + self, + _val: Self::Val, + origin: &RuntimeOrigin, + _call: &RuntimeCall, + _info: &DispatchInfo, + _len: usize, + ) -> Result { + Ok(()) + } + + fn post_dispatch_details( + _pre: Self::Pre, + _info: &DispatchInfo, + _post_info: &PostDispatchInfo, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Ok(Weight::zero()) + } +} + +pub type SimpleExtV0 = SimpleExt<0>; +pub type SimpleExtV4 = SimpleExt<4>; +pub type SimpleExtV7 = SimpleExt<7>; + +pub type Ext4 = sp_runtime::traits::TxExtLineAtVers<4, SimpleExtV4>; +pub type Ext7 = sp_runtime::traits::TxExtLineAtVers<7, SimpleExtV7>; + +pub type OtherVersions = sp_runtime::traits::MultiVersion; + +pub type AccountId = u64; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic< + AccountId, + RuntimeCall, + UintAuthorityId, + SimpleExtV0, + OtherVersions, +>; + +pub type BlockNumber = u32; +pub type Block = generic::Block, UncheckedExtrinsic>; + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(30)] + pub type System = frame_system; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type PalletInfo = PalletInfo; + type OnSetCode = (); + type Block = Block; +} + +#[test] +fn test_metadata() { + let metadata = Runtime::metadata_ir(); + + assert_eq!( + metadata.extrinsic.extensions_by_version, + [(0, vec![0]), (4, vec![1]), (7, vec![2]),].into_iter().collect() + ); + + assert_eq!( + metadata + .extrinsic + .extensions_in_versions + .iter() + .map(|ext| ext.identifier.clone()) + .collect::>(), + vec!["SimpleExt0", "SimpleExt4", "SimpleExt7"] + ); +} + +#[test] +fn dispatch_of_valid_extrinsic_succeeds() { + let mut ext = sp_io::TestExternalities::new(Default::default()); + ext.execute_with(|| { + // Create an unchecked extrinsic with token=7 + // and set `AccountId=1` to simulate an authorized origin. + let xt = UncheckedExtrinsic::from_parts( + RuntimeCall::System(frame_system::Call::remark { remark: vec![1, 2] }), + Preamble::General(ExtensionVariant::Other(OtherVersions::A(Ext4::new(SimpleExtV4 { + token: 7, + })))), + ); + + let len = xt.using_encoded(|e| e.len()); + let info = xt.get_dispatch_info(); + + let checked = xt.check(&IdentityLookup::default()); + assert!(checked.is_ok(), "Should produce a valid checked extrinsic"); + let checked = checked.unwrap(); + + checked + .validate::(TransactionSource::External, &info, len) + .expect("valid"); + + checked.apply::(&info, len).expect("valid").expect("success"); + }); +} + +#[test] +fn dispatch_of_invalid_extrinsic_fails() { + let mut ext = sp_io::TestExternalities::new(Default::default()); + ext.execute_with(|| { + // Create an unchecked extrinsic with token=7 + // and set `AccountId=1` to simulate an authorized origin. + let xt = UncheckedExtrinsic::from_parts( + RuntimeCall::System(frame_system::Call::remark { remark: vec![1, 2] }), + Preamble::General(ExtensionVariant::Other(OtherVersions::A(Ext4::new(SimpleExtV4 { + token: 0, + })))), + ); + + let len = xt.using_encoded(|e| e.len()); + let info = xt.get_dispatch_info(); + + let checked = xt.check(&IdentityLookup::default()); + assert!(checked.is_ok(), "Should produce a valid checked extrinsic"); + let checked = checked.unwrap(); + + checked + .validate::(TransactionSource::External, &info, len) + .expect_err("invalid"); + + checked.apply::(&info, len).expect_err("invalid"); + }); +} diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 6990036b403b2..22bedb1aab2f1 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -152,7 +152,7 @@ impl where Call: Dispatchable, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersTxExtLineWeight + ExtensionOtherVersions: VersTxExtLineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs index 5199742dc11f9..51031e5a0025d 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -291,7 +291,9 @@ mod tests { let len = 0usize; // dispatch => OK - ext_v3.clone().dispatch_transaction(MockOrigin(1), call.clone(), &info, len) + ext_v3 + .clone() + .dispatch_transaction(MockOrigin(1), call.clone(), &info, len) .expect("valid dispatch") .expect("should be OK"); diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index b3d3bf758b09d..0f694221822fe 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -22,7 +22,7 @@ use crate::{ generic::ExtensionVersion, traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DispatchInfoOf, DispatchTransaction, - Dispatchable, PostDispatchInfoOf, TransactionExtension, VersTxExtLine, + Dispatchable, PostDispatchInfoOf, TransactionExtension, TxExtLineAtVers, VersTxExtLine, VersTxExtLineMetadataBuilder, VersTxExtLineVersion, VersTxExtLineWeight, }, transaction_validity::TransactionSource, @@ -122,6 +122,7 @@ where ::RuntimeOrigin: AsTransactionAuthorizedOrigin, { fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { + TxExtLineAtVers::::build_metadata(builder); ExtensionOtherVersions::build_metadata(builder); } fn validate_only( @@ -433,4 +434,6 @@ mod tests { .expect("Should be ok"); assert!(outcome.is_ok()); } + + // TODO TODO: maybe test metadata } From 181286086baa9da2cf905b36c0f54405a40272ae Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 18:13:25 +0900 Subject: [PATCH 22/56] make invalid version safer --- .../runtime/src/traits/vers_tx_ext/invalid.rs | 23 ++++++++++++++++++- .../runtime/src/traits/vers_tx_ext/variant.rs | 2 -- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index c2b2c06be82cb..953f5ba03c252 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -31,9 +31,14 @@ use core::fmt::Debug; use scale_info::TypeInfo; use sp_weights::Weight; + + /// An implementation of [`VersTxExtLine`] that consider any version invalid. +/// +/// This is mostly used by [`crate::traits::MultiVersions`]. +// NOTE: This type cannot be instantiated. #[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] -pub struct InvalidVersion; +pub enum InvalidVersion {} impl DecodeWithVersion for InvalidVersion { fn decode_with_version( @@ -71,12 +76,28 @@ impl VersTxExtLine for InvalidVersion { impl VersTxExtLineVersion for InvalidVersion { fn version(&self) -> u8 { + // NOTE: The type cannot be instantiated so this method is never called. 0 } } impl VersTxExtLineWeight for InvalidVersion { fn weight(&self, _call: &Call) -> Weight { + // NOTE: The type cannot be instantiated so this method is never called. Weight::zero() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn invalid_version_cannot_be_decoded() { + let mut input = &b""[..]; + assert_eq!( + InvalidVersion::decode_with_version(0, &mut input), + Err(codec::Error::from("Invalid extension version")) + ); + } +} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index 0f694221822fe..52791310c70cd 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -434,6 +434,4 @@ mod tests { .expect("Should be ok"); assert!(outcome.is_ok()); } - - // TODO TODO: maybe test metadata } From 082ab90db4ec258d6a328c6a8961547e6a07a006 Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 18:16:42 +0900 Subject: [PATCH 23/56] fmt --- substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index 953f5ba03c252..d5efb21f01038 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -31,8 +31,6 @@ use core::fmt::Debug; use scale_info::TypeInfo; use sp_weights::Weight; - - /// An implementation of [`VersTxExtLine`] that consider any version invalid. /// /// This is mostly used by [`crate::traits::MultiVersions`]. From a4a87f5c23cba17e609c94cb098530eb8793a009 Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 18:42:00 +0900 Subject: [PATCH 24/56] prdoc --- prdoc/pr_7035.prdoc | 50 +++++++++++++++++++++++++++++++++++++++++++++ prdoc/pr_xxxx.prdoc | 15 -------------- 2 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 prdoc/pr_7035.prdoc delete mode 100644 prdoc/pr_xxxx.prdoc diff --git a/prdoc/pr_7035.prdoc b/prdoc/pr_7035.prdoc new file mode 100644 index 0000000000000..3a49da3a1e7aa --- /dev/null +++ b/prdoc/pr_7035.prdoc @@ -0,0 +1,50 @@ +title: Allow declaration and usage of multiple transaction extension version in FRAME and primitives + +doc: + - audience: ["Runtime Dev"] + description: | + This PR enhance `UncheckedExtrinsic` type with a new optional generic: `ExtensionOtherVersion`. + This generic defaults to `InvalidVersion` meaning there is not other version than the regular version 0. This is the same behavior as before this PR. + + # Breaking change + + The types `Preamble`, `CheckedExtrinsic` and `ExtrinsicFormat` also have this new optional generic. Their type definition also have changed a bit, the `General` variant was 2 fields, the version and the extension, it is now only one field, the extension, and the version can be retrieve by calling `extension.version()` + + The type inference for those types may fail because of this PR, to update the code, write some partial type: `UncheckedExtrinsic<_, _, _, _>`, `Preamble<_, _, _>`, `ExtrinsicFormat<_, _> and `CheckedExtrinsic<_, _, _>`. + + # New feature + + To use this new feature, you can use the new types `TxExtLineAtVers` and `MultiVersion` to define a transaction extension with multiple version: + + ```rust + pub type TransactionExtensionV0 = (); + pub type TransactionExtensionV4 = (); + pub type TransactionExtensionV7 = (); + + pub type OtherVersions = MultiVersion< + TxExtLineAtVers<4, TransactionExtensionV4>; + TxExtLineAtVers<7, TransactionExtensionV7>; + >; + + pub type UncheckedExtrinsic = generic::UncheckedExtrinsic< + AccountId, + RuntimeCall, + UintAuthorityId, + TransactionExtensionV0, // The version 0, same as before + OtherVersions, // The other versions. + >; + ``` + +crates: + - name: node-testing + bump: major + - name: pallet-revive + bump: major + - name: frame-support-procedural + bump: major + - name: frame-support + bump: major + - name: frame-support-test + bump: major + - name: sp-runtime + bump: major diff --git a/prdoc/pr_xxxx.prdoc b/prdoc/pr_xxxx.prdoc deleted file mode 100644 index 4f220c5ae0367..0000000000000 --- a/prdoc/pr_xxxx.prdoc +++ /dev/null @@ -1,15 +0,0 @@ -With general transactions, we can have different version of the transaction extension pipeline. Currently only `0` is used. This PR allows to define other versions. - -I added a new generic to `UncheckedExtrinsic`: `ExtensionOtherVersions = InvalidVersions`. By default this generic is bound to "no other versions", so less breaking change. - -The type needs to keep some definition for the pipeline for signed transactions and also for inherent extrinsics. For this reason I decided to introduce a new generic to allow to define only other versions. - -### Additional notes - -It is still a breaking change because type inference don't assume generic being the default one. So usage like `UncheckedExtrinsic::from_parts(...)` may need to be rewritten to `UncheckedExtrinsic::<_, _, _, _>::from_parts(...)`. - -Otherwise we can introduce a new type `UncheckedExtrinsicV2` and make `type UncheckedExtrinsic = UncheckedExtrincV2`. - -If the new type is not a good design we can also just reimplement the logic to a new type. We don't have to force enhancing the current type. - -// TODO TODO: usage, examples, doc, tests From b657487c0f80f48561fa7e2c942395df7010354b Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 18:46:40 +0900 Subject: [PATCH 25/56] prdoc fmt --- prdoc/pr_7035.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_7035.prdoc b/prdoc/pr_7035.prdoc index 3a49da3a1e7aa..8f624545de4f7 100644 --- a/prdoc/pr_7035.prdoc +++ b/prdoc/pr_7035.prdoc @@ -1,7 +1,7 @@ title: Allow declaration and usage of multiple transaction extension version in FRAME and primitives doc: - - audience: ["Runtime Dev"] + - audience: Runtime Dev description: | This PR enhance `UncheckedExtrinsic` type with a new optional generic: `ExtensionOtherVersion`. This generic defaults to `InvalidVersion` meaning there is not other version than the regular version 0. This is the same behavior as before this PR. From 4d7e494bf0fcd4930995866b2ab400df800c5d92 Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 19:13:21 +0900 Subject: [PATCH 26/56] semver --- prdoc/pr_7035.prdoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prdoc/pr_7035.prdoc b/prdoc/pr_7035.prdoc index 8f624545de4f7..922a0f300c11b 100644 --- a/prdoc/pr_7035.prdoc +++ b/prdoc/pr_7035.prdoc @@ -48,3 +48,7 @@ crates: bump: major - name: sp-runtime bump: major + - name: sp-metadata-ir + bump: major + - name: pallet-transaction-payment + bump: major From 0b0d980dbccdc8e22c0b5186b111111665bfc98d Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 19:19:29 +0900 Subject: [PATCH 27/56] remove unused --- .../test/tests/tx_ext_multi_version.rs | 33 +++++-------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/substrate/frame/support/test/tests/tx_ext_multi_version.rs b/substrate/frame/support/test/tests/tx_ext_multi_version.rs index 0f78147a00c9c..b30cac0ff4139 100644 --- a/substrate/frame/support/test/tests/tx_ext_multi_version.rs +++ b/substrate/frame/support/test/tests/tx_ext_multi_version.rs @@ -17,43 +17,26 @@ //! Test that FRAME support multiple version for transaction extension. -use codec::{Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode}; use core::fmt::Debug; -use frame_metadata::RuntimeMetadata; use frame_support::{ - construct_runtime, derive_impl, + derive_impl, dispatch::{DispatchInfo, GetDispatchInfo, PostDispatchInfo}, pallet_prelude::Weight, - parameter_types, - traits::{Get, OnFinalize, OnInitialize, PalletInfo as _}, - weights::RuntimeDbWeight, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - DispatchEventInfo, }; use scale_info::TypeInfo; -use sp_core::{hashing::blake2_256, sr25519, H256}; -use sp_io::TestExternalities; use sp_runtime::{ generic, generic::Preamble, testing::UintAuthorityId, traits::{ - Applyable, AsTransactionAuthorizedOrigin, BlakeTwo256, Block as BlockT, Checkable, - Checkable as _, DecodeWithVersion, DispatchInfoOf, DispatchOriginOf, DispatchTransaction, - Dispatchable, ExtensionVariant, ExtrinsicLike, IdentifyAccount, IdentityLookup, NumberFor, - SaturatedConversion, TransactionExtension, ValidateUnsigned, Verify, VersTxExtLine, - VersTxExtLineWeight, + Applyable, BlakeTwo256, Checkable, ExtensionVariant, IdentityLookup, TransactionExtension, }, transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionSource as Source, - TransactionValidityError, TransactionValidityError as TvErr, ValidTransaction, + InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction, }, - ApplyExtrinsicResultWithInfo, DispatchError, DispatchErrorWithPostInfo, DispatchResult, - ModuleError, MultiSignature, RuntimeAppPublic, RuntimeDebug, + DispatchResult, }; -use sp_version::RuntimeVersion; #[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo)] pub struct SimpleExt { @@ -87,7 +70,7 @@ impl TransactionExtension for SimpleExt { fn validate( &self, - origin: RuntimeOrigin, + _origin: RuntimeOrigin, _call: &RuntimeCall, _info: &DispatchInfo, _len: usize, @@ -104,7 +87,7 @@ impl TransactionExtension for SimpleExt { fn prepare( self, _val: Self::Val, - origin: &RuntimeOrigin, + _origin: &RuntimeOrigin, _call: &RuntimeCall, _info: &DispatchInfo, _len: usize, @@ -191,7 +174,7 @@ fn test_metadata() { .extrinsic .extensions_in_versions .iter() - .map(|ext| ext.identifier.clone()) + .map(|ext| ext.identifier) .collect::>(), vec!["SimpleExt0", "SimpleExt4", "SimpleExt7"] ); From 90b8297718ba6ec22d55a2aa95207de62ffd68d6 Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 19:56:06 +0900 Subject: [PATCH 28/56] explicit re-export + fix doc --- substrate/primitives/runtime/src/traits/mod.rs | 5 ++++- .../primitives/runtime/src/traits/vers_tx_ext/invalid.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index 128888ae2c40b..5ab7833839a3e 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -59,7 +59,10 @@ pub use transaction_extension::{ DispatchTransaction, Implication, ImplicationParts, TransactionExtension, TransactionExtensionMetadata, TxBaseImplication, ValidateResult, }; -pub use vers_tx_ext::*; +pub use vers_tx_ext::{ + ExtensionVariant, InvalidVersion, MultiVersion, TxExtLineAtVers, VersTxExtLine, + VersTxExtLineMetadataBuilder, VersTxExtLineVersion, VersTxExtLineWeight, +}; /// A lazy value. pub trait Lazy { diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index d5efb21f01038..33abcef21a1bb 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -33,7 +33,7 @@ use sp_weights::Weight; /// An implementation of [`VersTxExtLine`] that consider any version invalid. /// -/// This is mostly used by [`crate::traits::MultiVersions`]. +/// This is mostly used by [`crate::traits::MultiVersion`]. // NOTE: This type cannot be instantiated. #[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] pub enum InvalidVersion {} From d1bdbd954113fd6d272b99a061dd20ae69290b3f Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 20:01:27 +0900 Subject: [PATCH 29/56] explicit reexport --- substrate/primitives/runtime/src/traits/mod.rs | 4 ++-- .../primitives/runtime/src/traits/vers_tx_ext/mod.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index 5ab7833839a3e..ad3dd61a7b7ac 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -60,8 +60,8 @@ pub use transaction_extension::{ TransactionExtensionMetadata, TxBaseImplication, ValidateResult, }; pub use vers_tx_ext::{ - ExtensionVariant, InvalidVersion, MultiVersion, TxExtLineAtVers, VersTxExtLine, - VersTxExtLineMetadataBuilder, VersTxExtLineVersion, VersTxExtLineWeight, + DecodeWithVersion, ExtensionVariant, InvalidVersion, MultiVersion, TxExtLineAtVers, + VersTxExtLine, VersTxExtLineMetadataBuilder, VersTxExtLineVersion, VersTxExtLineWeight, }; /// A lazy value. diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 88fafbee7ebdc..800acf454e17a 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -34,10 +34,10 @@ mod at_vers; mod invalid; mod multi; mod variant; -pub use at_vers::*; -pub use invalid::*; -pub use multi::*; -pub use variant::*; +pub use at_vers::TxExtLineAtVers; +pub use invalid::InvalidVersion; +pub use multi::MultiVersion; +pub use variant::ExtensionVariant; /// The weight for an instance of a versioned transaction extension pipeline and a call. /// From a59da7b4f25bdb2d27575feb0f7c661a706e6fef Mon Sep 17 00:00:00 2001 From: gui Date: Wed, 8 Jan 2025 20:49:05 +0900 Subject: [PATCH 30/56] refactor and doc --- .../src/generic/unchecked_extrinsic.rs | 37 +++++++++---------- .../runtime/src/traits/vers_tx_ext/at_vers.rs | 9 ++--- .../runtime/src/traits/vers_tx_ext/mod.rs | 2 +- .../runtime/src/traits/vers_tx_ext/multi.rs | 6 +++ 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index f9d6c993ea18e..dc93129f737d7 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -156,8 +156,10 @@ where .saturating_add(address.size_hint()) .saturating_add(signature.size_hint()) .saturating_add(ext.size_hint()), - Preamble::General(ext) => - EXTRINSIC_FORMAT_VERSION.size_hint().saturating_add(ext.size_hint()), + Preamble::General(ext) => EXTRINSIC_FORMAT_VERSION + .size_hint() + .saturating_add(0u8.size_hint()) // version + .saturating_add(ext.size_hint()), } } @@ -388,8 +390,6 @@ impl } /// New instance of an new-school unsigned transaction. - /// - /// This function is only available for `UncheckedExtrinsic` without multi version extension. pub fn new_transaction(function: Call, tx_ext: ExtensionV0) -> Self { Self { preamble: Preamble::General(ExtensionVariant::V0(tx_ext)), function } } @@ -561,14 +561,14 @@ where } #[cfg(feature = "serde")] -impl< - Address: Encode, - Signature: Encode, - Call: Encode, - ExtensionV0: Encode, - ExtensionOtherVersions: Encode + VersTxExtLineVersion, - > serde::Serialize +impl serde::Serialize for UncheckedExtrinsic +where + Address: Encode, + Signature: Encode, + Call: Encode, + ExtensionV0: Encode, + ExtensionOtherVersions: Encode + VersTxExtLineVersion, { fn serialize(&self, seq: S) -> Result where @@ -579,15 +579,14 @@ impl< } #[cfg(feature = "serde")] -impl< - 'a, - Address: Decode, - Signature: Decode, - Call: Decode, - ExtensionV0: Decode, - ExtensionOtherVersions: DecodeWithVersion, - > serde::Deserialize<'a> +impl<'a, Address, Signature, Call, ExtensionV0, ExtensionOtherVersions> serde::Deserialize<'a> for UncheckedExtrinsic +where + Address: Decode, + Signature: Decode, + Call: Decode, + ExtensionV0: Decode, + ExtensionOtherVersions: DecodeWithVersion, { fn deserialize(de: D) -> Result where diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs index 51031e5a0025d..5a404a2a9c2d8 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -65,11 +65,10 @@ impl VersTxExtLineVersion for TxExtLineAtVers + Encode, - Extension: TransactionExtension, - > VersTxExtLine for TxExtLineAtVers +impl VersTxExtLine for TxExtLineAtVers +where + Call: Dispatchable + Encode, + Extension: TransactionExtension, { fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { builder.push_versioned_extension(VERSION, Extension::metadata()); diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 800acf454e17a..275dfa1446ccb 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -109,7 +109,7 @@ pub trait DecodeWithVersion: Sized { /// A type to build the metadata for the versioned transaction extension pipeline. pub struct VersTxExtLineMetadataBuilder { /// The transaction extension pipeline by version and its list of items as vec of index into - /// other field `in_versions`. + /// the other field `in_versions`. pub by_version: BTreeMap>, /// The list of all transaction extension item used. pub in_versions: Vec, diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs index 102040a3e12a6..7e6fedcd972a8 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -35,6 +35,8 @@ use sp_weights::Weight; /// single version. pub trait MultiVersionItem { /// The version of the transaction extension pipeline. + /// + /// `None` means that the item has no version and can't be decoded. const VERSION: Option; } @@ -145,6 +147,10 @@ macro_rules! declare_multi_version_enum { input: &mut CodecInput, ) -> Result { $( + // NOTE: Here we could try all variants without checking for the version, + // but the error would be less informative. + // Otherwise we could change the trait `DecodeWithVersion` to return an enum of + // 3 variants: ok, error and invalid_version. if $variant::VERSION == Some(extension_version) { return Ok(MultiVersion::$variant($variant::decode_with_version(extension_version, input)?)); } From ef48bc75b246713ee584b8aeda89c42189ffabaa Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 1 Jan 2026 11:26:20 +0900 Subject: [PATCH 31/56] remove useless type info breaking subxt --- .../runtime/src/generic/unchecked_extrinsic.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 198a7ad50c8e5..ba11159843ed3 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -417,10 +417,11 @@ where TypeParameter::new("Call", Some(meta_type::())), TypeParameter::new("Signature", Some(meta_type::())), TypeParameter::new("Extra", Some(meta_type::())), - TypeParameter::new( - "GeneralExtensions", - Some(meta_type::>()), - ), + // NOTE: We avoid adding `ExtensionOtherVersions` in the type parameter type info + // because they break tools like subxt that hard-coded the number of type + // parameters. Also in general type parameters are not useful, information related + // to transaction extension are available in the metadata like for v16 the fields + // `transaction_extensions_by_version` and `transaction_extensions`. ]) .docs(&["UncheckedExtrinsic raw bytes, requires custom decoding routine"]) // Because of the custom encoding, we can only accurately describe the encoding as an From f26336692e4619e388fc8c2f7d7303f89a526bd8 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 1 Jan 2026 12:15:58 +0900 Subject: [PATCH 32/56] doc --- .../primitives/runtime/src/traits/vers_tx_ext/invalid.rs | 8 +++++--- .../primitives/runtime/src/traits/vers_tx_ext/mod.rs | 8 +++----- .../primitives/runtime/src/traits/vers_tx_ext/multi.rs | 8 +++++--- .../primitives/runtime/src/traits/vers_tx_ext/variant.rs | 3 +-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index 6aa434dd21630..81ae6c530894e 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -35,7 +35,7 @@ use sp_weights::Weight; /// An implementation of [`VersTxExtLine`] that consider any version invalid. /// /// This is mostly used by [`crate::traits::MultiVersion`]. -// NOTE: This type cannot be instantiated. +// This type cannot be instantiated. #[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] pub enum InvalidVersion {} @@ -62,6 +62,7 @@ impl VersTxExtLine for InvalidVersion { _len: usize, _source: TransactionSource, ) -> Result { + // The type cannot be instantiated so this method is never called. Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))) } fn dispatch_transaction( @@ -71,20 +72,21 @@ impl VersTxExtLine for InvalidVersion { _info: &DispatchInfoOf, _len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { + // The type cannot be instantiated so this method is never called. Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0)).into()) } } impl VersTxExtLineVersion for InvalidVersion { fn version(&self) -> u8 { - // NOTE: The type cannot be instantiated so this method is never called. + // The type cannot be instantiated so this method is never called. 0 } } impl VersTxExtLineWeight for InvalidVersion { fn weight(&self, _call: &Call) -> Weight { - // NOTE: The type cannot be instantiated so this method is never called. + // The type cannot be instantiated so this method is never called. Weight::zero() } } diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index e9505e538f21c..74d76ea500abb 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -42,8 +42,7 @@ pub use variant::ExtensionVariant; /// The weight for an instance of a versioned transaction extension pipeline and a call. /// /// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to -/// rely only on it without bounding the whole trait [`VersTxExtLine`]. This is used by -/// [`crate::generic::UncheckedExtrinsic`] to be backward compatible with its previous version. +/// rely only on it without bounding the whole trait [`VersTxExtLine`]. pub trait VersTxExtLineWeight { /// Return the pre dispatch weight for the given versioned transaction extension pipeline and /// call. @@ -53,8 +52,7 @@ pub trait VersTxExtLineWeight { /// The version for an instance of a versioned transaction extension pipeline. /// /// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to -/// rely only on it without bounding the whole trait [`VersTxExtLine`]. This is used by -/// [`crate::generic::UncheckedExtrinsic`] to be backward compatible with its previous version. +/// rely only on it without bounding the whole trait [`VersTxExtLine`]. pub trait VersTxExtLineVersion { /// Return the version for the given versioned transaction extension pipeline. fn version(&self) -> u8; @@ -126,7 +124,7 @@ impl VersTxExtLineMetadataBuilder { Self { by_version: BTreeMap::new(), in_versions: Vec::new() } } - /// A function to add a versioned transaction extension to the metadata builder. + /// A function to add a versioned transaction extension pipeline to the metadata builder. pub fn push_versioned_extension( &mut self, ext_version: u8, diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs index 8281024eed1cb..213ab297f8fc3 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -51,10 +51,10 @@ impl MultiVersionItem for TxExtLineAtVers { - /// An implementation of [`VersTxExtLine`] that aggregate multiple versioned transaction + /// An implementation of [`VersTxExtLine`] that aggregates multiple versioned transaction /// extension pipeline. /// - /// It is an enum where each variant have its own version, duplicated version must be + /// It is an enum where each variant has its own version, duplicated version must be /// avoided, only the first used version will be effective other duplicated version will be /// ignored. /// @@ -98,6 +98,7 @@ macro_rules! declare_multi_version_enum { } } + // It encodes without the variant index. impl<$( $variant: Encode, )*> Encode for MultiVersion<$( $variant, )*> { fn size_hint(&self) -> usize { match self { @@ -139,6 +140,7 @@ macro_rules! declare_multi_version_enum { } } + // It decodes from a specified version. impl<$( $variant: DecodeWithVersion + MultiVersionItem, )*> DecodeWithVersion for MultiVersion<$( $variant, )*> { @@ -147,7 +149,7 @@ macro_rules! declare_multi_version_enum { input: &mut CodecInput, ) -> Result { $( - // NOTE: Here we could try all variants without checking for the version, + // Here we could try all variants without checking for the version, // but the error would be less informative. // Otherwise we could change the trait `DecodeWithVersion` to return an enum of // 3 variants: ok, error and invalid_version. diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index d5f0dccad1fcc..648b5edf58ec1 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -33,8 +33,7 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_weights::Weight; -/// Version 0 of the transaction extension version used to construct the inherited -/// implication for legacy transactions. +/// Version 0 of the transaction extension version. const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// A versioned transaction extension pipeline defined with 2 variants: one for the version 0 and From a66d24d0ac46c6695065f827eae4a6f016e3f065 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 1 Jan 2026 12:17:23 +0900 Subject: [PATCH 33/56] fix rust doc link --- substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 74d76ea500abb..80cbf0aa577b4 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -106,7 +106,7 @@ pub trait DecodeWithVersion: Sized { } /// A type implements [`DecodeWithVersion`] where inner decoding is implementing -/// [`DecodeWithMemTracking`]. +/// [`codec::DecodeWithMemTracking`]. pub trait DecodeWithVersionWithMemTracking: DecodeWithVersion {} /// A type to build the metadata for the versioned transaction extension pipeline. From ecc7cc7a3c4a91150ec69effc135ab5ba3245782 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 1 Jan 2026 12:57:37 +0900 Subject: [PATCH 34/56] fix rustdoc test --- substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index ba11159843ed3..0ca51113c6072 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -302,7 +302,6 @@ where /// Signature, /// ExtensionV0, /// OtherVersions, -/// DEFAULT_MAX_CALL_SIZE, /// >; /// ``` #[derive(DecodeWithMemTracking, Eq, Clone)] From 4b6ef768885f33c3a00b3940ab54f904c0ef3142 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 1 Jan 2026 13:09:18 +0900 Subject: [PATCH 35/56] better type info --- .../primitives/runtime/src/generic/checked_extrinsic.rs | 3 +-- .../runtime/src/generic/unchecked_extrinsic.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 0994240a0cdbc..f31ff54e519ed 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -30,8 +30,7 @@ use crate::{ use codec::Encode; use sp_weights::Weight; -/// Version 0 of the transaction extension version used to construct the inherited -/// implication for legacy transactions. +/// Version 0 of the transaction extension version. const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// The kind of extrinsic this is, including any fields required of that kind. This is basically diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 0ca51113c6072..b9671f88a5e40 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -403,7 +403,14 @@ where ExtensionV0: StaticTypeInfo, ExtensionOtherVersions: StaticTypeInfo, { - type Identity = UncheckedExtrinsic; + type Identity = UncheckedExtrinsic< + Address, + Call, + Signature, + ExtensionV0, + ExtensionOtherVersions, + MAX_CALL_SIZE, + >; fn type_info() -> Type { Type::builder() From 31ea43d6a77b8c388b3a705fcbd144aca0c91f08 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 1 Jan 2026 13:46:45 +0900 Subject: [PATCH 36/56] better rename + impl revive --- .../assets/asset-hub-westend/src/lib.rs | 4 +- .../runtimes/testing/penpal/src/lib.rs | 4 +- substrate/bin/node/runtime/src/lib.rs | 4 +- .../frame/revive/dev-node/runtime/src/lib.rs | 4 +- substrate/frame/revive/src/evm/fees.rs | 2 +- substrate/frame/revive/src/evm/runtime.rs | 117 ++++++++++++++---- substrate/frame/revive/src/tests.rs | 4 +- .../src/construct_runtime/expand/metadata.rs | 4 +- substrate/primitives/metadata-ir/src/lib.rs | 2 +- substrate/primitives/metadata-ir/src/types.rs | 4 +- substrate/primitives/metadata-ir/src/v14.rs | 2 +- substrate/primitives/metadata-ir/src/v15.rs | 2 +- .../src/generic/unchecked_extrinsic.rs | 2 +- .../primitives/runtime/src/traits/mod.rs | 4 +- 14 files changed, 112 insertions(+), 47 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 8b9cbf66015c7..1d59445d7febe 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1439,9 +1439,9 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Runtime; - type Extension = TxExtension; + type ExtensionV0 = TxExtension; - fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension { + fn get_eth_extension(nonce: u32, tip: Balance) -> Self::ExtensionV0 { ( frame_system::AuthorizeCall::::new(), frame_system::CheckNonZeroSender::::new(), diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index bc018b160f778..7ea2323c83493 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -154,9 +154,9 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Runtime; - type Extension = TxExtension; + type ExtensionV0 = TxExtension; - fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension { + fn get_eth_extension(nonce: u32, tip: Balance) -> Self::ExtensionV0 { ( frame_system::AuthorizeCall::::new(), frame_system::CheckNonZeroSender::::new(), diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 6f1170651bc0c..8976cbe674391 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2910,9 +2910,9 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Runtime; - type Extension = TxExtension; + type ExtensionV0 = TxExtension; - fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension { + fn get_eth_extension(nonce: u32, tip: Balance) -> Self::ExtensionV0 { ( frame_system::AuthorizeCall::::new(), frame_system::CheckNonZeroSender::::new(), diff --git a/substrate/frame/revive/dev-node/runtime/src/lib.rs b/substrate/frame/revive/dev-node/runtime/src/lib.rs index dd3c3fade71a2..a9ee8ec552d08 100644 --- a/substrate/frame/revive/dev-node/runtime/src/lib.rs +++ b/substrate/frame/revive/dev-node/runtime/src/lib.rs @@ -189,9 +189,9 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Runtime; - type Extension = TxExtension; + type ExtensionV0 = TxExtension; - fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension { + fn get_eth_extension(nonce: u32, tip: Balance) -> Self::ExtensionV0 { ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), diff --git a/substrate/frame/revive/src/evm/fees.rs b/substrate/frame/revive/src/evm/fees.rs index 4722d333d596d..dbe5f98ed619b 100644 --- a/substrate/frame/revive/src/evm/fees.rs +++ b/substrate/frame/revive/src/evm/fees.rs @@ -210,7 +210,7 @@ where Dispatchable, CallOf: SetWeightLimit, <::Block as BlockT>::Extrinsic: - From, Signature, E::Extension>>, + From, Signature, E::ExtensionV0>>, <::OnChargeTransaction as TxCreditHold>::Credit: SuppressedDrop>, { diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 62a182341fdb1..307b1a5d03617 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -39,7 +39,7 @@ use sp_runtime::{ generic::{self, CheckedExtrinsic, ExtrinsicFormat}, traits::{ Checkable, ExtrinsicCall, ExtrinsicLike, ExtrinsicMetadata, LazyExtrinsic, - TransactionExtension, + TransactionExtension, VersTxExtLine, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, Debug, OpaqueExtrinsic, Weight, @@ -57,28 +57,58 @@ pub trait SetWeightLimit { /// [`crate::Call::eth_transact`] extrinsic. #[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug)] pub struct UncheckedExtrinsic( - pub generic::UncheckedExtrinsic, Signature, E::Extension>, + pub generic::UncheckedExtrinsic< + Address, + CallOf, + Signature, + E::ExtensionV0, + E::ExtensionOtherVersions, + >, ); impl TypeInfo for UncheckedExtrinsic where Address: StaticTypeInfo, Signature: StaticTypeInfo, - E::Extension: StaticTypeInfo, + E::ExtensionV0: StaticTypeInfo, { - type Identity = - generic::UncheckedExtrinsic, Signature, E::Extension>; + type Identity = generic::UncheckedExtrinsic< + Address, + CallOf, + Signature, + E::ExtensionV0, + E::ExtensionOtherVersions, + >; fn type_info() -> scale_info::Type { - generic::UncheckedExtrinsic::, Signature, E::Extension>::type_info() + generic::UncheckedExtrinsic::< + Address, + CallOf, + Signature, + E::ExtensionV0, + E::ExtensionOtherVersions, + >::type_info() } } impl - From, Signature, E::Extension>> - for UncheckedExtrinsic + From< + generic::UncheckedExtrinsic< + Address, + CallOf, + Signature, + E::ExtensionV0, + E::ExtensionOtherVersions, + >, + > for UncheckedExtrinsic { fn from( - utx: generic::UncheckedExtrinsic, Signature, E::Extension>, + utx: generic::UncheckedExtrinsic< + Address, + CallOf, + Signature, + E::ExtensionV0, + E::ExtensionOtherVersions, + >, ) -> Self { Self(utx) } @@ -99,14 +129,16 @@ impl ExtrinsicMetadata Address, CallOf, Signature, - E::Extension, + E::ExtensionV0, + E::ExtensionOtherVersions, >::VERSIONS; - type TransactionExtensions = E::Extension; + type TransactionExtensionsV0 = E::ExtensionV0; type TransactionExtensionsVersions = , Signature, - E::Extension, + E::ExtensionV0, + E::ExtensionOtherVersions, > as ExtrinsicMetadata>::TransactionExtensionsVersions; } @@ -132,13 +164,28 @@ where ::Nonce: TryFrom, CallOf: SetWeightLimit, // required by Checkable for `generic::UncheckedExtrinsic` - generic::UncheckedExtrinsic, Signature, E::Extension>: - Checkable< - Lookup, - Checked = CheckedExtrinsic, CallOf, E::Extension>, + generic::UncheckedExtrinsic< + LookupSource, + CallOf, + Signature, + E::ExtensionV0, + E::ExtensionOtherVersions, + >: Checkable< + Lookup, + Checked = CheckedExtrinsic< + AccountIdOf, + CallOf, + E::ExtensionV0, + E::ExtensionOtherVersions, >, + >, { - type Checked = CheckedExtrinsic, CallOf, E::Extension>; + type Checked = CheckedExtrinsic< + AccountIdOf, + CallOf, + E::ExtensionV0, + E::ExtensionOtherVersions, + >; fn check(self, lookup: &Lookup) -> Result { if !self.0.is_signed() { @@ -196,17 +243,17 @@ impl SignedTransactionBuilder where Address: TypeInfo, Signature: TypeInfo, - E::Extension: TypeInfo, + E::ExtensionV0: TypeInfo, { type Address = Address; type Signature = Signature; - type Extension = E::Extension; + type Extension = E::ExtensionV0; fn new_signed_transaction( call: Self::Call, signed: Address, signature: Signature, - tx_ext: E::Extension, + tx_ext: E::ExtensionV0, ) -> Self { generic::UncheckedExtrinsic::new_signed(call, signed, signature, tx_ext).into() } @@ -216,7 +263,7 @@ impl InherentBuilder for UncheckedExtrinsic Self { generic::UncheckedExtrinsic::new_bare(call).into() @@ -228,7 +275,7 @@ impl From) -> Self { extrinsic.0.into() @@ -237,7 +284,13 @@ where impl LazyExtrinsic for UncheckedExtrinsic where - generic::UncheckedExtrinsic, Signature, E::Extension>: LazyExtrinsic, + generic::UncheckedExtrinsic< + Address, + CallOf, + Signature, + E::ExtensionV0, + E::ExtensionOtherVersions, + >: LazyExtrinsic, { fn decode_unprefixed(data: &[u8]) -> Result { Ok(Self(LazyExtrinsic::decode_unprefixed(data)?)) @@ -249,11 +302,16 @@ pub trait EthExtra { /// The Runtime configuration. type Config: Config + TxConfig; - /// The Runtime's transaction extension. + /// The Runtime's transaction extension version 0. /// It should include at least: /// - [`frame_system::CheckNonce`] to ensure that the nonce from the Ethereum transaction is /// correct. - type Extension: TransactionExtension>; + type ExtensionV0: TransactionExtension>; + + /// The Runtime's transaction extension versions other than 0. + /// + /// Use [`sp_runtime::traits::InvalidVersion`] if no other versions should be supported. + type ExtensionOtherVersions: VersTxExtLine>; /// Get the transaction extension to apply to an unsigned [`crate::Call::eth_transact`] /// extrinsic. @@ -264,7 +322,7 @@ pub trait EthExtra { fn get_eth_extension( nonce: ::Nonce, tip: BalanceOf, - ) -> Self::Extension; + ) -> Self::ExtensionV0; /// Convert the unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. /// and ensure that the fees from the Ethereum transaction correspond to the fees computed from @@ -277,7 +335,12 @@ pub trait EthExtra { payload: &[u8], encoded_len: usize, ) -> Result< - CheckedExtrinsic, CallOf, Self::Extension>, + CheckedExtrinsic< + AccountIdOf, + CallOf, + Self::ExtensionV0, + Self::ExtensionOtherVersions, + >, InvalidTransaction, > where diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 0af794f6ec7e3..5328f4eb10858 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -70,9 +70,9 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Test; - type Extension = SignedExtra; + type ExtensionV0 = SignedExtra; - fn get_eth_extension(nonce: u32, tip: BalanceOf) -> Self::Extension { + fn get_eth_extension(nonce: u32, tip: BalanceOf) -> Self::ExtensionV0 { ( frame_system::CheckNonce::from(nonce), ChargeTransactionPayment::from(tip), diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index a275ae794a174..a3cf13172188e 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -133,10 +133,10 @@ pub fn expand_runtime_metadata( call_ty, signature_ty, extra_ty, - extensions: < + extensions_v0: < < #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata - >::TransactionExtensions + >::TransactionExtensionsV0 as #scrate::sp_runtime::traits::TransactionExtension::< <#runtime as #system_path::Config>::RuntimeCall diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index a8cbbd246049b..f66f2e83ca5b8 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -119,7 +119,7 @@ mod test { call_ty: meta_type::<()>(), signature_ty: meta_type::<()>(), extra_ty: meta_type::<()>(), - extensions: vec![], + extensions_v0: vec![], extensions_by_version: Default::default(), extensions_in_versions: vec![], }, diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index 82cd677bb48cc..7c9670238bd5c 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -244,7 +244,7 @@ pub struct ExtrinsicMetadataIR { // TODO: metadata-v16: remove this, the `implicit` type can be found in `extensions::implicit`. pub extra_ty: T::Type, /// The transaction extensions in the order they appear in the extrinsic for the version 0. - pub extensions: Vec>, + pub extensions_v0: Vec>, /// The transaction extensions for each version as a list of index in reference to items in /// `extensions_in_versions` field. pub extensions_by_version: BTreeMap>, @@ -263,7 +263,7 @@ impl IntoPortable for ExtrinsicMetadataIR { call_ty: registry.register_type(&self.call_ty), signature_ty: registry.register_type(&self.signature_ty), extra_ty: registry.register_type(&self.extra_ty), - extensions: registry.map_into_portable(self.extensions), + extensions_v0: registry.map_into_portable(self.extensions_v0), extensions_by_version: self.extensions_by_version, extensions_in_versions: registry.map_into_portable(self.extensions_in_versions), } diff --git a/substrate/primitives/metadata-ir/src/v14.rs b/substrate/primitives/metadata-ir/src/v14.rs index f3cb5973f5bdc..45f6fc49798f7 100644 --- a/substrate/primitives/metadata-ir/src/v14.rs +++ b/substrate/primitives/metadata-ir/src/v14.rs @@ -155,7 +155,7 @@ impl From for ExtrinsicMetadata { ExtrinsicMetadata { ty: ir.ty, version: *lowest_supported_version, - signed_extensions: ir.extensions.into_iter().map(Into::into).collect(), + signed_extensions: ir.extensions_v0.into_iter().map(Into::into).collect(), } } } diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index 1bfad0bd355f1..ef004684d5198 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -101,7 +101,7 @@ impl From for ExtrinsicMetadata { call_ty: ir.call_ty, signature_ty: ir.signature_ty, extra_ty: ir.extra_ty, - signed_extensions: ir.extensions.into_iter().map(Into::into).collect(), + signed_extensions: ir.extensions_v0.into_iter().map(Into::into).collect(), } } } diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index b9671f88a5e40..30a60e9a18a3e 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -703,7 +703,7 @@ impl< > { const VERSIONS: &'static [u8] = &[LEGACY_EXTRINSIC_FORMAT_VERSION, EXTRINSIC_FORMAT_VERSION]; - type TransactionExtensions = ExtensionV0; + type TransactionExtensionsV0 = ExtensionV0; type TransactionExtensionsVersions = ExtensionVariant; } diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index 4826f3282e219..a5089f43aede8 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -1503,7 +1503,9 @@ pub trait ExtrinsicMetadata { const VERSIONS: &'static [u8]; /// The transaction extensions version 0 attached to this `Extrinsic`. - type TransactionExtensions; + // We could remove this associated type and let user retrieve it from + // `TransactionExtensionsVersions`. + type TransactionExtensionsV0; /// All version of transaction extensions attached to this `Extrinsic`. type TransactionExtensionsVersions; From b2621eb6d01a2b9dd7236193af108b1725bccf9c Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 1 Jan 2026 13:58:31 +0900 Subject: [PATCH 37/56] prdoc --- prdoc/pr_7035.prdoc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/prdoc/pr_7035.prdoc b/prdoc/pr_7035.prdoc index 922a0f300c11b..ed95006ad1cce 100644 --- a/prdoc/pr_7035.prdoc +++ b/prdoc/pr_7035.prdoc @@ -3,14 +3,17 @@ title: Allow declaration and usage of multiple transaction extension version in doc: - audience: Runtime Dev description: | - This PR enhance `UncheckedExtrinsic` type with a new optional generic: `ExtensionOtherVersion`. + This PR enhance `UncheckedExtrinsic` type with a new optional generic: `ExtensionOtherVersions`. This generic defaults to `InvalidVersion` meaning there is not other version than the regular version 0. This is the same behavior as before this PR. # Breaking change The types `Preamble`, `CheckedExtrinsic` and `ExtrinsicFormat` also have this new optional generic. Their type definition also have changed a bit, the `General` variant was 2 fields, the version and the extension, it is now only one field, the extension, and the version can be retrieve by calling `extension.version()` - The type inference for those types may fail because of this PR, to update the code, write some partial type: `UncheckedExtrinsic<_, _, _, _>`, `Preamble<_, _, _>`, `ExtrinsicFormat<_, _> and `CheckedExtrinsic<_, _, _>`. + Some trait such as `ExtrinsicMetadata` and `EthExtraImpl` changed their associated type named `Extension` to `ExtensionV0` and have new associated type `ExtensionOtherVersions`. This is because multiple version are now supported. + You can always use `InvalidVersions` for `ExtensionOtherVersions` and keep the old `Extension` for `ExtensionV0` to keep the same behavior as before this PR. + + The type inference for those types may fail because of this PR, to update the code by writing the concrete types. # New feature From 8284dc8ed2ca3d7eb49829642f01bedc57e7e912 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 1 Jan 2026 14:05:49 +0900 Subject: [PATCH 38/56] fix revive --- .../runtimes/assets/asset-hub-westend/src/lib.rs | 1 + cumulus/parachains/runtimes/testing/penpal/src/lib.rs | 1 + substrate/bin/node/runtime/src/lib.rs | 1 + substrate/frame/revive/dev-node/runtime/src/lib.rs | 1 + substrate/frame/revive/src/evm/fees.rs | 11 +++++++++-- substrate/frame/revive/src/tests.rs | 1 + 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 1d59445d7febe..70e421c841f4e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1440,6 +1440,7 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Runtime; type ExtensionV0 = TxExtension; + type ExtensionOtherVersions = sp_runtime::traits::InvalidVersion; fn get_eth_extension(nonce: u32, tip: Balance) -> Self::ExtensionV0 { ( diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 7ea2323c83493..b87b2a0bca7c9 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -155,6 +155,7 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Runtime; type ExtensionV0 = TxExtension; + type ExtensionOtherVersions = sp_runtime::traits::InvalidVersion; fn get_eth_extension(nonce: u32, tip: Balance) -> Self::ExtensionV0 { ( diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 8976cbe674391..835bddfc5c053 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2911,6 +2911,7 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Runtime; type ExtensionV0 = TxExtension; + type ExtensionOtherVersions = sp_runtime::traits::InvalidVersion; fn get_eth_extension(nonce: u32, tip: Balance) -> Self::ExtensionV0 { ( diff --git a/substrate/frame/revive/dev-node/runtime/src/lib.rs b/substrate/frame/revive/dev-node/runtime/src/lib.rs index a9ee8ec552d08..ac858168a8832 100644 --- a/substrate/frame/revive/dev-node/runtime/src/lib.rs +++ b/substrate/frame/revive/dev-node/runtime/src/lib.rs @@ -190,6 +190,7 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Runtime; type ExtensionV0 = TxExtension; + type ExtensionOtherVersions = sp_runtime::traits::InvalidVersion; fn get_eth_extension(nonce: u32, tip: Balance) -> Self::ExtensionV0 { ( diff --git a/substrate/frame/revive/src/evm/fees.rs b/substrate/frame/revive/src/evm/fees.rs index dbe5f98ed619b..8bbeb88d9df71 100644 --- a/substrate/frame/revive/src/evm/fees.rs +++ b/substrate/frame/revive/src/evm/fees.rs @@ -209,8 +209,15 @@ where ::RuntimeCall: Dispatchable, CallOf: SetWeightLimit, - <::Block as BlockT>::Extrinsic: - From, Signature, E::ExtensionV0>>, + <::Block as BlockT>::Extrinsic: From< + UncheckedExtrinsic< + Address, + CallOf, + Signature, + E::ExtensionV0, + E::ExtensionOtherVersions, + >, + >, <::OnChargeTransaction as TxCreditHold>::Credit: SuppressedDrop>, { diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 5328f4eb10858..07b7169caaa99 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -71,6 +71,7 @@ pub struct EthExtraImpl; impl EthExtra for EthExtraImpl { type Config = Test; type ExtensionV0 = SignedExtra; + type ExtensionOtherVersions = sp_runtime::traits::InvalidVersion; fn get_eth_extension(nonce: u32, tip: BalanceOf) -> Self::ExtensionV0 { ( From acf6904ea3a439ed9b08fd9564b2cc7b47f6ed42 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Fri, 9 Jan 2026 12:37:16 +0900 Subject: [PATCH 39/56] Apply suggestions from code review Co-authored-by: Francisco Aguirre --- prdoc/pr_7035.prdoc | 6 +++--- .../primitives/runtime/src/generic/checked_extrinsic.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/prdoc/pr_7035.prdoc b/prdoc/pr_7035.prdoc index ed95006ad1cce..c19e2288319f2 100644 --- a/prdoc/pr_7035.prdoc +++ b/prdoc/pr_7035.prdoc @@ -1,4 +1,4 @@ -title: Allow declaration and usage of multiple transaction extension version in FRAME and primitives +title: Allow declaration and usage of multiple transaction extension versions in FRAME and primitives doc: - audience: Runtime Dev @@ -8,10 +8,10 @@ doc: # Breaking change - The types `Preamble`, `CheckedExtrinsic` and `ExtrinsicFormat` also have this new optional generic. Their type definition also have changed a bit, the `General` variant was 2 fields, the version and the extension, it is now only one field, the extension, and the version can be retrieve by calling `extension.version()` + The types `Preamble`, `CheckedExtrinsic` and `ExtrinsicFormat` also have this new optional generic. Their type definitions also have changed a bit: the `General` variant was 2 fields, the version and the extension, it is now only one field, the extension, and the version can be retrieve by calling `extension.version()` Some trait such as `ExtrinsicMetadata` and `EthExtraImpl` changed their associated type named `Extension` to `ExtensionV0` and have new associated type `ExtensionOtherVersions`. This is because multiple version are now supported. - You can always use `InvalidVersions` for `ExtensionOtherVersions` and keep the old `Extension` for `ExtensionV0` to keep the same behavior as before this PR. + You can always use `InvalidVersion` for `ExtensionOtherVersions` and keep the old `Extension` for `ExtensionV0` to keep the same behavior as before this PR. The type inference for those types may fail because of this PR, to update the code by writing the concrete types. diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index f31ff54e519ed..d0b1956ddada2 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -65,7 +65,7 @@ pub enum ExtrinsicFormat Date: Fri, 9 Jan 2026 12:37:33 +0900 Subject: [PATCH 40/56] Update substrate/frame/support/test/tests/tx_ext_multi_version.rs Co-authored-by: Francisco Aguirre --- substrate/frame/support/test/tests/tx_ext_multi_version.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/test/tests/tx_ext_multi_version.rs b/substrate/frame/support/test/tests/tx_ext_multi_version.rs index 12947c28dcb4a..e17212529e1c5 100644 --- a/substrate/frame/support/test/tests/tx_ext_multi_version.rs +++ b/substrate/frame/support/test/tests/tx_ext_multi_version.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Test that FRAME support multiple version for transaction extension. +//! Test that FRAME support multiple versions for transaction extensions. use codec::{Decode, DecodeWithMemTracking, Encode}; use core::fmt::Debug; From 316e62319e4eb75959eb406a90f65c42abbab4c0 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Fri, 9 Jan 2026 12:37:42 +0900 Subject: [PATCH 41/56] Update substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs Co-authored-by: Francisco Aguirre --- substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 30a60e9a18a3e..4671d4b9498c0 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -271,7 +271,7 @@ where /// /// # Usage: /// -/// Usage with multiple version for general transaction. +/// Usage with multiple versions for general transaction. /// ``` /// use sp_runtime::{ /// generic::UncheckedExtrinsic, From 64cfd4c6c41743350231975eaa7981b597785fe4 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Fri, 9 Jan 2026 12:38:37 +0900 Subject: [PATCH 42/56] Apply suggestion from @franciscoaguirre Co-authored-by: Francisco Aguirre --- substrate/frame/support/test/tests/tx_ext_multi_version.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/test/tests/tx_ext_multi_version.rs b/substrate/frame/support/test/tests/tx_ext_multi_version.rs index e17212529e1c5..5a0bc3b76e2e0 100644 --- a/substrate/frame/support/test/tests/tx_ext_multi_version.rs +++ b/substrate/frame/support/test/tests/tx_ext_multi_version.rs @@ -212,7 +212,7 @@ fn dispatch_of_valid_extrinsic_succeeds() { fn dispatch_of_invalid_extrinsic_fails() { let mut ext = sp_io::TestExternalities::new(Default::default()); ext.execute_with(|| { - // Create an unchecked extrinsic with token=7 + // Create an unchecked extrinsic with token=0 // and set `AccountId=1` to simulate an authorized origin. let xt = UncheckedExtrinsic::from_parts( RuntimeCall::System(frame_system::Call::remark { remark: vec![1, 2] }), From 0071ee20cc5f03ca595d1b5a4c682004805f5ba6 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Fri, 9 Jan 2026 13:06:09 +0900 Subject: [PATCH 43/56] better doc and comments --- .../frame/support/test/tests/tx_ext_multi_version.rs | 12 +++++++----- .../primitives/runtime/src/traits/vers_tx_ext/mod.rs | 8 ++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/substrate/frame/support/test/tests/tx_ext_multi_version.rs b/substrate/frame/support/test/tests/tx_ext_multi_version.rs index 5a0bc3b76e2e0..0165d3209cf8c 100644 --- a/substrate/frame/support/test/tests/tx_ext_multi_version.rs +++ b/substrate/frame/support/test/tests/tx_ext_multi_version.rs @@ -38,6 +38,8 @@ use sp_runtime::{ DispatchResult, }; +// This transaction extension is valid iff `token != 0`, when valid the resulting origin is +// `frame_system::Origin::Signed(100)`. #[derive(Clone, Debug, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)] pub struct SimpleExt { pub token: u8, @@ -184,8 +186,8 @@ fn test_metadata() { fn dispatch_of_valid_extrinsic_succeeds() { let mut ext = sp_io::TestExternalities::new(Default::default()); ext.execute_with(|| { - // Create an unchecked extrinsic with token=7 - // and set `AccountId=1` to simulate an authorized origin. + // Create an unchecked extrinsic with transaction extension: token=7, + // This is valid and will result in a signed origin with account id `100`. let xt = UncheckedExtrinsic::from_parts( RuntimeCall::System(frame_system::Call::remark { remark: vec![1, 2] }), Preamble::General(ExtensionVariant::Other(OtherVersions::A(Ext4::new(SimpleExtV4 { @@ -212,8 +214,8 @@ fn dispatch_of_valid_extrinsic_succeeds() { fn dispatch_of_invalid_extrinsic_fails() { let mut ext = sp_io::TestExternalities::new(Default::default()); ext.execute_with(|| { - // Create an unchecked extrinsic with token=0 - // and set `AccountId=1` to simulate an authorized origin. + // Create an unchecked extrinsic with transaction extension: token=0, + // This is invalid as `SimpleExt` validation fails for token=0, let xt = UncheckedExtrinsic::from_parts( RuntimeCall::System(frame_system::Call::remark { remark: vec![1, 2] }), Preamble::General(ExtensionVariant::Other(OtherVersions::A(Ext4::new(SimpleExtV4 { @@ -230,7 +232,7 @@ fn dispatch_of_invalid_extrinsic_fails() { checked .validate::(TransactionSource::External, &info, len) - .expect_err("invalid"); + .expect_err("invalid, `SimpleExt` is invalid if token == 0"); checked.apply::(&info, len).expect_err("invalid"); }); diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 80cbf0aa577b4..8d28cc360b376 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -43,6 +43,9 @@ pub use variant::ExtensionVariant; /// /// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to /// rely only on it without bounding the whole trait [`VersTxExtLine`]. +/// +/// (type name is short for versioned (Vers) transaction (Tx) Extension (Ext) pipeline (Line) weight +/// (Weight)). pub trait VersTxExtLineWeight { /// Return the pre dispatch weight for the given versioned transaction extension pipeline and /// call. @@ -53,6 +56,9 @@ pub trait VersTxExtLineWeight { /// /// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to /// rely only on it without bounding the whole trait [`VersTxExtLine`]. +/// +/// (type name is short for versioned (Vers) transaction (Tx) Extension (Ext) pipeline (Line) +/// version (Version)). pub trait VersTxExtLineVersion { /// Return the version for the given versioned transaction extension pipeline. fn version(&self) -> u8; @@ -61,6 +67,8 @@ pub trait VersTxExtLineVersion { /// A versioned transaction extension pipeline. /// /// This defines multiple version of a transaction extensions pipeline. +/// +/// (type name is short for versioned (Vers) transaction (Tx) Extension (Ext) pipeline (Line)). pub trait VersTxExtLine: Encode + DecodeWithVersion From e071249e6f5cc29795ad6d5a89586b30919e3d15 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 22 Jan 2026 15:17:57 +0900 Subject: [PATCH 44/56] use unreachable --- .../primitives/runtime/src/traits/vers_tx_ext/invalid.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index 81ae6c530894e..16b7f0b2b070b 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -63,7 +63,7 @@ impl VersTxExtLine for InvalidVersion { _source: TransactionSource, ) -> Result { // The type cannot be instantiated so this method is never called. - Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))) + unreachable!() } fn dispatch_transaction( self, @@ -73,21 +73,21 @@ impl VersTxExtLine for InvalidVersion { _len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { // The type cannot be instantiated so this method is never called. - Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0)).into()) + unreachable!() } } impl VersTxExtLineVersion for InvalidVersion { fn version(&self) -> u8 { // The type cannot be instantiated so this method is never called. - 0 + unreachable!() } } impl VersTxExtLineWeight for InvalidVersion { fn weight(&self, _call: &Call) -> Weight { // The type cannot be instantiated so this method is never called. - Weight::zero() + unreachable!() } } From a9942a802927635cb9840179068dd8e024acc41d Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 22 Jan 2026 16:30:31 +0900 Subject: [PATCH 45/56] remove metadata ir extension v0 type --- .../src/construct_runtime/expand/metadata.rs | 16 ---------------- substrate/primitives/metadata-ir/src/lib.rs | 1 - substrate/primitives/metadata-ir/src/types.rs | 16 +++++++++++++--- substrate/primitives/metadata-ir/src/v14.rs | 4 +++- substrate/primitives/metadata-ir/src/v15.rs | 4 +++- substrate/primitives/runtime/src/traits/mod.rs | 8 +++----- 6 files changed, 22 insertions(+), 27 deletions(-) diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index a3cf13172188e..ba411d76e3c5e 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -133,22 +133,6 @@ pub fn expand_runtime_metadata( call_ty, signature_ty, extra_ty, - extensions_v0: < - < - #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata - >::TransactionExtensionsV0 - as - #scrate::sp_runtime::traits::TransactionExtension::< - <#runtime as #system_path::Config>::RuntimeCall - > - >::metadata() - .into_iter() - .map(|meta| #scrate::__private::metadata_ir::TransactionExtensionMetadataIR { - identifier: meta.identifier, - ty: meta.ty, - implicit: meta.implicit, - }) - .collect(), extensions_by_version: versioned_extensions_metadata.by_version, extensions_in_versions: versioned_extensions_metadata.in_versions .into_iter() diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index f66f2e83ca5b8..f5e2f2bbe4524 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -119,7 +119,6 @@ mod test { call_ty: meta_type::<()>(), signature_ty: meta_type::<()>(), extra_ty: meta_type::<()>(), - extensions_v0: vec![], extensions_by_version: Default::default(), extensions_in_versions: vec![], }, diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index 7c9670238bd5c..d464fd295ee1b 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -243,8 +243,6 @@ pub struct ExtrinsicMetadataIR { /// The type of the outermost Extra/Extensions enum. // TODO: metadata-v16: remove this, the `implicit` type can be found in `extensions::implicit`. pub extra_ty: T::Type, - /// The transaction extensions in the order they appear in the extrinsic for the version 0. - pub extensions_v0: Vec>, /// The transaction extensions for each version as a list of index in reference to items in /// `extensions_in_versions` field. pub extensions_by_version: BTreeMap>, @@ -252,6 +250,19 @@ pub struct ExtrinsicMetadataIR { pub extensions_in_versions: Vec>, } +impl ExtrinsicMetadataIR { + /// The transaction extensions in the order they appear in the extrinsic for the version 0 if + /// defined. + pub fn extensions_v0(&self) -> Option> { + self.extensions_by_version.get(&0).map(|indices| { + indices + .iter() + .map(|i| self.extensions_in_versions[*i as usize].clone()) + .collect() + }) + } +} + impl IntoPortable for ExtrinsicMetadataIR { type Output = ExtrinsicMetadataIR; @@ -263,7 +274,6 @@ impl IntoPortable for ExtrinsicMetadataIR { call_ty: registry.register_type(&self.call_ty), signature_ty: registry.register_type(&self.signature_ty), extra_ty: registry.register_type(&self.extra_ty), - extensions_v0: registry.map_into_portable(self.extensions_v0), extensions_by_version: self.extensions_by_version, extensions_in_versions: registry.map_into_portable(self.extensions_in_versions), } diff --git a/substrate/primitives/metadata-ir/src/v14.rs b/substrate/primitives/metadata-ir/src/v14.rs index 45f6fc49798f7..c1fa407c7c469 100644 --- a/substrate/primitives/metadata-ir/src/v14.rs +++ b/substrate/primitives/metadata-ir/src/v14.rs @@ -155,7 +155,9 @@ impl From for ExtrinsicMetadata { ExtrinsicMetadata { ty: ir.ty, version: *lowest_supported_version, - signed_extensions: ir.extensions_v0.into_iter().map(Into::into).collect(), + signed_extensions: ir.extensions_v0() + .expect("Metadata V14 expect a defined transaction extenstion pipeline version 0") + .into_iter().map(Into::into).collect(), } } } diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index ef004684d5198..83b54b91bc063 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -101,7 +101,9 @@ impl From for ExtrinsicMetadata { call_ty: ir.call_ty, signature_ty: ir.signature_ty, extra_ty: ir.extra_ty, - signed_extensions: ir.extensions_v0.into_iter().map(Into::into).collect(), + signed_extensions: ir.extensions_v0() + .expect("Metadata V15 expect a defined transaction extenstion pipeline version 0") + .into_iter().map(Into::into).collect(), } } } diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index a5089f43aede8..8319e17b9df48 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -1502,12 +1502,10 @@ pub trait ExtrinsicMetadata { /// By format we mean the encoded representation of the `Extrinsic`. const VERSIONS: &'static [u8]; - /// The transaction extensions version 0 attached to this `Extrinsic`. - // We could remove this associated type and let user retrieve it from - // `TransactionExtensionsVersions`. - type TransactionExtensionsV0; - /// All version of transaction extensions attached to this `Extrinsic`. + /// + /// For the transaction extension pipeline used for the signed extrinsics it is defined as the + /// version 0, if defined. type TransactionExtensionsVersions; } From a49294c8cc058e529dba2f2c4874de83b6b61279 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 22 Jan 2026 16:44:28 +0900 Subject: [PATCH 46/56] remove ExtensionV0 type in metadata --- Cargo.lock | 1 + substrate/frame/revive/src/evm/runtime.rs | 1 - substrate/primitives/metadata-ir/Cargo.toml | 1 + substrate/primitives/metadata-ir/src/types.rs | 66 ++++++++++++------- substrate/primitives/metadata-ir/src/v14.rs | 7 +- substrate/primitives/metadata-ir/src/v15.rs | 7 +- .../src/generic/unchecked_extrinsic.rs | 1 - 7 files changed, 56 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a959ef0c98433..d0b20c8c68f69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23176,6 +23176,7 @@ dependencies = [ name = "sp-metadata-ir" version = "0.6.0" dependencies = [ + "derive-where", "frame-metadata 23.0.1", "parity-scale-codec", "scale-info", diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 307b1a5d03617..2d2056fe2c8a5 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -132,7 +132,6 @@ impl ExtrinsicMetadata E::ExtensionV0, E::ExtensionOtherVersions, >::VERSIONS; - type TransactionExtensionsV0 = E::ExtensionV0; type TransactionExtensionsVersions = , diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index d7786347dd028..c7db98b51568d 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -19,6 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { workspace = true } frame-metadata = { features = ["current"], workspace = true } scale-info = { features = ["derive"], workspace = true } +derive-where = { workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index d464fd295ee1b..6e8f8757249b0 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -16,6 +16,7 @@ // limitations under the License. use codec::{Compact, Decode, Encode}; +use derive_where::derive_where; use scale_info::{ form::{Form, MetaForm, PortableForm}, prelude::{collections::BTreeMap, vec::Vec}, @@ -44,7 +45,8 @@ pub struct MetadataIR { } /// Metadata of a runtime trait. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct RuntimeApiMetadataIR { /// Trait name. pub name: T::String, @@ -73,7 +75,8 @@ impl IntoPortable for RuntimeApiMetadataIR { } /// Metadata of a runtime method. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct RuntimeApiMethodMetadataIR { /// Method name. pub name: T::String, @@ -102,7 +105,8 @@ impl IntoPortable for RuntimeApiMethodMetadataIR { } /// Metadata of a runtime method parameter. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct RuntimeApiMethodParamMetadataIR { /// Parameter name. pub name: T::String, @@ -122,7 +126,8 @@ impl IntoPortable for RuntimeApiMethodParamMetadataIR { } /// Metadata of a pallet view function method. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] +#[derive(Encode, Decode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletViewFunctionMetadataIR { /// Method name. pub name: T::String, @@ -154,7 +159,8 @@ impl IntoPortable for PalletViewFunctionMetadataIR { } /// Metadata of a pallet view function method argument. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] +#[derive(Encode, Decode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletViewFunctionParamMetadataIR { /// Parameter name. pub name: T::String, @@ -174,7 +180,8 @@ impl IntoPortable for PalletViewFunctionParamMetadataIR { } /// The intermediate representation for a pallet metadata. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletMetadataIR { /// Pallet name. pub name: T::String, @@ -226,7 +233,8 @@ impl IntoPortable for PalletMetadataIR { } /// Metadata of the extrinsic used by the runtime. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct ExtrinsicMetadataIR { /// The type of the extrinsic. /// @@ -250,10 +258,10 @@ pub struct ExtrinsicMetadataIR { pub extensions_in_versions: Vec>, } -impl ExtrinsicMetadataIR { +impl ExtrinsicMetadataIR { /// The transaction extensions in the order they appear in the extrinsic for the version 0 if /// defined. - pub fn extensions_v0(&self) -> Option> { + pub fn extensions_v0(&self) -> Option>> { self.extensions_by_version.get(&0).map(|indices| { indices .iter() @@ -281,7 +289,8 @@ impl IntoPortable for ExtrinsicMetadataIR { } /// Metadata of a pallet's associated type. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletAssociatedTypeMetadataIR { /// The name of the associated type. pub name: T::String, @@ -304,7 +313,8 @@ impl IntoPortable for PalletAssociatedTypeMetadataIR { } /// Metadata of an extrinsic's signed extension. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct TransactionExtensionMetadataIR { /// The unique signed extension identifier, which may be different from the type name. pub identifier: T::String, @@ -327,8 +337,10 @@ impl IntoPortable for TransactionExtensionMetadataIR { } /// All metadata of the pallet's storage. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +/// /// The common prefix used by all storage entries. +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletStorageMetadataIR { /// The common prefix used by all storage entries. pub prefix: T::String, @@ -348,7 +360,8 @@ impl IntoPortable for PalletStorageMetadataIR { } /// Metadata about one storage entry. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct StorageEntryMetadataIR { /// Variable name of the storage entry. pub name: T::String, @@ -414,7 +427,8 @@ pub enum StorageHasherIR { } /// A type of storage value. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub enum StorageEntryTypeIR { /// Plain storage entry (just the value). Plain(T::Type), @@ -445,7 +459,8 @@ impl IntoPortable for StorageEntryTypeIR { } /// Metadata for all calls in a pallet -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletCallMetadataIR { /// The corresponding enum type for the pallet call. pub ty: T::Type, @@ -465,7 +480,8 @@ impl IntoPortable for PalletCallMetadataIR { } /// Metadata about the pallet Event type. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletEventMetadataIR { /// The Event type. pub ty: T::Type, @@ -485,7 +501,8 @@ impl IntoPortable for PalletEventMetadataIR { } /// Metadata about one pallet constant. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletConstantMetadataIR { /// Name of the pallet constant. pub name: T::String, @@ -514,7 +531,8 @@ impl IntoPortable for PalletConstantMetadataIR { } /// Metadata about a pallet error. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct PalletErrorMetadataIR { /// The error type information. pub ty: T::Type, @@ -534,7 +552,8 @@ impl IntoPortable for PalletErrorMetadataIR { } /// The type of the outer enums. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct OuterEnumsIR { /// The type of the outer `RuntimeCall` enum. pub call_enum_ty: T::Type, @@ -571,7 +590,8 @@ impl IntoPortable for OuterEnumsIR { } /// Deprecation information for generic items. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub enum ItemDeprecationInfoIR { /// Item is not deprecated. NotDeprecated, @@ -604,7 +624,8 @@ impl IntoPortable for ItemDeprecationInfoIR { /// Deprecation information for enums in which specific variants can be deprecated. /// If the map is empty, then nothing is deprecated. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub struct EnumDeprecationInfoIR(pub BTreeMap>); impl EnumDeprecationInfoIR { @@ -634,7 +655,8 @@ impl IntoPortable for EnumDeprecationInfoIR { } /// Deprecation information for an item or variant in the metadata. -#[derive(Clone, PartialEq, Eq, Encode, Debug)] +#[derive(Encode)] +#[derive_where(Clone, PartialEq, Eq, Debug;)] pub enum VariantDeprecationInfoIR { /// Variant is deprecated without a note. DeprecatedWithoutNote, diff --git a/substrate/primitives/metadata-ir/src/v14.rs b/substrate/primitives/metadata-ir/src/v14.rs index c1fa407c7c469..a8a528e8bf101 100644 --- a/substrate/primitives/metadata-ir/src/v14.rs +++ b/substrate/primitives/metadata-ir/src/v14.rs @@ -155,9 +155,12 @@ impl From for ExtrinsicMetadata { ExtrinsicMetadata { ty: ir.ty, version: *lowest_supported_version, - signed_extensions: ir.extensions_v0() + signed_extensions: ir + .extensions_v0() .expect("Metadata V14 expect a defined transaction extenstion pipeline version 0") - .into_iter().map(Into::into).collect(), + .into_iter() + .map(Into::into) + .collect(), } } } diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index 83b54b91bc063..371b1b1fcd820 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -101,9 +101,12 @@ impl From for ExtrinsicMetadata { call_ty: ir.call_ty, signature_ty: ir.signature_ty, extra_ty: ir.extra_ty, - signed_extensions: ir.extensions_v0() + signed_extensions: ir + .extensions_v0() .expect("Metadata V15 expect a defined transaction extenstion pipeline version 0") - .into_iter().map(Into::into).collect(), + .into_iter() + .map(Into::into) + .collect(), } } } diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 4671d4b9498c0..facd125f08895 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -703,7 +703,6 @@ impl< > { const VERSIONS: &'static [u8] = &[LEGACY_EXTRINSIC_FORMAT_VERSION, EXTRINSIC_FORMAT_VERSION]; - type TransactionExtensionsV0 = ExtensionV0; type TransactionExtensionsVersions = ExtensionVariant; } From 5bb9d50834eac9dd8e763c1c240af49ffa8c7043 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Thu, 22 Jan 2026 20:13:50 +0900 Subject: [PATCH 47/56] rename --- prdoc/pr_7035.prdoc | 6 ++-- substrate/frame/revive/src/evm/runtime.rs | 8 ++--- .../src/construct_runtime/expand/metadata.rs | 6 ++-- substrate/frame/support/src/dispatch.rs | 4 +-- .../test/tests/tx_ext_multi_version.rs | 4 +-- .../runtime/src/generic/checked_extrinsic.rs | 6 ++-- .../src/generic/unchecked_extrinsic.rs | 20 +++++------ .../primitives/runtime/src/traits/mod.rs | 6 ++-- .../runtime/src/traits/vers_tx_ext/at_vers.rs | 26 +++++++------- .../runtime/src/traits/vers_tx_ext/invalid.rs | 14 ++++---- .../runtime/src/traits/vers_tx_ext/mod.rs | 36 +++++++++---------- .../runtime/src/traits/vers_tx_ext/multi.rs | 34 +++++++++--------- .../runtime/src/traits/vers_tx_ext/variant.rs | 24 ++++++------- 13 files changed, 96 insertions(+), 98 deletions(-) diff --git a/prdoc/pr_7035.prdoc b/prdoc/pr_7035.prdoc index c19e2288319f2..87770c83e0fd0 100644 --- a/prdoc/pr_7035.prdoc +++ b/prdoc/pr_7035.prdoc @@ -17,7 +17,7 @@ doc: # New feature - To use this new feature, you can use the new types `TxExtLineAtVers` and `MultiVersion` to define a transaction extension with multiple version: + To use this new feature, you can use the new types `PipelineAtVers` and `MultiVersion` to define a transaction extension with multiple version: ```rust pub type TransactionExtensionV0 = (); @@ -25,8 +25,8 @@ doc: pub type TransactionExtensionV7 = (); pub type OtherVersions = MultiVersion< - TxExtLineAtVers<4, TransactionExtensionV4>; - TxExtLineAtVers<7, TransactionExtensionV7>; + PipelineAtVers<4, TransactionExtensionV4>; + PipelineAtVers<7, TransactionExtensionV7>; >; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic< diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 2d2056fe2c8a5..3ac734869470b 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -39,7 +39,7 @@ use sp_runtime::{ generic::{self, CheckedExtrinsic, ExtrinsicFormat}, traits::{ Checkable, ExtrinsicCall, ExtrinsicLike, ExtrinsicMetadata, LazyExtrinsic, - TransactionExtension, VersTxExtLine, + TransactionExtension, Pipeline, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, Debug, OpaqueExtrinsic, Weight, @@ -132,13 +132,13 @@ impl ExtrinsicMetadata E::ExtensionV0, E::ExtensionOtherVersions, >::VERSIONS; - type TransactionExtensionsVersions = , Signature, E::ExtensionV0, E::ExtensionOtherVersions, - > as ExtrinsicMetadata>::TransactionExtensionsVersions; + > as ExtrinsicMetadata>::TransactionExtensionPipelines; } impl ExtrinsicCall @@ -310,7 +310,7 @@ pub trait EthExtra { /// The Runtime's transaction extension versions other than 0. /// /// Use [`sp_runtime::traits::InvalidVersion`] if no other versions should be supported. - type ExtensionOtherVersions: VersTxExtLine>; + type ExtensionOtherVersions: Pipeline>; /// Get the transaction extension to apply to an unsigned [`crate::Call::eth_transact`] /// extrinsic. diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index ba411d76e3c5e..3afaf0b961f53 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -112,14 +112,14 @@ pub fn expand_runtime_metadata( let mut versioned_extensions_metadata = - #scrate::sp_runtime::traits::VersTxExtLineMetadataBuilder::new(); + #scrate::sp_runtime::traits::PipelineMetadataBuilder::new(); < < #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata - >::TransactionExtensionsVersions + >::TransactionExtensionPipelines as - #scrate::sp_runtime::traits::VersTxExtLine::< + #scrate::sp_runtime::traits::Pipeline::< <#runtime as #system_path::Config>::RuntimeCall > >::build_metadata(&mut versioned_extensions_metadata); diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 30dbfb2260935..d11e00e1d191c 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -412,7 +412,7 @@ impl GetDispatchI where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: sp_runtime::traits::VersTxExtLineWeight, + ExtensionOtherVersions: sp_runtime::traits::PipelineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -427,7 +427,7 @@ impl GetDispatchInfo where Call: GetDispatchInfo + Dispatchable, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: sp_runtime::traits::VersTxExtLineWeight, + ExtensionOtherVersions: sp_runtime::traits::PipelineWeight, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); diff --git a/substrate/frame/support/test/tests/tx_ext_multi_version.rs b/substrate/frame/support/test/tests/tx_ext_multi_version.rs index 0165d3209cf8c..ed65fca3b59e1 100644 --- a/substrate/frame/support/test/tests/tx_ext_multi_version.rs +++ b/substrate/frame/support/test/tests/tx_ext_multi_version.rs @@ -112,8 +112,8 @@ pub type SimpleExtV0 = SimpleExt<0>; pub type SimpleExtV4 = SimpleExt<4>; pub type SimpleExtV7 = SimpleExt<7>; -pub type Ext4 = sp_runtime::traits::TxExtLineAtVers<4, SimpleExtV4>; -pub type Ext7 = sp_runtime::traits::TxExtLineAtVers<7, SimpleExtV7>; +pub type Ext4 = sp_runtime::traits::PipelineAtVers<4, SimpleExtV4>; +pub type Ext7 = sp_runtime::traits::PipelineAtVers<7, SimpleExtV7>; pub type OtherVersions = sp_runtime::traits::MultiVersion; diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index d0b1956ddada2..34b3ddeba57bb 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -23,7 +23,7 @@ use crate::{ traits::{ self, AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, ExtensionVariant, InvalidVersion, MaybeDisplay, Member, PostDispatchInfoOf, - TransactionExtension, ValidateUnsigned, VersTxExtLine, VersTxExtLineWeight, + TransactionExtension, ValidateUnsigned, Pipeline, PipelineWeight, }, transaction_validity::{TransactionSource, TransactionValidity}, }; @@ -85,7 +85,7 @@ where AccountId: Member + MaybeDisplay, Call: Member + Dispatchable + Encode, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersTxExtLine, + ExtensionOtherVersions: Pipeline, RuntimeOrigin: From> + AsTransactionAuthorizedOrigin, { type Call = Call; @@ -150,7 +150,7 @@ impl where Call: Dispatchable, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersTxExtLineWeight, + ExtensionOtherVersions: PipelineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index facd125f08895..074d0139a9721 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -23,7 +23,7 @@ use crate::{ self, Checkable, DecodeWithVersion, DecodeWithVersionWithMemTracking, Dispatchable, ExtensionVariant, ExtrinsicCall, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, InvalidVersion, LazyExtrinsic, MaybeDisplay, Member, SignaturePayload, - TransactionExtension, VersTxExtLineVersion, VersTxExtLineWeight, + TransactionExtension, PipelineVersion, PipelineWeight, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, @@ -165,7 +165,7 @@ where Address: Encode, Signature: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode + VersTxExtLineVersion, + ExtensionOtherVersions: Encode + PipelineVersion, { fn size_hint(&self) -> usize { match &self { @@ -275,7 +275,7 @@ where /// ``` /// use sp_runtime::{ /// generic::UncheckedExtrinsic, -/// traits::{MultiVersion, TxExtLineAtVers}, +/// traits::{MultiVersion, PipelineAtVers}, /// }; /// /// struct Signature; // Some signature scheme. @@ -291,8 +291,8 @@ where /// /// // Definition of the extrinsic. /// type ExtensionV0 = (SigV2Ext, NonceExt, PaymentExt); -/// type ExtensionV1 = TxExtLineAtVers<1, (SigV2Ext, NonceExt, PaymentV2Ext)>; -/// type ExtensionV2 = TxExtLineAtVers<2, (SigV2Ext, NonceV2Ext, PaymentV2Ext)>; +/// type ExtensionV1 = PipelineAtVers<1, (SigV2Ext, NonceExt, PaymentV2Ext)>; +/// type ExtensionV2 = PipelineAtVers<2, (SigV2Ext, NonceV2Ext, PaymentV2Ext)>; /// /// type OtherVersions = MultiVersion; /// @@ -703,7 +703,7 @@ impl< > { const VERSIONS: &'static [u8] = &[LEGACY_EXTRINSIC_FORMAT_VERSION, EXTRINSIC_FORMAT_VERSION]; - type TransactionExtensionsVersions = ExtensionVariant; + type TransactionExtensionPipelines = ExtensionVariant; } impl @@ -711,7 +711,7 @@ impl, - ExtensionOtherVersions: VersTxExtLineWeight, + ExtensionOtherVersions: PipelineWeight, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. @@ -814,7 +814,7 @@ where Signature: Encode, Call: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode + VersTxExtLineVersion, + ExtensionOtherVersions: Encode + PipelineVersion, { fn serialize(&self, seq: S) -> Result where @@ -967,7 +967,7 @@ where Preamble: Encode, Call: Encode, ExtensionV0: Encode, - ExtensionOtherVersions: Encode + VersTxExtLineVersion, + ExtensionOtherVersions: Encode + PipelineVersion, { fn from( extrinsic: UncheckedExtrinsic< @@ -997,7 +997,7 @@ where Preamble: Decode, Call: DecodeWithMemTracking, ExtensionV0: Decode, - ExtensionOtherVersions: DecodeWithVersion + VersTxExtLineVersion, + ExtensionOtherVersions: DecodeWithVersion + PipelineVersion, { fn decode_unprefixed(data: &[u8]) -> Result { Self::decode_with_len(&mut &data[..], data.len()) diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index 8319e17b9df48..6d8b4dbc9457d 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -63,8 +63,8 @@ pub use transaction_extension::{ }; pub use vers_tx_ext::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, ExtensionVariant, InvalidVersion, - MultiVersion, TxExtLineAtVers, VersTxExtLine, VersTxExtLineMetadataBuilder, - VersTxExtLineVersion, VersTxExtLineWeight, + MultiVersion, PipelineAtVers, Pipeline, PipelineMetadataBuilder, PipelineVersion, + PipelineWeight, }; /// A lazy value. @@ -1506,7 +1506,7 @@ pub trait ExtrinsicMetadata { /// /// For the transaction extension pipeline used for the signed extrinsics it is defined as the /// version 0, if defined. - type TransactionExtensionsVersions; + type TransactionExtensionPipelines; } /// Extract the hashing type for a block. diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs index 15d311d5104b0..b437d33d38bea 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -21,8 +21,8 @@ use crate::{ traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchOriginOf, DispatchTransaction, Dispatchable, PostDispatchInfoOf, - TransactionExtension, VersTxExtLine, VersTxExtLineMetadataBuilder, VersTxExtLineVersion, - VersTxExtLineWeight, + TransactionExtension, Pipeline, PipelineMetadataBuilder, PipelineVersion, + PipelineWeight, }, transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; @@ -33,12 +33,12 @@ use sp_weights::Weight; /// A transaction extension pipeline defined for a single version. #[derive(Encode, Clone, Debug, TypeInfo, PartialEq, Eq)] -pub struct TxExtLineAtVers { +pub struct PipelineAtVers { /// The transaction extension pipeline for the version `VERSION`. pub extension: Extension, } -impl TxExtLineAtVers { +impl PipelineAtVers { /// Create a new versioned extension. pub fn new(extension: Extension) -> Self { Self { extension } @@ -46,14 +46,14 @@ impl TxExtLineAtVers { } impl DecodeWithVersion - for TxExtLineAtVers + for PipelineAtVers { fn decode_with_version( extension_version: u8, input: &mut I, ) -> Result { if extension_version == VERSION { - Ok(TxExtLineAtVers { extension: Extension::decode(input)? }) + Ok(PipelineAtVers { extension: Extension::decode(input)? }) } else { Err(codec::Error::from("Invalid extension version")) } @@ -61,22 +61,22 @@ impl DecodeWithVersion } impl DecodeWithVersionWithMemTracking - for TxExtLineAtVers + for PipelineAtVers { } -impl VersTxExtLineVersion for TxExtLineAtVers { +impl PipelineVersion for PipelineAtVers { fn version(&self) -> u8 { VERSION } } -impl VersTxExtLine for TxExtLineAtVers +impl Pipeline for PipelineAtVers where Call: Dispatchable + Encode, Extension: TransactionExtension, { - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { + fn build_metadata(builder: &mut PipelineMetadataBuilder) { builder.push_versioned_extension(VERSION, Extension::metadata()); } fn validate_only( @@ -103,7 +103,7 @@ where } impl> - VersTxExtLineWeight for TxExtLineAtVers + PipelineWeight for PipelineAtVers { fn weight(&self, call: &Call) -> Weight { self.extension.weight(call) @@ -210,10 +210,10 @@ mod tests { } // This type represents the versioned extension pipeline for version=3. - pub type ExtV3 = TxExtLineAtVers<3, SimpleExtension>; + pub type ExtV3 = PipelineAtVers<3, SimpleExtension>; // This type represents the versioned extension pipeline for version=10. - pub type ExtV10 = TxExtLineAtVers<10, SimpleExtension>; + pub type ExtV10 = PipelineAtVers<10, SimpleExtension>; // --- Tests --- diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index 16b7f0b2b070b..59569698b8a5b 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -20,8 +20,8 @@ use crate::{ traits::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchOriginOf, - Dispatchable, PostDispatchInfoOf, VersTxExtLine, VersTxExtLineMetadataBuilder, - VersTxExtLineVersion, VersTxExtLineWeight, + Dispatchable, PostDispatchInfoOf, Pipeline, PipelineMetadataBuilder, + PipelineVersion, PipelineWeight, }, transaction_validity::{ InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction, @@ -32,7 +32,7 @@ use core::fmt::Debug; use scale_info::TypeInfo; use sp_weights::Weight; -/// An implementation of [`VersTxExtLine`] that consider any version invalid. +/// An implementation of [`Pipeline`] that consider any version invalid. /// /// This is mostly used by [`crate::traits::MultiVersion`]. // This type cannot be instantiated. @@ -50,8 +50,8 @@ impl DecodeWithVersion for InvalidVersion { impl DecodeWithVersionWithMemTracking for InvalidVersion {} -impl VersTxExtLine for InvalidVersion { - fn build_metadata(_builder: &mut VersTxExtLineMetadataBuilder) { +impl Pipeline for InvalidVersion { + fn build_metadata(_builder: &mut PipelineMetadataBuilder) { // Do nothing. } fn validate_only( @@ -77,14 +77,14 @@ impl VersTxExtLine for InvalidVersion { } } -impl VersTxExtLineVersion for InvalidVersion { +impl PipelineVersion for InvalidVersion { fn version(&self) -> u8 { // The type cannot be instantiated so this method is never called. unreachable!() } } -impl VersTxExtLineWeight for InvalidVersion { +impl PipelineWeight for InvalidVersion { fn weight(&self, _call: &Call) -> Weight { // The type cannot be instantiated so this method is never called. unreachable!() diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 8d28cc360b376..c6d7d27b7686e 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -34,19 +34,18 @@ mod at_vers; mod invalid; mod multi; mod variant; -pub use at_vers::TxExtLineAtVers; +pub use at_vers::PipelineAtVers; pub use invalid::InvalidVersion; pub use multi::MultiVersion; pub use variant::ExtensionVariant; /// The weight for an instance of a versioned transaction extension pipeline and a call. /// -/// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to -/// rely only on it without bounding the whole trait [`VersTxExtLine`]. +/// This trait is part of [`Pipeline`]. It is defined independently to allow implementation to +/// rely only on it without bounding the whole trait [`Pipeline`]. /// -/// (type name is short for versioned (Vers) transaction (Tx) Extension (Ext) pipeline (Line) weight -/// (Weight)). -pub trait VersTxExtLineWeight { +/// (type name is short for versioned (Vers) Pipeline weight (Weight)). +pub trait PipelineWeight { /// Return the pre dispatch weight for the given versioned transaction extension pipeline and /// call. fn weight(&self, call: &Call) -> Weight; @@ -54,12 +53,11 @@ pub trait VersTxExtLineWeight { /// The version for an instance of a versioned transaction extension pipeline. /// -/// This trait is part of [`VersTxExtLine`]. It is defined independently to allow implementation to -/// rely only on it without bounding the whole trait [`VersTxExtLine`]. +/// This trait is part of [`Pipeline`]. It is defined independently to allow implementation to +/// rely only on it without bounding the whole trait [`Pipeline`]. /// -/// (type name is short for versioned (Vers) transaction (Tx) Extension (Ext) pipeline (Line) -/// version (Version)). -pub trait VersTxExtLineVersion { +/// (type name is short for versioned (Vers) Pipeline version (Version)). +pub trait PipelineVersion { /// Return the version for the given versioned transaction extension pipeline. fn version(&self) -> u8; } @@ -68,8 +66,8 @@ pub trait VersTxExtLineVersion { /// /// This defines multiple version of a transaction extensions pipeline. /// -/// (type name is short for versioned (Vers) transaction (Tx) Extension (Ext) pipeline (Line)). -pub trait VersTxExtLine: +/// (type name is short for versioned (Vers) Pipeline). +pub trait Pipeline: Encode + DecodeWithVersion + DecodeWithVersionWithMemTracking @@ -78,11 +76,11 @@ pub trait VersTxExtLine: + Send + Sync + Clone - + VersTxExtLineWeight - + VersTxExtLineVersion + + PipelineWeight + + PipelineVersion { /// Build the metadata for the versioned transaction extension pipeline. - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder); + fn build_metadata(builder: &mut PipelineMetadataBuilder); /// Validate a transaction. fn validate_only( @@ -118,7 +116,7 @@ pub trait DecodeWithVersion: Sized { pub trait DecodeWithVersionWithMemTracking: DecodeWithVersion {} /// A type to build the metadata for the versioned transaction extension pipeline. -pub struct VersTxExtLineMetadataBuilder { +pub struct PipelineMetadataBuilder { /// The transaction extension pipeline by version and its list of items as vec of index into /// the other field `in_versions`. pub by_version: BTreeMap>, @@ -126,7 +124,7 @@ pub struct VersTxExtLineMetadataBuilder { pub in_versions: Vec, } -impl VersTxExtLineMetadataBuilder { +impl PipelineMetadataBuilder { /// Create a new empty metadata builder. pub fn new() -> Self { Self { by_version: BTreeMap::new(), in_versions: Vec::new() } @@ -172,7 +170,7 @@ mod tests { #[test] fn test_metadata_builder() { - let mut builder = VersTxExtLineMetadataBuilder::new(); + let mut builder = PipelineMetadataBuilder::new(); let ext_item_a = TransactionExtensionMetadata { identifier: "ExtensionA", diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs index 213ab297f8fc3..b48392994ce0c 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -20,8 +20,8 @@ use crate::{ traits::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchOriginOf, - Dispatchable, InvalidVersion, PostDispatchInfoOf, TxExtLineAtVers, VersTxExtLine, - VersTxExtLineMetadataBuilder, VersTxExtLineVersion, VersTxExtLineWeight, + Dispatchable, InvalidVersion, PipelineAtVers, PostDispatchInfoOf, Pipeline, + PipelineMetadataBuilder, PipelineVersion, PipelineWeight, }, transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; @@ -44,14 +44,14 @@ impl MultiVersionItem for InvalidVersion { const VERSION: Option = None; } -impl MultiVersionItem for TxExtLineAtVers { +impl MultiVersionItem for PipelineAtVers { const VERSION: Option = Some(VERSION); } macro_rules! declare_multi_version_enum { ($( $variant:tt, )*) => { - /// An implementation of [`VersTxExtLine`] that aggregates multiple versioned transaction + /// An implementation of [`Pipeline`] that aggregates multiple versioned transaction /// extension pipeline. /// /// It is an enum where each variant has its own version, duplicated version must be @@ -63,14 +63,14 @@ macro_rules! declare_multi_version_enum { /// # Example /// /// ``` - /// use sp_runtime::traits::{MultiVersion, TxExtLineAtVers}; + /// use sp_runtime::traits::{MultiVersion, PipelineAtVers}; /// /// struct PaymentExt; /// struct PaymentExtV2; /// struct NonceExt; /// - /// type ExtV1 = TxExtLineAtVers<1, (NonceExt, PaymentExt)>; - /// type ExtV4 = TxExtLineAtVers<4, (NonceExt, PaymentExtV2)>; + /// type ExtV1 = PipelineAtVers<1, (NonceExt, PaymentExt)>; + /// type ExtV4 = PipelineAtVers<4, (NonceExt, PaymentExtV2)>; /// /// /// The transaction extension pipeline that supports both version 1 and 4. /// type TransactionExtension = MultiVersion; @@ -88,7 +88,7 @@ macro_rules! declare_multi_version_enum { )* } - impl<$( $variant: VersTxExtLineVersion, )*> VersTxExtLineVersion for MultiVersion<$( $variant, )*> { + impl<$( $variant: PipelineVersion, )*> PipelineVersion for MultiVersion<$( $variant, )*> { fn version(&self) -> u8 { match self { $( @@ -166,8 +166,8 @@ macro_rules! declare_multi_version_enum { DecodeWithVersionWithMemTracking for MultiVersion<$( $variant, )*> {} - impl<$( $variant: VersTxExtLineWeight + MultiVersionItem, )* Call: Dispatchable> - VersTxExtLineWeight for MultiVersion<$( $variant, )*> + impl<$( $variant: PipelineWeight + MultiVersionItem, )* Call: Dispatchable> + PipelineWeight for MultiVersion<$( $variant, )*> { fn weight(&self, call: &Call) -> Weight { match self { @@ -178,10 +178,10 @@ macro_rules! declare_multi_version_enum { } } - impl<$( $variant: VersTxExtLine + MultiVersionItem, )* Call: Dispatchable> - VersTxExtLine for MultiVersion<$( $variant, )*> + impl<$( $variant: Pipeline + MultiVersionItem, )* Call: Dispatchable> + Pipeline for MultiVersion<$( $variant, )*> { - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { + fn build_metadata(builder: &mut PipelineMetadataBuilder) { $( $variant::build_metadata(builder); )* @@ -227,8 +227,8 @@ mod tests { use crate::{ traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DispatchInfoOf, Dispatchable, - Implication, TransactionExtension, TransactionSource, ValidateResult, VersTxExtLine, - VersTxExtLineVersion, VersTxExtLineWeight, + Implication, TransactionExtension, TransactionSource, ValidateResult, Pipeline, + PipelineVersion, PipelineWeight, }, transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, DispatchError, @@ -330,7 +330,7 @@ mod tests { } } - pub type PipelineV4 = TxExtLineAtVers<4, SimpleExtensionV4>; + pub type PipelineV4 = PipelineAtVers<4, SimpleExtensionV4>; // Another single-version extension pipeline, version=7 #[derive(Clone, Debug, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)] @@ -382,7 +382,7 @@ mod tests { } } - pub type PipelineV7 = TxExtLineAtVers<7, SimpleExtensionV7>; + pub type PipelineV7 = PipelineAtVers<7, SimpleExtensionV7>; // -------------------------------------------------------- // Our MultiVersion definition under test diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index 648b5edf58ec1..45250e0b7aaea 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -22,9 +22,9 @@ use crate::{ generic::ExtensionVersion, traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DecodeWithVersionWithMemTracking, - DispatchInfoOf, DispatchTransaction, Dispatchable, PostDispatchInfoOf, - TransactionExtension, TxExtLineAtVers, VersTxExtLine, VersTxExtLineMetadataBuilder, - VersTxExtLineVersion, VersTxExtLineWeight, + DispatchInfoOf, DispatchTransaction, Dispatchable, PipelineAtVers, PostDispatchInfoOf, + TransactionExtension, Pipeline, PipelineMetadataBuilder, PipelineVersion, + PipelineWeight, }, transaction_validity::TransactionSource, }; @@ -49,7 +49,7 @@ pub enum ExtensionVariant { Other(ExtensionOtherVersions), } -impl VersTxExtLineVersion +impl PipelineVersion for ExtensionVariant { fn version(&self) -> u8 { @@ -120,13 +120,13 @@ impl, - ExtensionOtherVersions: VersTxExtLine, - > VersTxExtLine for ExtensionVariant + ExtensionOtherVersions: Pipeline, + > Pipeline for ExtensionVariant where ::RuntimeOrigin: AsTransactionAuthorizedOrigin, { - fn build_metadata(builder: &mut VersTxExtLineMetadataBuilder) { - TxExtLineAtVers::::build_metadata(builder); + fn build_metadata(builder: &mut PipelineMetadataBuilder) { + PipelineAtVers::::build_metadata(builder); ExtensionOtherVersions::build_metadata(builder); } fn validate_only( @@ -165,8 +165,8 @@ where impl< Call: Dispatchable, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: VersTxExtLineWeight, - > VersTxExtLineWeight for ExtensionVariant + ExtensionOtherVersions: PipelineWeight, + > PipelineWeight for ExtensionVariant { fn weight(&self, call: &Call) -> Weight { match self { @@ -182,7 +182,7 @@ mod tests { use crate::{ traits::{ AsTransactionAuthorizedOrigin, DispatchInfoOf, Dispatchable, Implication, - TransactionExtension, TransactionSource, TxExtLineAtVers, ValidateResult, + TransactionExtension, TransactionSource, PipelineAtVers, ValidateResult, }, transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, DispatchError, @@ -331,7 +331,7 @@ mod tests { } } - type ExtV2 = TxExtLineAtVers<2, OtherExtension>; + type ExtV2 = PipelineAtVers<2, OtherExtension>; // -------------------------------------------------------------------- // Actual unit tests From fcafaac7a6ce0de6dd88cae5c7ad483841d1aa71 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Sun, 25 Jan 2026 19:35:42 +0900 Subject: [PATCH 48/56] fix unused --- substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index 59569698b8a5b..8ff50d3dd5ad5 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -24,7 +24,7 @@ use crate::{ PipelineVersion, PipelineWeight, }, transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction, + TransactionSource, TransactionValidityError, ValidTransaction, }, }; use codec::Encode; From 1879c54fe0be320cbe90b127e831e909b46daeb1 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Tue, 27 Jan 2026 11:18:54 +0900 Subject: [PATCH 49/56] fmt --- substrate/frame/revive/src/evm/runtime.rs | 4 ++-- .../primitives/runtime/src/generic/checked_extrinsic.rs | 4 ++-- .../primitives/runtime/src/generic/unchecked_extrinsic.rs | 4 ++-- substrate/primitives/runtime/src/traits/mod.rs | 2 +- .../primitives/runtime/src/traits/vers_tx_ext/at_vers.rs | 6 +++--- .../primitives/runtime/src/traits/vers_tx_ext/invalid.rs | 8 +++----- .../primitives/runtime/src/traits/vers_tx_ext/multi.rs | 8 ++++---- .../primitives/runtime/src/traits/vers_tx_ext/variant.rs | 8 ++++---- 8 files changed, 21 insertions(+), 23 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index b25ddb642fd00..57b818547469a 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -38,8 +38,8 @@ use sp_core::U256; use sp_runtime::{ generic::{self, CheckedExtrinsic, ExtrinsicFormat}, traits::{ - Checkable, ExtrinsicCall, ExtrinsicLike, ExtrinsicMetadata, LazyExtrinsic, - TransactionExtension, Pipeline, + Checkable, ExtrinsicCall, ExtrinsicLike, ExtrinsicMetadata, LazyExtrinsic, Pipeline, + TransactionExtension, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, Debug, OpaqueExtrinsic, Weight, diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 34b3ddeba57bb..3d289a33d27a8 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -22,8 +22,8 @@ use super::unchecked_extrinsic::ExtensionVersion; use crate::{ traits::{ self, AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, - ExtensionVariant, InvalidVersion, MaybeDisplay, Member, PostDispatchInfoOf, - TransactionExtension, ValidateUnsigned, Pipeline, PipelineWeight, + ExtensionVariant, InvalidVersion, MaybeDisplay, Member, Pipeline, PipelineWeight, + PostDispatchInfoOf, TransactionExtension, ValidateUnsigned, }, transaction_validity::{TransactionSource, TransactionValidity}, }; diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 074d0139a9721..69df8664d9c0b 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -22,8 +22,8 @@ use crate::{ traits::{ self, Checkable, DecodeWithVersion, DecodeWithVersionWithMemTracking, Dispatchable, ExtensionVariant, ExtrinsicCall, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, - InvalidVersion, LazyExtrinsic, MaybeDisplay, Member, SignaturePayload, - TransactionExtension, PipelineVersion, PipelineWeight, + InvalidVersion, LazyExtrinsic, MaybeDisplay, Member, PipelineVersion, PipelineWeight, + SignaturePayload, TransactionExtension, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index 6d8b4dbc9457d..c469f7fe67046 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -63,7 +63,7 @@ pub use transaction_extension::{ }; pub use vers_tx_ext::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, ExtensionVariant, InvalidVersion, - MultiVersion, PipelineAtVers, Pipeline, PipelineMetadataBuilder, PipelineVersion, + MultiVersion, Pipeline, PipelineAtVers, PipelineMetadataBuilder, PipelineVersion, PipelineWeight, }; diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs index b437d33d38bea..4c107eae94747 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -20,9 +20,9 @@ use crate::{ traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DecodeWithVersionWithMemTracking, - DispatchInfoOf, DispatchOriginOf, DispatchTransaction, Dispatchable, PostDispatchInfoOf, - TransactionExtension, Pipeline, PipelineMetadataBuilder, PipelineVersion, - PipelineWeight, + DispatchInfoOf, DispatchOriginOf, DispatchTransaction, Dispatchable, Pipeline, + PipelineMetadataBuilder, PipelineVersion, PipelineWeight, PostDispatchInfoOf, + TransactionExtension, }, transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index 8ff50d3dd5ad5..e1e83d34147d0 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -20,12 +20,10 @@ use crate::{ traits::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchOriginOf, - Dispatchable, PostDispatchInfoOf, Pipeline, PipelineMetadataBuilder, - PipelineVersion, PipelineWeight, - }, - transaction_validity::{ - TransactionSource, TransactionValidityError, ValidTransaction, + Dispatchable, Pipeline, PipelineMetadataBuilder, PipelineVersion, PipelineWeight, + PostDispatchInfoOf, }, + transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; use codec::Encode; use core::fmt::Debug; diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs index b48392994ce0c..daf64573c438b 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -20,8 +20,8 @@ use crate::{ traits::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchOriginOf, - Dispatchable, InvalidVersion, PipelineAtVers, PostDispatchInfoOf, Pipeline, - PipelineMetadataBuilder, PipelineVersion, PipelineWeight, + Dispatchable, InvalidVersion, Pipeline, PipelineAtVers, PipelineMetadataBuilder, + PipelineVersion, PipelineWeight, PostDispatchInfoOf, }, transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; @@ -227,8 +227,8 @@ mod tests { use crate::{ traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DispatchInfoOf, Dispatchable, - Implication, TransactionExtension, TransactionSource, ValidateResult, Pipeline, - PipelineVersion, PipelineWeight, + Implication, Pipeline, PipelineVersion, PipelineWeight, TransactionExtension, + TransactionSource, ValidateResult, }, transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, DispatchError, diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index 45250e0b7aaea..3b7a49e3e012e 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -22,9 +22,9 @@ use crate::{ generic::ExtensionVersion, traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DecodeWithVersionWithMemTracking, - DispatchInfoOf, DispatchTransaction, Dispatchable, PipelineAtVers, PostDispatchInfoOf, - TransactionExtension, Pipeline, PipelineMetadataBuilder, PipelineVersion, - PipelineWeight, + DispatchInfoOf, DispatchTransaction, Dispatchable, Pipeline, PipelineAtVers, + PipelineMetadataBuilder, PipelineVersion, PipelineWeight, PostDispatchInfoOf, + TransactionExtension, }, transaction_validity::TransactionSource, }; @@ -182,7 +182,7 @@ mod tests { use crate::{ traits::{ AsTransactionAuthorizedOrigin, DispatchInfoOf, Dispatchable, Implication, - TransactionExtension, TransactionSource, PipelineAtVers, ValidateResult, + PipelineAtVers, TransactionExtension, TransactionSource, ValidateResult, }, transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, DispatchError, From 545199186c9aeb3363ed3a9e2711e088b34a500f Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Mon, 16 Mar 2026 07:58:56 +0900 Subject: [PATCH 50/56] Update substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index c6d7d27b7686e..679d0d1930cdb 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -140,8 +140,7 @@ impl PipelineMetadataBuilder { log::warn!("Duplicate definition for transaction extension version: {}", ext_version); debug_assert!( false, - "Duplicate definition for transaction extension version: {}", - ext_version + "Duplicate definition for transaction extension version: {ext_version}", ); return } From cfc4375cd4c43bcb59a9ac3d96d49534bd713faf Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Mon, 16 Mar 2026 07:59:08 +0900 Subject: [PATCH 51/56] Update substrate/frame/revive/src/evm/runtime.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- substrate/frame/revive/src/evm/runtime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 57b818547469a..12d21657e2fdf 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -57,7 +57,7 @@ pub trait SetWeightLimit { /// [`crate::Call::eth_transact`] extrinsic. #[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug)] pub struct UncheckedExtrinsic( - pub generic::UncheckedExtrinsic< + pub generic::UncheckedExtrinsic< Address, CallOf, Signature, From 22f7bcc24d5d4e9a4e8879f59ab082333d9679ec Mon Sep 17 00:00:00 2001 From: gui1117 Date: Mon, 16 Mar 2026 08:05:09 +0900 Subject: [PATCH 52/56] improve comments --- .../primitives/runtime/src/traits/vers_tx_ext/invalid.rs | 3 ++- .../primitives/runtime/src/traits/vers_tx_ext/variant.rs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index e1e83d34147d0..0cfaa3b887980 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -33,7 +33,8 @@ use sp_weights::Weight; /// An implementation of [`Pipeline`] that consider any version invalid. /// /// This is mostly used by [`crate::traits::MultiVersion`]. -// This type cannot be instantiated. +/// +/// This type cannot be instantiated. #[derive(Encode, Debug, Clone, Eq, PartialEq, TypeInfo)] pub enum InvalidVersion {} diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index 3b7a49e3e012e..81fbf02274652 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -39,8 +39,9 @@ const EXTENSION_V0_VERSION: ExtensionVersion = 0; /// A versioned transaction extension pipeline defined with 2 variants: one for the version 0 and /// one for other versions. /// -/// The generic `ExtensionOtherVersions` must not re-define a transaction extension pipeline for the -/// version 0, it will be ignored and overwritten by `ExtensionV0`. +/// The generic `ExtensionOtherVersions` should not re-define a transaction extension pipeline for +/// the version 0, it will be ignored. The transaction extension pipeline for the version 0 is +/// defined by the generic `ExtensionV0`. #[derive(PartialEq, Eq, Clone, Debug, TypeInfo)] pub enum ExtensionVariant { /// A transaction extension pipeline for the version 0. From 2abb369c2cfe6603a7d3224bd8dc606388b7ddf4 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Mon, 16 Mar 2026 08:24:28 +0900 Subject: [PATCH 53/56] merge PipelineWeight directly into Pipeline --- substrate/frame/support/src/dispatch.rs | 10 +++++--- .../runtime/src/generic/checked_extrinsic.rs | 9 ++++--- .../src/generic/unchecked_extrinsic.rs | 13 +++++----- .../primitives/runtime/src/traits/mod.rs | 1 - .../runtime/src/traits/vers_tx_ext/at_vers.rs | 8 +----- .../runtime/src/traits/vers_tx_ext/invalid.rs | 12 +++------ .../runtime/src/traits/vers_tx_ext/mod.rs | 17 +++---------- .../runtime/src/traits/vers_tx_ext/multi.rs | 25 ++++++++----------- .../runtime/src/traits/vers_tx_ext/variant.rs | 11 +------- 9 files changed, 38 insertions(+), 68 deletions(-) diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index d11e00e1d191c..67c08a2545f75 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -410,9 +410,10 @@ where impl GetDispatchInfo for UncheckedExtrinsic where - Call: GetDispatchInfo + Dispatchable, + Call: GetDispatchInfo + Dispatchable + Encode, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: sp_runtime::traits::PipelineWeight, + ExtensionOtherVersions: sp_runtime::traits::Pipeline, + ::RuntimeOrigin: sp_runtime::traits::AsTransactionAuthorizedOrigin, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); @@ -425,9 +426,10 @@ where impl GetDispatchInfo for CheckedExtrinsic where - Call: GetDispatchInfo + Dispatchable, + Call: GetDispatchInfo + Dispatchable + Encode, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: sp_runtime::traits::PipelineWeight, + ExtensionOtherVersions: sp_runtime::traits::Pipeline, + ::RuntimeOrigin: sp_runtime::traits::AsTransactionAuthorizedOrigin, { fn get_dispatch_info(&self) -> DispatchInfo { let mut info = self.function.get_dispatch_info(); diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 3d289a33d27a8..c973976942b14 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -22,8 +22,8 @@ use super::unchecked_extrinsic::ExtensionVersion; use crate::{ traits::{ self, AsTransactionAuthorizedOrigin, DispatchInfoOf, DispatchTransaction, Dispatchable, - ExtensionVariant, InvalidVersion, MaybeDisplay, Member, Pipeline, PipelineWeight, - PostDispatchInfoOf, TransactionExtension, ValidateUnsigned, + ExtensionVariant, InvalidVersion, MaybeDisplay, Member, Pipeline, PostDispatchInfoOf, + TransactionExtension, ValidateUnsigned, }, transaction_validity::{TransactionSource, TransactionValidity}, }; @@ -148,9 +148,10 @@ where impl CheckedExtrinsic where - Call: Dispatchable, + Call: Dispatchable + Encode, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: PipelineWeight, + ExtensionOtherVersions: Pipeline, + ::RuntimeOrigin: AsTransactionAuthorizedOrigin, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 69df8664d9c0b..3c37e0b33b957 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -20,10 +20,10 @@ use crate::{ generic::{CheckedExtrinsic, ExtrinsicFormat}, traits::{ - self, Checkable, DecodeWithVersion, DecodeWithVersionWithMemTracking, Dispatchable, - ExtensionVariant, ExtrinsicCall, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, - InvalidVersion, LazyExtrinsic, MaybeDisplay, Member, PipelineVersion, PipelineWeight, - SignaturePayload, TransactionExtension, + self, AsTransactionAuthorizedOrigin, Checkable, DecodeWithVersion, + DecodeWithVersionWithMemTracking, Dispatchable, ExtensionVariant, ExtrinsicCall, + ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, InvalidVersion, LazyExtrinsic, + MaybeDisplay, Member, Pipeline, PipelineVersion, SignaturePayload, TransactionExtension, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, @@ -709,9 +709,10 @@ impl< impl UncheckedExtrinsic where - Call: Dispatchable, + Call: Dispatchable + Encode, ExtensionV0: TransactionExtension, - ExtensionOtherVersions: PipelineWeight, + ExtensionOtherVersions: Pipeline, + ::RuntimeOrigin: AsTransactionAuthorizedOrigin, { /// Returns the weight of the extension of this transaction, if present. If the transaction /// doesn't use any extension, the weight returned is equal to zero. diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index c469f7fe67046..9f26c5ec9da57 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -64,7 +64,6 @@ pub use transaction_extension::{ pub use vers_tx_ext::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, ExtensionVariant, InvalidVersion, MultiVersion, Pipeline, PipelineAtVers, PipelineMetadataBuilder, PipelineVersion, - PipelineWeight, }; /// A lazy value. diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs index 4c107eae94747..f4078fb5a1f92 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -21,8 +21,7 @@ use crate::{ traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchOriginOf, DispatchTransaction, Dispatchable, Pipeline, - PipelineMetadataBuilder, PipelineVersion, PipelineWeight, PostDispatchInfoOf, - TransactionExtension, + PipelineMetadataBuilder, PipelineVersion, PostDispatchInfoOf, TransactionExtension, }, transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; @@ -100,11 +99,6 @@ where ) -> crate::ApplyExtrinsicResultWithInfo> { self.extension.dispatch_transaction(origin, call, info, len, VERSION) } -} - -impl> - PipelineWeight for PipelineAtVers -{ fn weight(&self, call: &Call) -> Weight { self.extension.weight(call) } diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs index 0cfaa3b887980..f05cc2cfce06e 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs @@ -20,8 +20,7 @@ use crate::{ traits::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchOriginOf, - Dispatchable, Pipeline, PipelineMetadataBuilder, PipelineVersion, PipelineWeight, - PostDispatchInfoOf, + Dispatchable, Pipeline, PipelineMetadataBuilder, PipelineVersion, PostDispatchInfoOf, }, transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; @@ -74,17 +73,14 @@ impl Pipeline for InvalidVersion { // The type cannot be instantiated so this method is never called. unreachable!() } -} - -impl PipelineVersion for InvalidVersion { - fn version(&self) -> u8 { + fn weight(&self, _call: &Call) -> Weight { // The type cannot be instantiated so this method is never called. unreachable!() } } -impl PipelineWeight for InvalidVersion { - fn weight(&self, _call: &Call) -> Weight { +impl PipelineVersion for InvalidVersion { + fn version(&self) -> u8 { // The type cannot be instantiated so this method is never called. unreachable!() } diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 679d0d1930cdb..5c5ed60967fd8 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -39,18 +39,6 @@ pub use invalid::InvalidVersion; pub use multi::MultiVersion; pub use variant::ExtensionVariant; -/// The weight for an instance of a versioned transaction extension pipeline and a call. -/// -/// This trait is part of [`Pipeline`]. It is defined independently to allow implementation to -/// rely only on it without bounding the whole trait [`Pipeline`]. -/// -/// (type name is short for versioned (Vers) Pipeline weight (Weight)). -pub trait PipelineWeight { - /// Return the pre dispatch weight for the given versioned transaction extension pipeline and - /// call. - fn weight(&self, call: &Call) -> Weight; -} - /// The version for an instance of a versioned transaction extension pipeline. /// /// This trait is part of [`Pipeline`]. It is defined independently to allow implementation to @@ -76,7 +64,6 @@ pub trait Pipeline: + Send + Sync + Clone - + PipelineWeight + PipelineVersion { /// Build the metadata for the versioned transaction extension pipeline. @@ -100,6 +87,10 @@ pub trait Pipeline: info: &DispatchInfoOf, len: usize, ) -> crate::ApplyExtrinsicResultWithInfo>; + + /// Return the pre dispatch weight for the given versioned transaction extension pipeline and + /// call. + fn weight(&self, call: &Call) -> Weight; } /// A type that can be decoded from a specific version and a [`codec::Input`]. diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs index daf64573c438b..d90990740d981 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/multi.rs @@ -21,7 +21,7 @@ use crate::{ traits::{ DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchOriginOf, Dispatchable, InvalidVersion, Pipeline, PipelineAtVers, PipelineMetadataBuilder, - PipelineVersion, PipelineWeight, PostDispatchInfoOf, + PipelineVersion, PostDispatchInfoOf, }, transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}, }; @@ -166,18 +166,6 @@ macro_rules! declare_multi_version_enum { DecodeWithVersionWithMemTracking for MultiVersion<$( $variant, )*> {} - impl<$( $variant: PipelineWeight + MultiVersionItem, )* Call: Dispatchable> - PipelineWeight for MultiVersion<$( $variant, )*> - { - fn weight(&self, call: &Call) -> Weight { - match self { - $( - MultiVersion::$variant(v) => v.weight(call), - )* - } - } - } - impl<$( $variant: Pipeline + MultiVersionItem, )* Call: Dispatchable> Pipeline for MultiVersion<$( $variant, )*> { @@ -213,6 +201,13 @@ macro_rules! declare_multi_version_enum { )* } } + fn weight(&self, call: &Call) -> Weight { + match self { + $( + MultiVersion::$variant(v) => v.weight(call), + )* + } + } } }; } @@ -227,8 +222,8 @@ mod tests { use crate::{ traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DispatchInfoOf, Dispatchable, - Implication, Pipeline, PipelineVersion, PipelineWeight, TransactionExtension, - TransactionSource, ValidateResult, + Implication, Pipeline, PipelineVersion, TransactionExtension, TransactionSource, + ValidateResult, }, transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, DispatchError, diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index 81fbf02274652..ad3975d972a1d 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -23,8 +23,7 @@ use crate::{ traits::{ AsTransactionAuthorizedOrigin, DecodeWithVersion, DecodeWithVersionWithMemTracking, DispatchInfoOf, DispatchTransaction, Dispatchable, Pipeline, PipelineAtVers, - PipelineMetadataBuilder, PipelineVersion, PipelineWeight, PostDispatchInfoOf, - TransactionExtension, + PipelineMetadataBuilder, PipelineVersion, PostDispatchInfoOf, TransactionExtension, }, transaction_validity::TransactionSource, }; @@ -161,14 +160,6 @@ where ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), } } -} - -impl< - Call: Dispatchable, - ExtensionV0: TransactionExtension, - ExtensionOtherVersions: PipelineWeight, - > PipelineWeight for ExtensionVariant -{ fn weight(&self, call: &Call) -> Weight { match self { ExtensionVariant::V0(ext) => ext.weight(call), From 1a81f0a264a99b4ed6eea347feda10aa46b498d2 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Mon, 16 Mar 2026 09:52:08 +0900 Subject: [PATCH 54/56] extrinsic metadata better doc --- substrate/primitives/runtime/src/traits/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index a811e72728276..3dd4173bf19de 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -1503,8 +1503,10 @@ pub trait ExtrinsicMetadata { /// All version of transaction extensions attached to this `Extrinsic`. /// - /// For the transaction extension pipeline used for the signed extrinsics it is defined as the - /// version 0, if defined. + /// For extrinsic version 4, extrinsics don't specify any version, the pipeline version 0 is + /// used. + /// For extrinsic version 5, bare extrinsics don't specify any version, the pipeline version 0 + /// is used. type TransactionExtensionPipelines; } From c1009cf3ca3be03966ea0759d1d2f9b46d745cd7 Mon Sep 17 00:00:00 2001 From: gui1117 Date: Mon, 16 Mar 2026 16:53:21 +0900 Subject: [PATCH 55/56] fmt + taplo --- substrate/bin/node/testing/src/keyring.rs | 5 +++-- substrate/frame/revive/src/evm/runtime.rs | 16 ++++++++-------- .../support/test/tests/tx_ext_multi_version.rs | 2 +- substrate/primitives/metadata-ir/Cargo.toml | 2 +- .../runtime/src/generic/checked_extrinsic.rs | 10 ++++++---- .../runtime/src/traits/vers_tx_ext/at_vers.rs | 2 +- .../runtime/src/traits/vers_tx_ext/mod.rs | 2 +- .../runtime/src/traits/vers_tx_ext/variant.rs | 9 +++++---- 8 files changed, 26 insertions(+), 22 deletions(-) diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index 00905ac01be0e..e4e3313d703e8 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -131,8 +131,9 @@ pub fn sign( .into() }, ExtrinsicFormat::Bare => generic::UncheckedExtrinsic::new_bare(xt.function).into(), - ExtrinsicFormat::General(tx_ext) => + ExtrinsicFormat::General(tx_ext) => { generic::UncheckedExtrinsic::from_parts(xt.function, generic::Preamble::General(tx_ext)) - .into(), + .into() + }, } } diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 4c02d1e52dc3a..97fa53eab002f 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -57,7 +57,7 @@ pub trait SetWeightLimit { /// [`crate::Call::eth_transact`] extrinsic. #[derive(Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug)] pub struct UncheckedExtrinsic( - pub generic::UncheckedExtrinsic< + pub generic::UncheckedExtrinsic< Address, CallOf, Signature, @@ -170,14 +170,14 @@ where E::ExtensionV0, E::ExtensionOtherVersions, >: Checkable< - Lookup, - Checked = CheckedExtrinsic< - AccountIdOf, - CallOf, - E::ExtensionV0, - E::ExtensionOtherVersions, + Lookup, + Checked = CheckedExtrinsic< + AccountIdOf, + CallOf, + E::ExtensionV0, + E::ExtensionOtherVersions, + >, >, - >, { type Checked = CheckedExtrinsic< AccountIdOf, diff --git a/substrate/frame/support/test/tests/tx_ext_multi_version.rs b/substrate/frame/support/test/tests/tx_ext_multi_version.rs index ed65fca3b59e1..bde7935002b56 100644 --- a/substrate/frame/support/test/tests/tx_ext_multi_version.rs +++ b/substrate/frame/support/test/tests/tx_ext_multi_version.rs @@ -81,7 +81,7 @@ impl TransactionExtension for SimpleExt { _source: TransactionSource, ) -> sp_runtime::traits::ValidateResult { if self.token == 0 { - return Err(InvalidTransaction::Custom(N as u8).into()) + return Err(InvalidTransaction::Custom(N as u8).into()); } Ok((ValidTransaction::default(), (), frame_system::Origin::::Signed(100).into())) } diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index c7db98b51568d..852ded865d7c5 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } +derive-where = { workspace = true } frame-metadata = { features = ["current"], workspace = true } scale-info = { features = ["derive"], workspace = true } -derive-where = { workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index c973976942b14..62b738559ed5d 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -108,8 +108,9 @@ where .validate_only(origin, &self.function, info, len, source, EXTENSION_V0_VERSION) .map(|x| x.0) }, - ExtrinsicFormat::General(ref extension) => - extension.validate_only(None.into(), &self.function, info, len, source), + ExtrinsicFormat::General(ref extension) => { + extension.validate_only(None.into(), &self.function, info, len, source) + }, } } @@ -139,8 +140,9 @@ where len, EXTENSION_V0_VERSION, ), - ExtrinsicFormat::General(extension) => - extension.dispatch_transaction(None.into(), self.function, info, len), + ExtrinsicFormat::General(extension) => { + extension.dispatch_transaction(None.into(), self.function, info, len) + }, } } } diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs index f4078fb5a1f92..ed329f2c04482 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/at_vers.rs @@ -142,7 +142,7 @@ mod tests { origin: Self::RuntimeOrigin, ) -> crate::DispatchResultWithInfo { if origin.0 == 0 { - return Err(DispatchError::Other("origin is 0").into()) + return Err(DispatchError::Other("origin is 0").into()); } Ok(Default::default()) } diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs index 5c5ed60967fd8..705ecfebd35f0 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs @@ -133,7 +133,7 @@ impl PipelineMetadataBuilder { false, "Duplicate definition for transaction extension version: {ext_version}", ); - return + return; } let mut ext_item_indices = Vec::with_capacity(ext_items.len()); diff --git a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs index ad3975d972a1d..5e7eae325175b 100644 --- a/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs +++ b/substrate/primitives/runtime/src/traits/vers_tx_ext/variant.rs @@ -155,8 +155,9 @@ where len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { match self { - ExtensionVariant::V0(ext) => - ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION), + ExtensionVariant::V0(ext) => { + ext.dispatch_transaction(origin, call, info, len, EXTENSION_V0_VERSION) + }, ExtensionVariant::Other(ext) => ext.dispatch_transaction(origin, call, info, len), } } @@ -203,7 +204,7 @@ mod tests { _origin: Self::RuntimeOrigin, ) -> crate::DispatchResultWithInfo { if self.0 == 0 { - return Err(DispatchError::Other("call is 0").into()) + return Err(DispatchError::Other("call is 0").into()); } Ok(Default::default()) } @@ -306,7 +307,7 @@ mod tests { ) -> ValidateResult { // If 'token' is 0 => invalid. Else ok. if self.token == 0 { - return Err(InvalidTransaction::Custom(7).into()) + return Err(InvalidTransaction::Custom(7).into()); } Ok((ValidTransaction::default(), (), origin)) } From 17c1f8f8bde14a1c315a813a7645b215da8a146a Mon Sep 17 00:00:00 2001 From: gui1117 Date: Mon, 30 Mar 2026 14:19:52 +0900 Subject: [PATCH 56/56] fix test: have a correct metadata ir --- substrate/primitives/metadata-ir/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index f5e2f2bbe4524..433b383f04245 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -119,7 +119,7 @@ mod test { call_ty: meta_type::<()>(), signature_ty: meta_type::<()>(), extra_ty: meta_type::<()>(), - extensions_by_version: Default::default(), + extensions_by_version: [(0, vec![])].into(), extensions_in_versions: vec![], }, ty: meta_type::<()>(),