mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 22:11:06 +00:00
Utilize Metadata V15 (#1041)
* Update frame-metadata to the latest branch Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Add outer enum types Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Extend the extrinsic with address,call,sign,extra types Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Codegen test Event, Error and Call for outer enums Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Revert "Codegen test Event, Error and Call for outer enums" This reverts commit db542dca0369eedd257a7ec031d5b5549bc46a88. * Update frame-metadata from the latest release Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update scale-info Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen/error: Support v15 message Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Convert v14 to v15 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata/retain: Adjust to extrinsic type for V15 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata/validation: Adjust hashing for extrinsic types V15 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * scripts: Fetch V15 and output codegen for full_client only Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt/blocks: Use extrinsic types directly Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * testing: Fetch V15 for build script Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * artifacts: Generate from latest polkadot version Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Fetch legacy with old API for v14 only Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * rpc: Fetch metadata versions Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * client: Fetch latest unstable then V15 then V14 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * testing: Adjust testing API to latest interface Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust clippy Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Generate the `RuntimeError` type for V14 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Remove testing files Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * testing/staking: Remove controller account from bond Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata/validation: Use specific variants for hashing RuntimeCall Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * XXX: Custom Substrate binary: must revert with next release Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * XXX: To revert: CI use hardcoded substrate Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Use v15 outer enum types Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Retain outer enum types Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Use outer enum types instead of generating them Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update artifacts Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Revert "XXX: Custom Substrate binary: must revert with next release" This reverts commit e9705298661919f5769720b35030759fb8a7b01d. Revert "XXX: To revert: CI use hardcoded substrate" This reverts commit b18a5a0985a56ee4ad99bc9a1c0f9cd733cf4271. * testing: Include env for dummy wat contracts Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjsut clippy Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * ci: Use new link for fetching latest substrate binary Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * tests: Include dummy RuntimeEvent into test metadata Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * ci: Bump light-client timeout tests to 25min Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata/validation: Use specific pallets as provided Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * testing: Rename metadata constant Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Use call_ty instead of signature_ty Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Rename retaining variant function Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Use Option<&[&str]> Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * online_client: Fetch V15 metadata explicitely Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata/validation: Include the hash of the outer enum types Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Fix sign typo Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * artifacts: Update the artifacts Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Remove RootError RootEvent and RootExtrinsic traits Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update polkadot.rs Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata/tests: Ensure outer enum variants are retained Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * scripts: Include multiple pallets for our decoding purposes Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Apply clippy Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * artifacts: Update small metadata Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * error: Keep raw bytes for the ModuleError representation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * error: Modify docs to not include links Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt/tests: Propagate `RuntimeCall` to outer enums Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Provide proper byte slice for decoding Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update artifacts Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli/tests: Adjust expected pallets message Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Test conversion from v14 to v15 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Fix typo Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update subxt/src/blocks/extrinsic_types.rs Co-authored-by: James Wilson <james@jsdw.me> * metadata: Simplify type path for RuntimeError Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata/validation: Use visited ids per outer enum Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * error: Remove RawModuleError Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Fix new clippy error from updated rust version Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> Co-authored-by: James Wilson <james@jsdw.me>
This commit is contained in:
@@ -16,8 +16,8 @@ use crate::{
|
||||
use crate::utils::strip_compact_prefix;
|
||||
use codec::Decode;
|
||||
use derivative::Derivative;
|
||||
use scale_decode::DecodeAsFields;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use scale_decode::{DecodeAsFields, DecodeAsType};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Trait to uniquely identify the extrinsic's identity from the runtime metadata.
|
||||
///
|
||||
@@ -37,23 +37,6 @@ pub trait StaticExtrinsic: DecodeAsFields {
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait is implemented on the statically generated root extrinsic type, so that we're able
|
||||
/// to decode it properly via a pallet that impls `DecodeAsMetadata`. This is necessary
|
||||
/// because the "root extrinsic" type is generated using pallet info but doesn't actually exist in the
|
||||
/// metadata types, so we have no easy way to decode things into it via type information and need a
|
||||
/// little help via codegen.
|
||||
#[doc(hidden)]
|
||||
pub trait RootExtrinsic: Sized {
|
||||
/// Given details of the pallet extrinsic we want to decode, and the name of the pallet, try to hand
|
||||
/// back a "root extrinsic".
|
||||
fn root_extrinsic(
|
||||
pallet_bytes: &[u8],
|
||||
pallet_name: &str,
|
||||
pallet_extrinsic_ty: u32,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
/// The body of a block.
|
||||
pub struct Extrinsics<T: Config, C> {
|
||||
client: C,
|
||||
@@ -420,22 +403,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to decode these [`ExtrinsicDetails`] into a root extrinsic type (which includes
|
||||
/// Attempt to decode these [`ExtrinsicDetails`] into an outer call enum type (which includes
|
||||
/// the pallet and extrinsic enum variants as well as the extrinsic fields). A compatible
|
||||
/// type for this is exposed via static codegen as a root level `Call` type.
|
||||
pub fn as_root_extrinsic<E: RootExtrinsic>(&self) -> Result<E, Error> {
|
||||
let md = self.extrinsic_metadata()?;
|
||||
let pallet_extrinsic_ty = md.pallet.call_ty_id().ok_or_else(|| {
|
||||
Error::Metadata(MetadataError::CallTypeNotFoundInPallet(md.pallet.index()))
|
||||
})?;
|
||||
pub fn as_root_extrinsic<E: DecodeAsType>(&self) -> Result<E, Error> {
|
||||
let decoded = E::decode_as_type(
|
||||
&mut &self.call_bytes()[..],
|
||||
self.metadata.outer_enums().call_enum_ty(),
|
||||
self.metadata.types(),
|
||||
)?;
|
||||
|
||||
// Ignore root enum index.
|
||||
E::root_extrinsic(
|
||||
&self.call_bytes()[1..],
|
||||
md.pallet.name(),
|
||||
pallet_extrinsic_ty,
|
||||
&self.metadata,
|
||||
)
|
||||
Ok(decoded)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,47 +456,11 @@ pub(crate) struct ExtrinsicPartTypeIds {
|
||||
impl ExtrinsicPartTypeIds {
|
||||
/// Extract the generic type parameters IDs from the extrinsic type.
|
||||
pub(crate) fn new(metadata: &Metadata) -> Result<Self, BlockError> {
|
||||
const ADDRESS: &str = "Address";
|
||||
const CALL: &str = "Call";
|
||||
const SIGNATURE: &str = "Signature";
|
||||
const EXTRA: &str = "Extra";
|
||||
|
||||
let id = metadata.extrinsic().ty();
|
||||
|
||||
let Some(ty) = metadata.types().resolve(id) else {
|
||||
return Err(BlockError::MissingType);
|
||||
};
|
||||
|
||||
let params: HashMap<_, _> = ty
|
||||
.type_params
|
||||
.iter()
|
||||
.map(|ty_param| {
|
||||
let Some(ty) = ty_param.ty else {
|
||||
return Err(BlockError::MissingType);
|
||||
};
|
||||
|
||||
Ok((ty_param.name.as_str(), ty.id))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let Some(address) = params.get(ADDRESS) else {
|
||||
return Err(BlockError::MissingType);
|
||||
};
|
||||
let Some(call) = params.get(CALL) else {
|
||||
return Err(BlockError::MissingType);
|
||||
};
|
||||
let Some(signature) = params.get(SIGNATURE) else {
|
||||
return Err(BlockError::MissingType);
|
||||
};
|
||||
let Some(extra) = params.get(EXTRA) else {
|
||||
return Err(BlockError::MissingType);
|
||||
};
|
||||
|
||||
Ok(ExtrinsicPartTypeIds {
|
||||
address: *address,
|
||||
_call: *call,
|
||||
signature: *signature,
|
||||
extra: *extra,
|
||||
address: metadata.extrinsic().address_ty(),
|
||||
_call: metadata.extrinsic().call_ty(),
|
||||
signature: metadata.extrinsic().signature_ty(),
|
||||
extra: metadata.extrinsic().extra_ty(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -620,10 +562,10 @@ impl<T: Config> ExtrinsicEvents<T> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::metadata::DecodeWithMetadata;
|
||||
use crate::{rpc::types::RuntimeVersion, OfflineClient, PolkadotConfig};
|
||||
use assert_matches::assert_matches;
|
||||
use codec::{Decode, Encode};
|
||||
use frame_metadata::v15::{CustomMetadata, OuterEnums};
|
||||
use frame_metadata::{
|
||||
v15::{ExtrinsicMetadata, PalletCallMetadata, PalletMetadata, RuntimeMetadataV15},
|
||||
RuntimeMetadataPrefixed,
|
||||
@@ -660,27 +602,6 @@ mod tests {
|
||||
Test(Pallet),
|
||||
}
|
||||
|
||||
// We need this in order to be able to decode into a root extrinsic type:
|
||||
impl RootExtrinsic for RuntimeCall {
|
||||
fn root_extrinsic(
|
||||
mut pallet_bytes: &[u8],
|
||||
pallet_name: &str,
|
||||
pallet_extrinsic_ty: u32,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Self, Error> {
|
||||
if pallet_name == "Test" {
|
||||
return Ok(RuntimeCall::Test(Pallet::decode_with_metadata(
|
||||
&mut pallet_bytes,
|
||||
pallet_extrinsic_ty,
|
||||
metadata,
|
||||
)?));
|
||||
}
|
||||
panic!(
|
||||
"Asked for pallet name '{pallet_name}', which isn't in our test RuntimeCall type"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// The calls of the pallet.
|
||||
#[allow(unused)]
|
||||
#[derive(
|
||||
@@ -743,12 +664,28 @@ mod tests {
|
||||
}];
|
||||
|
||||
let extrinsic = ExtrinsicMetadata {
|
||||
ty: meta_type::<ExtrinsicType<(), RuntimeCall, (), ()>>(),
|
||||
version: 4,
|
||||
signed_extensions: vec![],
|
||||
address_ty: meta_type::<()>(),
|
||||
call_ty: meta_type::<RuntimeCall>(),
|
||||
signature_ty: meta_type::<()>(),
|
||||
extra_ty: meta_type::<()>(),
|
||||
};
|
||||
|
||||
let meta = RuntimeMetadataV15::new(pallets, extrinsic, meta_type::<()>(), vec![]);
|
||||
let meta = RuntimeMetadataV15::new(
|
||||
pallets,
|
||||
extrinsic,
|
||||
meta_type::<()>(),
|
||||
vec![],
|
||||
OuterEnums {
|
||||
call_enum_ty: meta_type::<RuntimeCall>(),
|
||||
event_enum_ty: meta_type::<()>(),
|
||||
error_enum_ty: meta_type::<()>(),
|
||||
},
|
||||
CustomMetadata {
|
||||
map: Default::default(),
|
||||
},
|
||||
);
|
||||
let runtime_metadata: RuntimeMetadataPrefixed = meta.into();
|
||||
|
||||
Metadata::new(runtime_metadata.try_into().unwrap())
|
||||
|
||||
@@ -10,6 +10,4 @@ mod extrinsic_types;
|
||||
|
||||
pub use block_types::{Block, BlockBody};
|
||||
pub use blocks_client::{subscribe_to_block_headers_filling_in_gaps, BlocksClient};
|
||||
pub use extrinsic_types::{
|
||||
ExtrinsicDetails, ExtrinsicEvents, Extrinsics, RootExtrinsic, StaticExtrinsic,
|
||||
};
|
||||
pub use extrinsic_types::{ExtrinsicDetails, ExtrinsicEvents, Extrinsics, StaticExtrinsic};
|
||||
|
||||
@@ -129,16 +129,32 @@ impl<T: Config> OnlineClient<T> {
|
||||
async fn fetch_metadata(rpc: &Rpc<T>) -> Result<Metadata, Error> {
|
||||
#[cfg(feature = "unstable-metadata")]
|
||||
{
|
||||
/// The unstable metadata version number.
|
||||
const UNSTABLE_METADATA_VERSION: u32 = u32::MAX;
|
||||
|
||||
// Try to fetch the latest unstable metadata, if that fails fall back to
|
||||
// fetching the latest stable metadata.
|
||||
const V15_METADATA_VERSION: u32 = u32::MAX;
|
||||
match rpc.metadata_at_version(V15_METADATA_VERSION).await {
|
||||
match rpc.metadata_at_version(UNSTABLE_METADATA_VERSION).await {
|
||||
Ok(bytes) => Ok(bytes),
|
||||
Err(_) => rpc.metadata().await,
|
||||
Err(_) => OnlineClient::fetch_latest_stable_metadata(rpc).await,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unstable-metadata"))]
|
||||
OnlineClient::fetch_latest_stable_metadata(rpc).await
|
||||
}
|
||||
|
||||
/// Fetch the latest stable metadata from the node.
|
||||
async fn fetch_latest_stable_metadata(rpc: &Rpc<T>) -> Result<Metadata, Error> {
|
||||
// This is the latest stable metadata that subxt can utilize.
|
||||
const V15_METADATA_VERSION: u32 = 15;
|
||||
|
||||
// Try to fetch the metadata version.
|
||||
if let Ok(bytes) = rpc.metadata_at_version(V15_METADATA_VERSION).await {
|
||||
return Ok(bytes);
|
||||
}
|
||||
|
||||
// If that fails, fetch the metadata V14 using the old API.
|
||||
rpc.metadata().await
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
|
||||
use crate::metadata::{DecodeWithMetadata, Metadata};
|
||||
use core::fmt::Debug;
|
||||
use scale_decode::visitor::DecodeAsTypeResult;
|
||||
use scale_decode::{visitor::DecodeAsTypeResult, DecodeAsType};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::{Error, MetadataError};
|
||||
use crate::error::RootError;
|
||||
|
||||
/// An error dispatching a transaction.
|
||||
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
|
||||
@@ -127,13 +126,17 @@ pub enum TransactionalError {
|
||||
#[non_exhaustive]
|
||||
pub struct ModuleError {
|
||||
metadata: Metadata,
|
||||
raw: RawModuleError,
|
||||
/// Bytes representation:
|
||||
/// - `bytes[0]`: pallet index
|
||||
/// - `bytes[1]`: error index
|
||||
/// - `bytes[2..]`: 3 bytes specific for the module error
|
||||
bytes: [u8; 5],
|
||||
}
|
||||
|
||||
impl PartialEq for ModuleError {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// A module error is the same if the raw underlying details are the same.
|
||||
self.raw == other.raw
|
||||
self.bytes == other.bytes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,27 +157,38 @@ impl std::fmt::Display for ModuleError {
|
||||
impl ModuleError {
|
||||
/// Return more details about this error.
|
||||
pub fn details(&self) -> Result<ModuleErrorDetails, MetadataError> {
|
||||
let pallet = self.metadata.pallet_by_index_err(self.raw.pallet_index)?;
|
||||
let pallet = self.metadata.pallet_by_index_err(self.pallet_index())?;
|
||||
let variant = pallet
|
||||
.error_variant_by_index(self.raw.error[0])
|
||||
.ok_or_else(|| MetadataError::VariantIndexNotFound(self.raw.error[0]))?;
|
||||
.error_variant_by_index(self.error_index())
|
||||
.ok_or_else(|| MetadataError::VariantIndexNotFound(self.error_index()))?;
|
||||
|
||||
Ok(ModuleErrorDetails { pallet, variant })
|
||||
}
|
||||
|
||||
/// Return the underlying module error data that was decoded.
|
||||
pub fn raw(&self) -> RawModuleError {
|
||||
self.raw
|
||||
pub fn bytes(&self) -> [u8; 5] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
/// Attempts to decode the ModuleError into a value implementing the trait `RootError`
|
||||
/// where the actual type of value is the generated top level enum `Error`.
|
||||
pub fn as_root_error<E: RootError>(&self) -> Result<E, Error> {
|
||||
E::root_error(
|
||||
&self.raw.error,
|
||||
self.details()?.pallet.name(),
|
||||
&self.metadata,
|
||||
)
|
||||
/// Obtain the pallet index from the underlying byte data.
|
||||
pub fn pallet_index(&self) -> u8 {
|
||||
self.bytes[0]
|
||||
}
|
||||
|
||||
/// Obtain the error index from the underlying byte data.
|
||||
pub fn error_index(&self) -> u8 {
|
||||
self.bytes[1]
|
||||
}
|
||||
|
||||
/// Attempts to decode the ModuleError into the top outer Error enum.
|
||||
pub fn as_root_error<E: DecodeAsType>(&self) -> Result<E, Error> {
|
||||
let decoded = E::decode_as_type(
|
||||
&mut &self.bytes[..],
|
||||
self.metadata.outer_enums().error_enum_ty(),
|
||||
self.metadata.types(),
|
||||
)?;
|
||||
|
||||
Ok(decoded)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,25 +200,6 @@ pub struct ModuleErrorDetails<'a> {
|
||||
pub variant: &'a scale_info::Variant<scale_info::form::PortableForm>,
|
||||
}
|
||||
|
||||
/// The error details about a module error that has occurred.
|
||||
///
|
||||
/// **Note**: Structure used to obtain the underlying bytes of a ModuleError.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct RawModuleError {
|
||||
/// Index of the pallet that the error came from.
|
||||
pub pallet_index: u8,
|
||||
/// Raw error bytes.
|
||||
pub error: [u8; 4],
|
||||
}
|
||||
|
||||
impl RawModuleError {
|
||||
/// Obtain the error index from the underlying byte data.
|
||||
pub fn error_index(&self) -> u8 {
|
||||
// Error index is utilized as the first byte from the error array.
|
||||
self.error[0]
|
||||
}
|
||||
}
|
||||
|
||||
impl DispatchError {
|
||||
/// Attempt to decode a runtime [`DispatchError`].
|
||||
#[doc(hidden)]
|
||||
@@ -290,21 +285,16 @@ impl DispatchError {
|
||||
|
||||
// The old version is 2 bytes; a pallet and error index.
|
||||
// The new version is 5 bytes; a pallet and error index and then 3 extra bytes.
|
||||
let raw = if module_bytes.len() == 2 {
|
||||
RawModuleError {
|
||||
pallet_index: module_bytes[0],
|
||||
error: [module_bytes[1], 0, 0, 0],
|
||||
}
|
||||
let bytes = if module_bytes.len() == 2 {
|
||||
[module_bytes[0], module_bytes[1], 0, 0, 0]
|
||||
} else if module_bytes.len() == 5 {
|
||||
RawModuleError {
|
||||
pallet_index: module_bytes[0],
|
||||
error: [
|
||||
module_bytes[1],
|
||||
module_bytes[2],
|
||||
module_bytes[3],
|
||||
module_bytes[4],
|
||||
],
|
||||
}
|
||||
[
|
||||
module_bytes[0],
|
||||
module_bytes[1],
|
||||
module_bytes[2],
|
||||
module_bytes[3],
|
||||
module_bytes[4],
|
||||
]
|
||||
} else {
|
||||
tracing::warn!("Can't decode error sp_runtime::DispatchError: bytes do not match known shapes");
|
||||
// Return _all_ of the bytes; every "unknown" return should be consistent.
|
||||
@@ -312,7 +302,7 @@ impl DispatchError {
|
||||
};
|
||||
|
||||
// And return our outward-facing version:
|
||||
DispatchError::Module(ModuleError { metadata, raw })
|
||||
DispatchError::Module(ModuleError { metadata, bytes })
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+1
-13
@@ -13,7 +13,7 @@ pub use crate::client::LightClientError;
|
||||
|
||||
// Re-export dispatch error types:
|
||||
pub use dispatch_error::{
|
||||
ArithmeticError, DispatchError, ModuleError, RawModuleError, TokenError, TransactionalError,
|
||||
ArithmeticError, DispatchError, ModuleError, TokenError, TransactionalError,
|
||||
};
|
||||
|
||||
// Re-expose the errors we use from other crates here:
|
||||
@@ -225,15 +225,3 @@ pub enum MetadataError {
|
||||
#[error("The generated code is not compatible with the node")]
|
||||
IncompatibleCodegen,
|
||||
}
|
||||
|
||||
/// This trait is implemented on the statically generated root ModuleError type
|
||||
#[doc(hidden)]
|
||||
pub trait RootError: Sized {
|
||||
/// Given details of the pallet error we want to decode
|
||||
fn root_error(
|
||||
// typically a [u8; 4] encodes the error of a pallet
|
||||
pallet_bytes: &[u8],
|
||||
pallet_name: &str,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
};
|
||||
use codec::{Compact, Decode};
|
||||
use derivative::Derivative;
|
||||
use scale_decode::DecodeAsType;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A collection of events obtained from a block, bundled with the necessary
|
||||
@@ -386,20 +387,16 @@ impl<T: Config> EventDetails<T> {
|
||||
/// Attempt to decode these [`EventDetails`] into a root event type (which includes
|
||||
/// the pallet and event enum variants as well as the event fields). A compatible
|
||||
/// type for this is exposed via static codegen as a root level `Event` type.
|
||||
pub fn as_root_event<E: RootEvent>(&self) -> Result<E, Error> {
|
||||
let ev_metadata = self.event_metadata();
|
||||
let pallet_bytes = &self.all_bytes[self.event_start_idx + 1..self.event_fields_end_idx];
|
||||
let pallet_event_ty = ev_metadata
|
||||
.pallet
|
||||
.event_ty_id()
|
||||
.ok_or_else(|| MetadataError::EventTypeNotFoundInPallet(ev_metadata.pallet.index()))?;
|
||||
pub fn as_root_event<E: DecodeAsType>(&self) -> Result<E, Error> {
|
||||
let bytes = &self.all_bytes[self.event_start_idx..self.event_fields_end_idx];
|
||||
|
||||
E::root_event(
|
||||
pallet_bytes,
|
||||
self.pallet_name(),
|
||||
pallet_event_ty,
|
||||
&self.metadata,
|
||||
)
|
||||
let decoded = E::decode_as_type(
|
||||
&mut &bytes[..],
|
||||
self.metadata.outer_enums().event_enum_ty(),
|
||||
self.metadata.types(),
|
||||
)?;
|
||||
|
||||
Ok(decoded)
|
||||
}
|
||||
|
||||
/// Return the topics associated with this event.
|
||||
@@ -414,32 +411,17 @@ pub struct EventMetadataDetails<'a> {
|
||||
pub variant: &'a scale_info::Variant<scale_info::form::PortableForm>,
|
||||
}
|
||||
|
||||
/// This trait is implemented on the statically generated root event type, so that we're able
|
||||
/// to decode it properly via a pallet event that impls `DecodeAsMetadata`. This is necessary
|
||||
/// becasue the "root event" type is generated using pallet info but doesn't actually exist in the
|
||||
/// metadata types, so we have no easy way to decode things into it via type information and need a
|
||||
/// little help via codegen.
|
||||
#[doc(hidden)]
|
||||
pub trait RootEvent: Sized {
|
||||
/// Given details of the pallet event we want to decode, and the name of the pallet, try to hand
|
||||
/// back a "root event".
|
||||
fn root_event(
|
||||
pallet_bytes: &[u8],
|
||||
pallet_name: &str,
|
||||
pallet_event_ty: u32,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
/// Event related test utilities used outside this module.
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test_utils {
|
||||
use super::*;
|
||||
use crate::metadata::DecodeWithMetadata;
|
||||
use crate::{Config, SubstrateConfig};
|
||||
use codec::Encode;
|
||||
use frame_metadata::{
|
||||
v15::{ExtrinsicMetadata, PalletEventMetadata, PalletMetadata, RuntimeMetadataV15},
|
||||
v15::{
|
||||
CustomMetadata, ExtrinsicMetadata, OuterEnums, PalletEventMetadata, PalletMetadata,
|
||||
RuntimeMetadataV15,
|
||||
},
|
||||
RuntimeMetadataPrefixed,
|
||||
};
|
||||
use scale_info::{meta_type, TypeInfo};
|
||||
@@ -460,25 +442,6 @@ pub(crate) mod test_utils {
|
||||
Test(Ev),
|
||||
}
|
||||
|
||||
// We need this in order to be able to decode into a root event type:
|
||||
impl<Ev: DecodeWithMetadata> RootEvent for AllEvents<Ev> {
|
||||
fn root_event(
|
||||
mut bytes: &[u8],
|
||||
pallet_name: &str,
|
||||
pallet_event_ty: u32,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Self, Error> {
|
||||
if pallet_name == "Test" {
|
||||
return Ok(AllEvents::Test(Ev::decode_with_metadata(
|
||||
&mut bytes,
|
||||
pallet_event_ty,
|
||||
metadata,
|
||||
)?));
|
||||
}
|
||||
panic!("Asked for pallet name '{pallet_name}', which isn't in our test AllEvents type")
|
||||
}
|
||||
}
|
||||
|
||||
/// This encodes to the same format an event is expected to encode to
|
||||
/// in node System.Events storage.
|
||||
#[derive(Encode)]
|
||||
@@ -546,12 +509,28 @@ pub(crate) mod test_utils {
|
||||
}];
|
||||
|
||||
let extrinsic = ExtrinsicMetadata {
|
||||
ty: meta_type::<ExtrinsicType<RuntimeCall>>(),
|
||||
version: 0,
|
||||
signed_extensions: vec![],
|
||||
address_ty: meta_type::<()>(),
|
||||
call_ty: meta_type::<RuntimeCall>(),
|
||||
signature_ty: meta_type::<()>(),
|
||||
extra_ty: meta_type::<()>(),
|
||||
};
|
||||
|
||||
let meta = RuntimeMetadataV15::new(pallets, extrinsic, meta_type::<()>(), vec![]);
|
||||
let meta = RuntimeMetadataV15::new(
|
||||
pallets,
|
||||
extrinsic,
|
||||
meta_type::<()>(),
|
||||
vec![],
|
||||
OuterEnums {
|
||||
call_enum_ty: meta_type::<()>(),
|
||||
event_enum_ty: meta_type::<AllEvents<E>>(),
|
||||
error_enum_ty: meta_type::<()>(),
|
||||
},
|
||||
CustomMetadata {
|
||||
map: Default::default(),
|
||||
},
|
||||
);
|
||||
let runtime_metadata: RuntimeMetadataPrefixed = meta.into();
|
||||
|
||||
Metadata::new(runtime_metadata.try_into().unwrap())
|
||||
|
||||
@@ -11,12 +11,7 @@ mod events_type;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
pub use events_client::EventsClient;
|
||||
pub use events_type::{
|
||||
EventDetails,
|
||||
Events,
|
||||
// Used in codegen but hidden from docs:
|
||||
RootEvent,
|
||||
};
|
||||
pub use events_type::{EventDetails, Events};
|
||||
use scale_decode::DecodeAsFields;
|
||||
|
||||
/// Trait to uniquely identify the events's identity from the runtime metadata.
|
||||
|
||||
@@ -365,6 +365,15 @@ impl<T: Config> Rpc<T> {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Provide a list of the supported metadata versions of the node.
|
||||
pub async fn metadata_versions(&self) -> Result<Vec<u32>, Error> {
|
||||
let versions = self
|
||||
.state_call("Metadata_metadata_versions", None, None)
|
||||
.await?;
|
||||
|
||||
Ok(versions)
|
||||
}
|
||||
|
||||
/// Execute runtime API call and return the specified runtime metadata version.
|
||||
pub async fn metadata_at_version(&self, version: u32) -> Result<Metadata, Error> {
|
||||
let param = version.encode();
|
||||
|
||||
Reference in New Issue
Block a user