Expose information about the extrinsic in the metadata (#4774)

* Expose information about the extrinsic in the metadata

This pr exposes some information about the extrinsic used in the runtime
via metadata. The following information are exposed:

- Version of the extrinsic
- List of all signed extensions used by the extrinsic.

* Increment `spec_version`
This commit is contained in:
Bastian Köcher
2020-01-30 16:41:03 +01:00
committed by GitHub
parent 6272b8d2c7
commit 45938d8033
13 changed files with 269 additions and 141 deletions
+2 -2
View File
@@ -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)",
+1 -1
View File
@@ -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,
};
+1
View File
@@ -1103,6 +1103,7 @@ impl<T: Trait + Send + Sync> sp_std::fmt::Debug for CheckBlockGasLimit<T> {
}
impl<T: Trait + Send + Sync> SignedExtension for CheckBlockGasLimit<T> {
const IDENTIFIER: &'static str = "CheckBlockGasLimit";
type AccountId = T::AccountId;
type Call = <T as Trait>::Call;
type AdditionalSigned = ();
+1
View File
@@ -603,6 +603,7 @@ impl<T: Trait + Send + Sync> sp_std::fmt::Debug for WatchDummy<T> {
}
impl<T: Trait + Send + Sync> SignedExtension for WatchDummy<T> {
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`.
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "frame-metadata"
version = "10.0.0"
version = "11.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "GPL-3.0"
+21 -6
View File
@@ -316,11 +316,21 @@ pub struct StorageMetadata {
pub entries: DecodeDifferent<&'static [StorageEntryMetadata], Vec<StorageEntryMetadata>>,
}
/// 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<DecodeDifferentStr>,
}
/// 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<ModuleMetadata>,
/// 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<sp_core::OpaqueMetadata> for RuntimeMetadataPrefixed {
impl Into<RuntimeMetadataPrefixed> for RuntimeMetadataLastVersion {
fn into(self) -> RuntimeMetadataPrefixed {
RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V10(self))
RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V11(self))
}
}
+1 -1
View File
@@ -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" }
@@ -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<TokenStream
let module_to_index = decl_module_to_index(modules.iter(), modules.len(), &scrate);
let dispatch = decl_outer_dispatch(&name, modules.iter(), &scrate);
let metadata = decl_runtime_metadata(&name, modules.iter(), &scrate);
let metadata = decl_runtime_metadata(&name, modules.iter(), &scrate, &unchecked_extrinsic);
let outer_config = decl_outer_config(&name, modules.iter(), &scrate);
let inherent = decl_outer_inherent(&block, &unchecked_extrinsic, modules.iter(), &scrate);
let validate_unsigned = decl_validate_unsigned(&name, modules.iter(), &scrate);
@@ -211,6 +211,7 @@ fn decl_runtime_metadata<'a>(
runtime: &'a Ident,
module_declarations: impl Iterator<Item = &'a ModuleDeclaration>,
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)*
}
)
+183 -126
View File
@@ -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<Self::AdditionalSigned, TransactionValidityError> {
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<Self::AdditionalSigned, TransactionValidityError> {
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::<TestRuntime>
)
)
),
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::<TestRuntime>
)
)
),
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());
}
+5
View File
@@ -960,6 +960,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
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<T: Trait> SignedExtension for CheckNonce<T> {
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<T: Trait + Send + Sync> SignedExtension for CheckEra<T> {
type AdditionalSigned = T::Hash;
type DispatchInfo = DispatchInfo;
type Pre = ();
const IDENTIFIER: &'static str = "CheckEra";
fn validate(
&self,
@@ -1180,6 +1183,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckGenesis<T> {
type AdditionalSigned = T::Hash;
type DispatchInfo = DispatchInfo;
type Pre = ();
const IDENTIFIER: &'static str = "CheckGenesis";
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(<Module<T>>::block_hash(T::BlockNumber::zero()))
@@ -1215,6 +1219,7 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckVersion<T> {
type AdditionalSigned = u32;
type DispatchInfo = DispatchInfo;
type Pre = ();
const IDENTIFIER: &'static str = "CheckVersion";
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(<Module<T>>::runtime_version().spec_version)
@@ -201,6 +201,7 @@ impl<T: Trait + Send + Sync> sp_std::fmt::Debug for ChargeTransactionPayment<T>
impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T>
where BalanceOf<T>: Send + Sync
{
const IDENTIFIER: &'static str = "ChargeTransactionPayment";
type AccountId = T::AccountId;
type Call = T::Call;
type AdditionalSigned = ();
@@ -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<Address, Call, Signature, Extra> ExtrinsicMetadata
for UncheckedExtrinsic<Address, Call, Signature, Extra>
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 = ();
@@ -608,6 +608,15 @@ pub trait Extrinsic: Sized {
fn new(_call: Self::Call, _signed_data: Option<Self::SignaturePayload>) -> Option<Self> { 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<B> = <HashFor<B> 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<AccountId, Call, Info: Clone> 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<AccountId, Call, Info: Clone> 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(()) }
}