diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index f28d341847..7371d9ebfd 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1311,7 +1311,7 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "10.0.0" +version = "11.0.0" dependencies = [ "parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1324,7 +1324,7 @@ name = "frame-support" version = "2.0.0" dependencies = [ "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "frame-metadata 10.0.0", + "frame-metadata 11.0.0", "frame-support-procedural 2.0.0", "frame-system 2.0.0", "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 3f12957a05..aa550893f9 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -80,7 +80,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 209, + spec_version: 210, impl_version: 0, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 6324b3fabc..9ac43cbb50 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -1103,6 +1103,7 @@ impl sp_std::fmt::Debug for CheckBlockGasLimit { } impl SignedExtension for CheckBlockGasLimit { + const IDENTIFIER: &'static str = "CheckBlockGasLimit"; type AccountId = T::AccountId; type Call = ::Call; type AdditionalSigned = (); diff --git a/substrate/frame/example/src/lib.rs b/substrate/frame/example/src/lib.rs index ab85de8ea9..56d3de14dc 100644 --- a/substrate/frame/example/src/lib.rs +++ b/substrate/frame/example/src/lib.rs @@ -603,6 +603,7 @@ impl sp_std::fmt::Debug for WatchDummy { } impl SignedExtension for WatchDummy { + const IDENTIFIER: &'static str = "WatchDummy"; type AccountId = T::AccountId; // Note that this could also be assigned to the top-level call enum. It is passed into the // balances module directly and since `Trait: pallet_balances::Trait`, you could also use `T::Call`. diff --git a/substrate/frame/metadata/Cargo.toml b/substrate/frame/metadata/Cargo.toml index 9cb6752926..e245f04849 100644 --- a/substrate/frame/metadata/Cargo.toml +++ b/substrate/frame/metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "frame-metadata" -version = "10.0.0" +version = "11.0.0" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0" diff --git a/substrate/frame/metadata/src/lib.rs b/substrate/frame/metadata/src/lib.rs index f6e280bed1..a7410bbfbc 100644 --- a/substrate/frame/metadata/src/lib.rs +++ b/substrate/frame/metadata/src/lib.rs @@ -316,11 +316,21 @@ pub struct StorageMetadata { pub entries: DecodeDifferent<&'static [StorageEntryMetadata], Vec>, } +/// Metadata prefixed by a u32 for reserved usage #[derive(Eq, Encode, PartialEq, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Decode, Serialize))] -/// Metadata prefixed by a u32 for reserved usage pub struct RuntimeMetadataPrefixed(pub u32, pub RuntimeMetadata); +/// Metadata of the extrinsic used by the runtime. +#[derive(Eq, Encode, PartialEq, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] +pub struct ExtrinsicMetadata { + /// Extrinsic version. + pub version: u8, + /// The signed extensions in the order they appear in the extrinsic. + pub signed_extensions: Vec, +} + /// The metadata of a runtime. /// The version ID encoded/decoded through /// the enum nature of `RuntimeMetadata`. @@ -347,8 +357,10 @@ pub enum RuntimeMetadata { V8(RuntimeMetadataDeprecated), /// Version 9 for runtime metadata. No longer used. V9(RuntimeMetadataDeprecated), - /// Version 10 for runtime metadata. - V10(RuntimeMetadataV10), + /// Version 10 for runtime metadata. No longer used. + V10(RuntimeMetadataDeprecated), + /// Version 11 for runtime metadata. + V11(RuntimeMetadataV11), } /// Enum that should fail. @@ -372,12 +384,15 @@ impl Decode for RuntimeMetadataDeprecated { /// The metadata of a runtime. #[derive(Eq, Encode, PartialEq, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Decode, Serialize))] -pub struct RuntimeMetadataV10 { +pub struct RuntimeMetadataV11 { + /// Metadata of all the modules. pub modules: DecodeDifferentArray, + /// Metadata of the extrinsic. + pub extrinsic: ExtrinsicMetadata, } /// The latest version of the metadata. -pub type RuntimeMetadataLastVersion = RuntimeMetadataV10; +pub type RuntimeMetadataLastVersion = RuntimeMetadataV11; /// All metadata about an runtime module. #[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] @@ -402,6 +417,6 @@ impl Into for RuntimeMetadataPrefixed { impl Into for RuntimeMetadataLastVersion { fn into(self) -> RuntimeMetadataPrefixed { - RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V10(self)) + RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V11(self)) } } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 77aa3aa168..f0e9b53bf2 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -9,7 +9,7 @@ license = "GPL-3.0" log = "0.4" serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false, features = ["derive"] } -frame-metadata = { version = "10.0.0", default-features = false, path = "../metadata" } +frame-metadata = { version = "11.0.0", default-features = false, path = "../metadata" } sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" } sp-io ={ path = "../../primitives/io", default-features = false } sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index 7e66610641..b4eaf09f6a 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -22,7 +22,7 @@ use parse::{ModuleDeclaration, RuntimeDefinition, WhereSection}; use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; -use syn::{Ident, Result}; +use syn::{Ident, Result, TypePath}; /// The fixed name of the system module. const SYSTEM_MODULE_NAME: &str = "System"; @@ -86,7 +86,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result( runtime: &'a Ident, module_declarations: impl Iterator, scrate: &'a TokenStream2, + extrinsic: &TypePath, ) -> TokenStream2 { let modules_tokens = module_declarations .filter_map(|module_declaration| { @@ -236,7 +237,7 @@ fn decl_runtime_metadata<'a>( }); quote!( #scrate::impl_runtime_metadata!{ - for #runtime with modules + for #runtime with modules where Extrinsic = #extrinsic #(#modules_tokens)* } ) diff --git a/substrate/frame/support/src/metadata.rs b/substrate/frame/support/src/metadata.rs index 110df87c64..f3c9945f88 100644 --- a/substrate/frame/support/src/metadata.rs +++ b/substrate/frame/support/src/metadata.rs @@ -17,7 +17,8 @@ pub use frame_metadata::{ DecodeDifferent, FnEncode, RuntimeMetadata, ModuleMetadata, RuntimeMetadataLastVersion, DefaultByteGetter, RuntimeMetadataPrefixed, StorageEntryMetadata, StorageMetadata, - StorageEntryType, StorageEntryModifier, DefaultByte, StorageHasher, ModuleErrorMetadata + StorageEntryType, StorageEntryModifier, DefaultByte, StorageHasher, ModuleErrorMetadata, + ExtrinsicMetadata, }; /// Implements the metadata support for the given runtime and all its modules. @@ -43,10 +44,12 @@ pub use frame_metadata::{ ///# type Origin = u32; ///# type BlockNumber = u32; ///# } +///# +///# type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic<(), (), (), ()>; /// /// struct Runtime; /// frame_support::impl_runtime_metadata! { -/// for Runtime with modules +/// for Runtime with modules where Extrinsic = UncheckedExtrinsic /// module0::Module as Module0 with, /// module1::Module as Module1 with, /// module2::Module as Module2 with Storage, @@ -57,13 +60,24 @@ pub use frame_metadata::{ #[macro_export] macro_rules! impl_runtime_metadata { ( - for $runtime:ident with modules + for $runtime:ident with modules where Extrinsic = $ext:ident $( $rest:tt )* ) => { impl $runtime { pub fn metadata() -> $crate::metadata::RuntimeMetadataPrefixed { $crate::metadata::RuntimeMetadataLastVersion { modules: $crate::__runtime_modules_to_metadata!($runtime;; $( $rest )*), + extrinsic: $crate::metadata::ExtrinsicMetadata { + version: <$ext as $crate::sp_runtime::traits::ExtrinsicMetadata>::VERSION, + signed_extensions: < + < + $ext as $crate::sp_runtime::traits::ExtrinsicMetadata + >::SignedExtensions as $crate::sp_runtime::traits::SignedExtension + >::identifier() + .into_iter() + .map($crate::metadata::DecodeDifferent::Encode) + .collect(), + }, }.into() } } @@ -232,10 +246,46 @@ mod tests { use frame_metadata::{ EventMetadata, StorageEntryModifier, StorageEntryType, FunctionMetadata, StorageEntryMetadata, ModuleMetadata, RuntimeMetadataPrefixed, DefaultByte, ModuleConstantMetadata, DefaultByteGetter, - ErrorMetadata, + ErrorMetadata, ExtrinsicMetadata, }; use codec::{Encode, Decode}; use crate::traits::Get; + use sp_runtime::transaction_validity::TransactionValidityError; + + #[derive(Clone, Eq, Debug, PartialEq, Encode, Decode)] + struct TestExtension; + impl sp_runtime::traits::SignedExtension for TestExtension { + type AccountId = u32; + type Call = u32; + type AdditionalSigned = u32; + type DispatchInfo = (); + type Pre = (); + const IDENTIFIER: &'static str = "testextension"; + fn additional_signed(&self) -> Result { + Ok(1) + } + } + + #[derive(Clone, Eq, Debug, PartialEq, Encode, Decode)] + struct TestExtension2; + impl sp_runtime::traits::SignedExtension for TestExtension2 { + type AccountId = u32; + type Call = u32; + type AdditionalSigned = u32; + type DispatchInfo = (); + type Pre = (); + const IDENTIFIER: &'static str = "testextension2"; + fn additional_signed(&self) -> Result { + Ok(1) + } + } + + struct TestExtrinsic; + + impl sp_runtime::traits::ExtrinsicMetadata for TestExtrinsic { + const VERSION: u8 = 1; + type SignedExtensions = (TestExtension, TestExtension2); + } mod system { use super::*; @@ -393,7 +443,7 @@ mod tests { } impl_runtime_metadata!( - for TestRuntime with modules + for TestRuntime with modules where Extrinsic = TestExtrinsic system::Module as System with Event, event_module::Module as Module with Event Call, event_module2::Module as Module2 with Event Storage Call, @@ -420,131 +470,138 @@ mod tests { } } - const EXPECTED_METADATA: RuntimeMetadataLastVersion = RuntimeMetadataLastVersion { - modules: DecodeDifferent::Encode(&[ - ModuleMetadata { - name: DecodeDifferent::Encode("System"), - storage: None, - calls: None, - event: Some(DecodeDifferent::Encode( - FnEncode(||&[ - EventMetadata { - name: DecodeDifferent::Encode("SystemEvent"), - arguments: DecodeDifferent::Encode(&[]), - documentation: DecodeDifferent::Encode(&[]) - } - ]) - )), - constants: DecodeDifferent::Encode( - FnEncode(|| &[ - ModuleConstantMetadata { - name: DecodeDifferent::Encode("BlockNumber"), - ty: DecodeDifferent::Encode("T::BlockNumber"), - value: DecodeDifferent::Encode( - DefaultByteGetter(&ConstantBlockNumberByteGetter) - ), - documentation: DecodeDifferent::Encode(&[" Hi, I am a comment."]), - }, - ModuleConstantMetadata { - name: DecodeDifferent::Encode("GetType"), - ty: DecodeDifferent::Encode("T::AccountId"), - value: DecodeDifferent::Encode( - DefaultByteGetter(&ConstantGetTypeByteGetter) - ), - documentation: DecodeDifferent::Encode(&[]), - }, - ModuleConstantMetadata { - name: DecodeDifferent::Encode("ASSOCIATED_CONST"), - ty: DecodeDifferent::Encode("u64"), - value: DecodeDifferent::Encode( - DefaultByteGetter(&ConstantAssociatedConstByteGetter) - ), - documentation: DecodeDifferent::Encode(&[]), - } - ]) - ), - errors: DecodeDifferent::Encode(FnEncode(|| &[])), - }, - ModuleMetadata { - name: DecodeDifferent::Encode("Module"), - storage: None, - calls: Some( - DecodeDifferent::Encode(FnEncode(|| &[ - FunctionMetadata { - name: DecodeDifferent::Encode("aux_0"), - arguments: DecodeDifferent::Encode(&[]), - documentation: DecodeDifferent::Encode(&[]), - } - ]))), - event: Some(DecodeDifferent::Encode( - FnEncode(||&[ - EventMetadata { - name: DecodeDifferent::Encode("TestEvent"), - arguments: DecodeDifferent::Encode(&["Balance"]), - documentation: DecodeDifferent::Encode(&[" Hi, I am a comment."]) - } - ]) - )), - constants: DecodeDifferent::Encode(FnEncode(|| &[])), - errors: DecodeDifferent::Encode(FnEncode(|| &[ - ErrorMetadata { - name: DecodeDifferent::Encode("UserInputError"), - documentation: DecodeDifferent::Encode(&[" Some user input error"]), - }, - ErrorMetadata { - name: DecodeDifferent::Encode("BadThingHappened"), - documentation: DecodeDifferent::Encode(&[ - " Something bad happened", - " this could be due to many reasons", - ]), - }, - ])), - }, - ModuleMetadata { - name: DecodeDifferent::Encode("Module2"), - storage: Some(DecodeDifferent::Encode( - FnEncode(|| StorageMetadata { - prefix: DecodeDifferent::Encode("TestStorage"), - entries: DecodeDifferent::Encode( - &[ - StorageEntryMetadata { - name: DecodeDifferent::Encode("StorageMethod"), - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), - default: DecodeDifferent::Encode( - DefaultByteGetter( - &event_module2::__GetByteStructStorageMethod( - std::marker::PhantomData:: - ) - ) - ), - documentation: DecodeDifferent::Encode(&[]), - } - ] - ) - }), - )), - calls: Some(DecodeDifferent::Encode(FnEncode(|| &[]))), - event: Some(DecodeDifferent::Encode( - FnEncode(||&[ - EventMetadata { - name: DecodeDifferent::Encode("TestEvent"), - arguments: DecodeDifferent::Encode(&["Balance"]), - documentation: DecodeDifferent::Encode(&[]) - } - ]) - )), - constants: DecodeDifferent::Encode(FnEncode(|| &[])), - errors: DecodeDifferent::Encode(FnEncode(|| &[])), - }, - ]) - }; - #[test] fn runtime_metadata() { + let expected_metadata: RuntimeMetadataLastVersion = RuntimeMetadataLastVersion { + modules: DecodeDifferent::Encode(&[ + ModuleMetadata { + name: DecodeDifferent::Encode("System"), + storage: None, + calls: None, + event: Some(DecodeDifferent::Encode( + FnEncode(||&[ + EventMetadata { + name: DecodeDifferent::Encode("SystemEvent"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]) + } + ]) + )), + constants: DecodeDifferent::Encode( + FnEncode(|| &[ + ModuleConstantMetadata { + name: DecodeDifferent::Encode("BlockNumber"), + ty: DecodeDifferent::Encode("T::BlockNumber"), + value: DecodeDifferent::Encode( + DefaultByteGetter(&ConstantBlockNumberByteGetter) + ), + documentation: DecodeDifferent::Encode(&[" Hi, I am a comment."]), + }, + ModuleConstantMetadata { + name: DecodeDifferent::Encode("GetType"), + ty: DecodeDifferent::Encode("T::AccountId"), + value: DecodeDifferent::Encode( + DefaultByteGetter(&ConstantGetTypeByteGetter) + ), + documentation: DecodeDifferent::Encode(&[]), + }, + ModuleConstantMetadata { + name: DecodeDifferent::Encode("ASSOCIATED_CONST"), + ty: DecodeDifferent::Encode("u64"), + value: DecodeDifferent::Encode( + DefaultByteGetter(&ConstantAssociatedConstByteGetter) + ), + documentation: DecodeDifferent::Encode(&[]), + } + ]) + ), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module"), + storage: None, + calls: Some( + DecodeDifferent::Encode(FnEncode(|| &[ + FunctionMetadata { + name: DecodeDifferent::Encode("aux_0"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + } + ]))), + event: Some(DecodeDifferent::Encode( + FnEncode(||&[ + EventMetadata { + name: DecodeDifferent::Encode("TestEvent"), + arguments: DecodeDifferent::Encode(&["Balance"]), + documentation: DecodeDifferent::Encode(&[" Hi, I am a comment."]) + } + ]) + )), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[ + ErrorMetadata { + name: DecodeDifferent::Encode("UserInputError"), + documentation: DecodeDifferent::Encode(&[" Some user input error"]), + }, + ErrorMetadata { + name: DecodeDifferent::Encode("BadThingHappened"), + documentation: DecodeDifferent::Encode(&[ + " Something bad happened", + " this could be due to many reasons", + ]), + }, + ])), + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module2"), + storage: Some(DecodeDifferent::Encode( + FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("TestStorage"), + entries: DecodeDifferent::Encode( + &[ + StorageEntryMetadata { + name: DecodeDifferent::Encode("StorageMethod"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter( + &event_module2::__GetByteStructStorageMethod( + std::marker::PhantomData:: + ) + ) + ), + documentation: DecodeDifferent::Encode(&[]), + } + ] + ) + }), + )), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[]))), + event: Some(DecodeDifferent::Encode( + FnEncode(||&[ + EventMetadata { + name: DecodeDifferent::Encode("TestEvent"), + arguments: DecodeDifferent::Encode(&["Balance"]), + documentation: DecodeDifferent::Encode(&[]) + } + ]) + )), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + }, + ]), + extrinsic: ExtrinsicMetadata { + version: 1, + signed_extensions: vec![ + DecodeDifferent::Encode("testextension"), + DecodeDifferent::Encode("testextension2"), + ], + } + }; + let metadata_encoded = TestRuntime::metadata().encode(); let metadata_decoded = RuntimeMetadataPrefixed::decode(&mut &metadata_encoded[..]); - let expected_metadata: RuntimeMetadataPrefixed = EXPECTED_METADATA.into(); + let expected_metadata: RuntimeMetadataPrefixed = expected_metadata.into(); pretty_assertions::assert_eq!(expected_metadata, metadata_decoded.unwrap()); } diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 4e665fd385..4a06dec6ee 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -960,6 +960,7 @@ impl SignedExtension for CheckWeight { type AdditionalSigned = (); type DispatchInfo = DispatchInfo; type Pre = (); + const IDENTIFIER: &'static str = "CheckWeight"; fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) } @@ -1040,6 +1041,7 @@ impl SignedExtension for CheckNonce { type AdditionalSigned = (); type DispatchInfo = DispatchInfo; type Pre = (); + const IDENTIFIER: &'static str = "CheckNonce"; fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) } @@ -1124,6 +1126,7 @@ impl SignedExtension for CheckEra { type AdditionalSigned = T::Hash; type DispatchInfo = DispatchInfo; type Pre = (); + const IDENTIFIER: &'static str = "CheckEra"; fn validate( &self, @@ -1180,6 +1183,7 @@ impl SignedExtension for CheckGenesis { type AdditionalSigned = T::Hash; type DispatchInfo = DispatchInfo; type Pre = (); + const IDENTIFIER: &'static str = "CheckGenesis"; fn additional_signed(&self) -> Result { Ok(>::block_hash(T::BlockNumber::zero())) @@ -1215,6 +1219,7 @@ impl SignedExtension for CheckVersion { type AdditionalSigned = u32; type DispatchInfo = DispatchInfo; type Pre = (); + const IDENTIFIER: &'static str = "CheckVersion"; fn additional_signed(&self) -> Result { Ok(>::runtime_version().spec_version) diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index 370bd87b4c..34768d808e 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -201,6 +201,7 @@ impl sp_std::fmt::Debug for ChargeTransactionPayment impl SignedExtension for ChargeTransactionPayment where BalanceOf: Send + Sync { + const IDENTIFIER: &'static str = "ChargeTransactionPayment"; type AccountId = T::AccountId; type Call = T::Call; type AdditionalSigned = (); diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 0a43524248..96e7988103 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -20,7 +20,10 @@ use sp_std::{fmt, prelude::*}; use sp_io::hashing::blake2_256; use codec::{Decode, Encode, EncodeLike, Input, Error}; use crate::{ - traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic, IdentifyAccount}, + traits::{ + self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic, ExtrinsicMetadata, + IdentifyAccount, + }, generic::CheckedExtrinsic, transaction_validity::{TransactionValidityError, InvalidTransaction}, }; @@ -130,6 +133,15 @@ where } } +impl ExtrinsicMetadata + for UncheckedExtrinsic + where + Extra: SignedExtension, +{ + const VERSION: u8 = TRANSACTION_VERSION; + type SignedExtensions = Extra; +} + /// A payload that has been signed for an unchecked extrinsics. /// /// Note that the payload that we sign to produce unchecked extrinsic signature @@ -316,6 +328,7 @@ mod tests { #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Ord, PartialOrd)] struct TestExtra; impl SignedExtension for TestExtra { + const IDENTIFIER: &'static str = "TestExtra"; type AccountId = u64; type Call = (); type AdditionalSigned = (); diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs index 3210b00c6b..f8c2ed11a4 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -608,6 +608,15 @@ pub trait Extrinsic: Sized { fn new(_call: Self::Call, _signed_data: Option) -> Option { None } } +/// Implementor is an [`Extrinsic`] and provides metadata about this extrinsic. +pub trait ExtrinsicMetadata { + /// The version of the `Extrinsic`. + const VERSION: u8; + + /// Signed extensions attached to this `Extrinsic`. + type SignedExtensions: SignedExtension; +} + /// Extract the hasher type for a block. pub type HasherFor = as Hash>::Hasher; /// Extract the hashing type for a block. @@ -668,6 +677,12 @@ pub trait Dispatchable { /// Means by which a transaction may be extended. This type embodies both the data and the logic /// that should be additionally associated with the transaction. It should be plain old data. pub trait SignedExtension: Codec + Debug + Sync + Send + Clone + Eq + PartialEq { + /// Unique identifier of this signed extension. + /// + /// This will be exposed in the metadata to identify the signed extension used + /// in an extrinsic. + const IDENTIFIER: &'static str; + /// The type which encodes the sender identity. type AccountId; @@ -765,6 +780,17 @@ pub trait SignedExtension: Codec + Debug + Sync + Send + Clone + Eq + PartialEq /// Do any post-flight stuff for a transaction. fn post_dispatch(_pre: Self::Pre, _info: Self::DispatchInfo, _len: usize) { } + + /// Returns the list of unique identifier for this signed extension. + /// + /// As a [`SignedExtension`] can be a tuple of [`SignedExtension`]`s we need to return a `Vec` + /// that holds all the unique identifiers. Each individual `SignedExtension` must return + /// *exactly* one identifier. + /// + /// This method provides a default implementation that returns `vec![SELF::IDENTIFIER]`. + fn identifier() -> Vec<&'static str> { + sp_std::vec![Self::IDENTIFIER] + } } #[impl_for_tuples(1, 12)] @@ -773,6 +799,7 @@ impl SignedExtension for Tuple { type AccountId = AccountId; type Call = Call; type DispatchInfo = Info; + const IDENTIFIER: &'static str = "You should call `identifier()`!"; for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); ); for_tuples!( type Pre = ( #( Tuple::Pre ),* ); ); @@ -823,6 +850,12 @@ impl SignedExtension for Tuple { ) { for_tuples!( #( Tuple::post_dispatch(pre.Tuple, info.clone(), len); )* ) } + + fn identifier() -> Vec<&'static str> { + let mut ids = Vec::new(); + for_tuples!( #( ids.extend(Tuple::identifier()); )* ); + ids + } } /// Only for bare bone testing when you don't care about signed extensions at all. @@ -833,6 +866,7 @@ impl SignedExtension for () { type Call = (); type Pre = (); type DispatchInfo = (); + const IDENTIFIER: &'static str = "UnitSignedExtension"; fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) } }