Metadata V15: Enrich extrinsic type info for decoding (#14123)

* metadata-ir: Add extrinsic type info to decode address, call, sig

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame-metadata: Point to unreleased branch

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* metadata-ir: Include addrees, call, signature in V15 conversion

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* metadata-ir: Include extra ty

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* construct_runtime: Extract address,call,sig,extra ty from tx type

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/tests: Check metadata populates xt types correctly

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* metadata-ir/tests: Add extra fields on ExtrinsicMetadataIR

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/traits: Expand the `Extrinsic::SignaturePayload`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Adjust to new `Extrinsic` associated types

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/metadata: Simplify metadata generation

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/example: Adjust to new interface

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/tests: Adjust `extrinsic_metadata_ir_types`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Revert the additional Extrinsic' associated types

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Add `SignaturePayload` marker trait

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Implement SignaturePayload for empty tuple

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Adjust to new SignaturePayload trait

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* tests: Adjust `extrinsic_metadata_ir_types` to new interface

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/support: Adjust pallet test

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame: Add Extrinsic length prefix to the metadata

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Populate `ExtrinsicMetadataIR` with `len_ty`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update primitives/runtime/src/traits.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Apply cargo fmt

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* v15: Remove len type of the extrinsic

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* cargo: Update frame-metadata

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

---------

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Co-authored-by: Bastian Köcher <git@kchr.de>
Co-authored-by: parity-processbot <>
This commit is contained in:
Alexandru Vasile
2023-06-28 15:44:20 +03:00
committed by GitHub
parent b4e863c472
commit 943697fa69
9 changed files with 131 additions and 21 deletions
@@ -96,11 +96,29 @@ pub fn expand_runtime_metadata(
// `Deref` needs a reference for resolving the function call. // `Deref` needs a reference for resolving the function call.
let rt = #runtime; let rt = #runtime;
let ty = #scrate::scale_info::meta_type::<#extrinsic>();
let address_ty = #scrate::scale_info::meta_type::<
<<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::SignatureAddress
>();
let call_ty = #scrate::scale_info::meta_type::<
<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::Call
>();
let signature_ty = #scrate::scale_info::meta_type::<
<<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::Signature
>();
let extra_ty = #scrate::scale_info::meta_type::<
<<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::SignatureExtra
>();
#scrate::metadata_ir::MetadataIR { #scrate::metadata_ir::MetadataIR {
pallets: #scrate::sp_std::vec![ #(#pallets),* ], pallets: #scrate::sp_std::vec![ #(#pallets),* ],
extrinsic: #scrate::metadata_ir::ExtrinsicMetadataIR { extrinsic: #scrate::metadata_ir::ExtrinsicMetadataIR {
ty: #scrate::scale_info::meta_type::<#extrinsic>(), ty,
version: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSION, version: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSION,
address_ty,
call_ty,
signature_ty,
extra_ty,
signed_extensions: < signed_extensions: <
< <
#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata
+6 -2
View File
@@ -893,7 +893,8 @@ pub trait ExtrinsicCall: sp_runtime::traits::Extrinsic {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<Call, Extra> ExtrinsicCall for sp_runtime::testing::TestXt<Call, Extra> impl<Call, Extra> ExtrinsicCall for sp_runtime::testing::TestXt<Call, Extra>
where where
Call: codec::Codec + Sync + Send, Call: codec::Codec + Sync + Send + TypeInfo,
Extra: TypeInfo,
{ {
fn call(&self) -> &Self::Call { fn call(&self) -> &Self::Call {
&self.call &self.call
@@ -903,7 +904,10 @@ where
impl<Address, Call, Signature, Extra> ExtrinsicCall impl<Address, Call, Signature, Extra> ExtrinsicCall
for sp_runtime::generic::UncheckedExtrinsic<Address, Call, Signature, Extra> for sp_runtime::generic::UncheckedExtrinsic<Address, Call, Signature, Extra>
where where
Extra: sp_runtime::traits::SignedExtension, Address: TypeInfo,
Call: TypeInfo,
Signature: TypeInfo,
Extra: sp_runtime::traits::SignedExtension + TypeInfo,
{ {
fn call(&self) -> &Self::Call { fn call(&self) -> &Self::Call {
&self.function &self.function
+26 -2
View File
@@ -36,7 +36,10 @@ use sp_io::{
hashing::{blake2_128, twox_128, twox_64}, hashing::{blake2_128, twox_128, twox_64},
TestExternalities, TestExternalities,
}; };
use sp_runtime::{DispatchError, ModuleError}; use sp_runtime::{
traits::{Extrinsic as ExtrinsicT, SignaturePayload as SignaturePayloadT},
DispatchError, ModuleError,
};
parameter_types! { parameter_types! {
/// Used to control if the storage version should be updated. /// Used to control if the storage version should be updated.
@@ -1700,6 +1703,28 @@ fn metadata_ir_pallet_runtime_docs() {
assert_eq!(pallet.docs, expected); assert_eq!(pallet.docs, expected);
} }
#[test]
fn extrinsic_metadata_ir_types() {
let ir = Runtime::metadata_ir().extrinsic;
assert_eq!(meta_type::<<<UncheckedExtrinsic as ExtrinsicT>::SignaturePayload as SignaturePayloadT>::SignatureAddress>(), ir.address_ty);
assert_eq!(meta_type::<u64>(), ir.address_ty);
assert_eq!(meta_type::<<UncheckedExtrinsic as ExtrinsicT>::Call>(), ir.call_ty);
assert_eq!(meta_type::<RuntimeCall>(), ir.call_ty);
assert_eq!(
meta_type::<
<<UncheckedExtrinsic as ExtrinsicT>::SignaturePayload as SignaturePayloadT>::Signature,
>(),
ir.signature_ty
);
assert_eq!(meta_type::<()>(), ir.signature_ty);
assert_eq!(meta_type::<<<UncheckedExtrinsic as ExtrinsicT>::SignaturePayload as SignaturePayloadT>::SignatureExtra>(), ir.extra_ty);
assert_eq!(meta_type::<frame_system::CheckNonZeroSender<Runtime>>(), ir.extra_ty);
}
#[test] #[test]
fn test_pallet_runtime_docs() { fn test_pallet_runtime_docs() {
let docs = crate::pallet::Pallet::<Runtime>::pallet_documentation_metadata(); let docs = crate::pallet::Pallet::<Runtime>::pallet_documentation_metadata();
@@ -1713,7 +1738,6 @@ fn test_pallet_info_access() {
assert_eq!(<System as frame_support::traits::PalletInfoAccess>::name(), "System"); assert_eq!(<System as frame_support::traits::PalletInfoAccess>::name(), "System");
assert_eq!(<Example as frame_support::traits::PalletInfoAccess>::name(), "Example"); assert_eq!(<Example as frame_support::traits::PalletInfoAccess>::name(), "Example");
assert_eq!(<Example2 as frame_support::traits::PalletInfoAccess>::name(), "Example2"); assert_eq!(<Example2 as frame_support::traits::PalletInfoAccess>::name(), "Example2");
assert_eq!(<System as frame_support::traits::PalletInfoAccess>::index(), 0); assert_eq!(<System as frame_support::traits::PalletInfoAccess>::index(), 0);
assert_eq!(<Example as frame_support::traits::PalletInfoAccess>::index(), 1); assert_eq!(<Example as frame_support::traits::PalletInfoAccess>::index(), 1);
assert_eq!(<Example2 as frame_support::traits::PalletInfoAccess>::index(), 2); assert_eq!(<Example2 as frame_support::traits::PalletInfoAccess>::index(), 2);
@@ -81,6 +81,10 @@ mod test {
extrinsic: ExtrinsicMetadataIR { extrinsic: ExtrinsicMetadataIR {
ty: meta_type::<()>(), ty: meta_type::<()>(),
version: 0, version: 0,
address_ty: meta_type::<()>(),
call_ty: meta_type::<()>(),
signature_ty: meta_type::<()>(),
extra_ty: meta_type::<()>(),
signed_extensions: vec![], signed_extensions: vec![],
}, },
ty: meta_type::<()>(), ty: meta_type::<()>(),
@@ -155,9 +155,19 @@ impl IntoPortable for PalletMetadataIR {
#[derive(Clone, PartialEq, Eq, Encode, Debug)] #[derive(Clone, PartialEq, Eq, Encode, Debug)]
pub struct ExtrinsicMetadataIR<T: Form = MetaForm> { pub struct ExtrinsicMetadataIR<T: Form = MetaForm> {
/// The type of the extrinsic. /// The type of the extrinsic.
///
/// Note: Field used for metadata V14 only.
pub ty: T::Type, pub ty: T::Type,
/// Extrinsic version. /// Extrinsic version.
pub version: u8, pub version: u8,
/// The type of the address that signes the extrinsic
pub address_ty: T::Type,
/// The type of the outermost Call enum.
pub call_ty: T::Type,
/// The type of the extrinsic's signature.
pub signature_ty: T::Type,
/// The type of the outermost Extra enum.
pub extra_ty: T::Type,
/// The signed extensions in the order they appear in the extrinsic. /// The signed extensions in the order they appear in the extrinsic.
pub signed_extensions: Vec<SignedExtensionMetadataIR<T>>, pub signed_extensions: Vec<SignedExtensionMetadataIR<T>>,
} }
@@ -169,6 +179,10 @@ impl IntoPortable for ExtrinsicMetadataIR {
ExtrinsicMetadataIR { ExtrinsicMetadataIR {
ty: registry.register_type(&self.ty), ty: registry.register_type(&self.ty),
version: self.version, version: self.version,
address_ty: registry.register_type(&self.address_ty),
call_ty: registry.register_type(&self.call_ty),
signature_ty: registry.register_type(&self.signature_ty),
extra_ty: registry.register_type(&self.extra_ty),
signed_extensions: registry.map_into_portable(self.signed_extensions), signed_extensions: registry.map_into_portable(self.signed_extensions),
} }
} }
+4 -5
View File
@@ -101,12 +101,11 @@ impl From<ExtrinsicMetadataIR> for ExtrinsicMetadata {
fn from(ir: ExtrinsicMetadataIR) -> Self { fn from(ir: ExtrinsicMetadataIR) -> Self {
ExtrinsicMetadata { ExtrinsicMetadata {
version: ir.version, version: ir.version,
address_ty: ir.address_ty,
call_ty: ir.call_ty,
signature_ty: ir.signature_ty,
extra_ty: ir.extra_ty,
signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(), signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(),
// Note: These fields are populated by complementary PR: https://github.com/paritytech/substrate/pull/14123.
address_ty: ir.ty,
call_ty: ir.ty,
signature_ty: ir.ty,
extra_ty: ir.ty,
} }
} }
} }
@@ -21,7 +21,7 @@ use crate::{
generic::CheckedExtrinsic, generic::CheckedExtrinsic,
traits::{ traits::{
self, Checkable, Extrinsic, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, self, Checkable, Extrinsic, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member,
SignedExtension, SignaturePayload, SignedExtension,
}, },
transaction_validity::{InvalidTransaction, TransactionValidityError}, transaction_validity::{InvalidTransaction, TransactionValidityError},
OpaqueExtrinsic, OpaqueExtrinsic,
@@ -40,6 +40,9 @@ use sp_std::{fmt, prelude::*};
/// the decoding fails. /// the decoding fails.
const EXTRINSIC_FORMAT_VERSION: u8 = 4; const EXTRINSIC_FORMAT_VERSION: u8 = 4;
/// The `SingaturePayload` of `UncheckedExtrinsic`.
type UncheckedSignaturePayload<Address, Signature, Extra> = (Address, Signature, Extra);
/// A extrinsic right from the external world. This is unchecked and so /// A extrinsic right from the external world. This is unchecked and so
/// can contain a signature. /// can contain a signature.
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
@@ -50,11 +53,19 @@ where
/// The signature, address, number of extrinsics have come before from /// The signature, address, number of extrinsics have come before from
/// the same signer and an era describing the longevity of this transaction, /// the same signer and an era describing the longevity of this transaction,
/// if this is a signed extrinsic. /// if this is a signed extrinsic.
pub signature: Option<(Address, Signature, Extra)>, pub signature: Option<UncheckedSignaturePayload<Address, Signature, Extra>>,
/// The function that should be called. /// The function that should be called.
pub function: Call, pub function: Call,
} }
impl<Address: TypeInfo, Signature: TypeInfo, Extra: TypeInfo> SignaturePayload
for UncheckedSignaturePayload<Address, Signature, Extra>
{
type SignatureAddress = Address;
type Signature = Signature;
type SignatureExtra = Extra;
}
/// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded /// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded
/// `Vec<u8>`, but requires some logic to extract the signature and payload. /// `Vec<u8>`, but requires some logic to extract the signature and payload.
/// ///
@@ -103,12 +114,12 @@ impl<Address, Call, Signature, Extra: SignedExtension>
} }
} }
impl<Address, Call, Signature, Extra: SignedExtension> Extrinsic impl<Address: TypeInfo, Call: TypeInfo, Signature: TypeInfo, Extra: SignedExtension + TypeInfo>
for UncheckedExtrinsic<Address, Call, Signature, Extra> Extrinsic for UncheckedExtrinsic<Address, Call, Signature, Extra>
{ {
type Call = Call; type Call = Call;
type SignaturePayload = (Address, Signature, Extra); type SignaturePayload = UncheckedSignaturePayload<Address, Signature, Extra>;
fn is_signed(&self) -> Option<bool> { fn is_signed(&self) -> Option<bool> {
Some(self.signature.is_some()) Some(self.signature.is_some())
+15 -4
View File
@@ -23,7 +23,7 @@ use crate::{
scale_info::TypeInfo, scale_info::TypeInfo,
traits::{ traits::{
self, Applyable, BlakeTwo256, Checkable, DispatchInfoOf, Dispatchable, OpaqueKeys, self, Applyable, BlakeTwo256, Checkable, DispatchInfoOf, Dispatchable, OpaqueKeys,
PostDispatchInfoOf, SignedExtension, ValidateUnsigned, PostDispatchInfoOf, SignaturePayload, SignedExtension, ValidateUnsigned,
}, },
transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError},
ApplyExtrinsicResultWithInfo, KeyTypeId, ApplyExtrinsicResultWithInfo, KeyTypeId,
@@ -279,6 +279,15 @@ where
} }
} }
/// The signature payload of a `TestXt`.
type TxSingaturePayload<Extra> = (u64, Extra);
impl<Extra: TypeInfo> SignaturePayload for TxSingaturePayload<Extra> {
type SignatureAddress = u64;
type Signature = ();
type SignatureExtra = Extra;
}
/// Test transaction, tuple of (sender, call, signed_extra) /// Test transaction, tuple of (sender, call, signed_extra)
/// with index only used if sender is some. /// with index only used if sender is some.
/// ///
@@ -286,7 +295,7 @@ where
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
pub struct TestXt<Call, Extra> { pub struct TestXt<Call, Extra> {
/// Signature of the extrinsic. /// Signature of the extrinsic.
pub signature: Option<(u64, Extra)>, pub signature: Option<TxSingaturePayload<Extra>>,
/// Call of the extrinsic. /// Call of the extrinsic.
pub call: Call, pub call: Call,
} }
@@ -331,9 +340,11 @@ impl<Call: Codec + Sync + Send, Context, Extra> Checkable<Context> for TestXt<Ca
} }
} }
impl<Call: Codec + Sync + Send, Extra> traits::Extrinsic for TestXt<Call, Extra> { impl<Call: Codec + Sync + Send + TypeInfo, Extra: TypeInfo> traits::Extrinsic
for TestXt<Call, Extra>
{
type Call = Call; type Call = Call;
type SignaturePayload = (u64, Extra); type SignaturePayload = TxSingaturePayload<Extra>;
fn is_signed(&self) -> Option<bool> { fn is_signed(&self) -> Option<bool> {
Some(self.signature.is_some()) Some(self.signature.is_some())
+27 -2
View File
@@ -1242,14 +1242,14 @@ pub trait Block: Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + 'st
/// Something that acts like an `Extrinsic`. /// Something that acts like an `Extrinsic`.
pub trait Extrinsic: Sized { pub trait Extrinsic: Sized {
/// The function call. /// The function call.
type Call; type Call: TypeInfo;
/// The payload we carry for signed extrinsics. /// The payload we carry for signed extrinsics.
/// ///
/// Usually it will contain a `Signature` and /// Usually it will contain a `Signature` and
/// may include some additional data that are specific to signed /// may include some additional data that are specific to signed
/// extrinsics. /// extrinsics.
type SignaturePayload; type SignaturePayload: SignaturePayload;
/// Is this `Extrinsic` signed? /// Is this `Extrinsic` signed?
/// If no information are available about signed/unsigned, `None` should be returned. /// If no information are available about signed/unsigned, `None` should be returned.
@@ -1268,6 +1268,31 @@ pub trait Extrinsic: Sized {
} }
} }
/// Something that acts like a [`SignaturePayload`](Extrinsic::SignaturePayload) of an
/// [`Extrinsic`].
pub trait SignaturePayload {
/// The type of the address that signed the extrinsic.
///
/// Particular to a signed extrinsic.
type SignatureAddress: TypeInfo;
/// The signature type of the extrinsic.
///
/// Particular to a signed extrinsic.
type Signature: TypeInfo;
/// The additional data that is specific to the signed extrinsic.
///
/// Particular to a signed extrinsic.
type SignatureExtra: TypeInfo;
}
impl SignaturePayload for () {
type SignatureAddress = ();
type Signature = ();
type SignatureExtra = ();
}
/// Implementor is an [`Extrinsic`] and provides metadata about this extrinsic. /// Implementor is an [`Extrinsic`] and provides metadata about this extrinsic.
pub trait ExtrinsicMetadata { pub trait ExtrinsicMetadata {
/// The format version of the `Extrinsic`. /// The format version of the `Extrinsic`.