mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 18:41:05 +00:00
WIP splitting errors and tidying payload/address traits
This commit is contained in:
@@ -4,17 +4,16 @@
|
|||||||
|
|
||||||
//! Construct addresses to access constants with.
|
//! Construct addresses to access constants with.
|
||||||
|
|
||||||
use crate::dynamic::DecodedValueThunk;
|
|
||||||
use crate::metadata::DecodeWithMetadata;
|
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use derive_where::derive_where;
|
use derive_where::derive_where;
|
||||||
|
use scale_decode::DecodeAsType;
|
||||||
|
|
||||||
/// This represents a constant address. Anything implementing this trait
|
/// This represents a constant address. Anything implementing this trait
|
||||||
/// can be used to fetch constants.
|
/// can be used to fetch constants.
|
||||||
pub trait Address {
|
pub trait Address {
|
||||||
/// The target type of the value that lives at this address.
|
/// The target type of the value that lives at this address.
|
||||||
type Target: DecodeWithMetadata;
|
type Target: DecodeAsType;
|
||||||
|
|
||||||
/// The name of the pallet that the constant lives under.
|
/// The name of the pallet that the constant lives under.
|
||||||
fn pallet_name(&self) -> &str;
|
fn pallet_name(&self) -> &str;
|
||||||
@@ -32,20 +31,18 @@ pub trait Address {
|
|||||||
|
|
||||||
/// This represents the address of a constant.
|
/// This represents the address of a constant.
|
||||||
#[derive_where(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
#[derive_where(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
pub struct DefaultAddress<ReturnTy> {
|
pub struct StaticAddress<ReturnTy> {
|
||||||
pallet_name: Cow<'static, str>,
|
pallet_name: Cow<'static, str>,
|
||||||
constant_name: Cow<'static, str>,
|
constant_name: Cow<'static, str>,
|
||||||
constant_hash: Option<[u8; 32]>,
|
constant_hash: Option<[u8; 32]>,
|
||||||
_marker: core::marker::PhantomData<ReturnTy>,
|
_marker: core::marker::PhantomData<ReturnTy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of address used by our static codegen.
|
/// A dynamic lookup address to access a constant.
|
||||||
pub type StaticAddress<ReturnTy> = DefaultAddress<ReturnTy>;
|
pub type DynamicAddress<ReturnTy> = StaticAddress<ReturnTy>;
|
||||||
/// The type of address typically used to return dynamic constant values.
|
|
||||||
pub type DynamicAddress = DefaultAddress<DecodedValueThunk>;
|
|
||||||
|
|
||||||
impl<ReturnTy> DefaultAddress<ReturnTy> {
|
impl<ReturnTy> StaticAddress<ReturnTy> {
|
||||||
/// Create a new [`DefaultAddress`] to use to look up a constant.
|
/// Create a new [`StaticAddress`] to use to look up a constant.
|
||||||
pub fn new(pallet_name: impl Into<String>, constant_name: impl Into<String>) -> Self {
|
pub fn new(pallet_name: impl Into<String>, constant_name: impl Into<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pallet_name: Cow::Owned(pallet_name.into()),
|
pallet_name: Cow::Owned(pallet_name.into()),
|
||||||
@@ -55,7 +52,7 @@ impl<ReturnTy> DefaultAddress<ReturnTy> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`DefaultAddress`] that will be validated
|
/// Create a new [`StaticAddress`] that will be validated
|
||||||
/// against node metadata using the hash given.
|
/// against node metadata using the hash given.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn new_static(
|
pub fn new_static(
|
||||||
@@ -82,7 +79,7 @@ impl<ReturnTy> DefaultAddress<ReturnTy> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ReturnTy: DecodeWithMetadata> Address for DefaultAddress<ReturnTy> {
|
impl<ReturnTy: DecodeAsType> Address for StaticAddress<ReturnTy> {
|
||||||
type Target = ReturnTy;
|
type Target = ReturnTy;
|
||||||
|
|
||||||
fn pallet_name(&self) -> &str {
|
fn pallet_name(&self) -> &str {
|
||||||
@@ -99,6 +96,6 @@ impl<ReturnTy: DecodeWithMetadata> Address for DefaultAddress<ReturnTy> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a new dynamic constant lookup.
|
/// Construct a new dynamic constant lookup.
|
||||||
pub fn dynamic(pallet_name: impl Into<String>, constant_name: impl Into<String>) -> DynamicAddress {
|
pub fn dynamic<ReturnTy: DecodeAsType>(pallet_name: impl Into<String>, constant_name: impl Into<String>) -> DynamicAddress<ReturnTy> {
|
||||||
DynamicAddress::new(pallet_name, constant_name)
|
DynamicAddress::new(pallet_name, constant_name)
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-16
@@ -42,24 +42,31 @@ pub mod address;
|
|||||||
|
|
||||||
use address::Address;
|
use address::Address;
|
||||||
use alloc::borrow::ToOwned;
|
use alloc::borrow::ToOwned;
|
||||||
use crate::{Metadata, metadata::DecodeWithMetadata};
|
use crate::Metadata;
|
||||||
use crate::error::ConstantsError;
|
use crate::error::ConstantError;
|
||||||
|
use scale_decode::IntoVisitor;
|
||||||
|
|
||||||
/// When the provided `address` is statically generated via the `#[subxt]` macro, this validates
|
/// When the provided `address` is statically generated via the `#[subxt]` macro, this validates
|
||||||
/// that the shape of the constant value is the same as the shape expected by the static address.
|
/// that the shape of the constant value is the same as the shape expected by the static address.
|
||||||
///
|
///
|
||||||
/// When the provided `address` is dynamic (and thus does not come with any expectation of the
|
/// When the provided `address` is dynamic (and thus does not come with any expectation of the
|
||||||
/// shape of the constant value), this just returns `Ok(())`
|
/// shape of the constant value), this just returns `Ok(())`
|
||||||
pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<(), ConstantsError> {
|
pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<(), ConstantError> {
|
||||||
if let Some(actual_hash) = address.validation_hash() {
|
if let Some(actual_hash) = address.validation_hash() {
|
||||||
let expected_hash = metadata
|
let expected_hash = metadata
|
||||||
.pallet_by_name_err(address.pallet_name())?
|
.pallet_by_name(address.pallet_name())
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ConstantError::PalletNameNotFound(address.pallet_name().to_string())
|
||||||
|
})?
|
||||||
.constant_hash(address.constant_name())
|
.constant_hash(address.constant_name())
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
ConstantsError::ConstantNameNotFound(address.constant_name().to_owned())
|
ConstantError::ConstantNameNotFound {
|
||||||
|
pallet_name: address.pallet_name().to_string(),
|
||||||
|
constant_name: address.constant_name().to_owned()
|
||||||
|
}
|
||||||
})?;
|
})?;
|
||||||
if actual_hash != expected_hash {
|
if actual_hash != expected_hash {
|
||||||
return Err(ConstantsError::IncompatibleCodegen);
|
return Err(ConstantError::IncompatibleCodegen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -67,19 +74,18 @@ pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<()
|
|||||||
|
|
||||||
/// Fetch a constant out of the metadata given a constant address. If the `address` has been
|
/// Fetch a constant out of the metadata given a constant address. If the `address` has been
|
||||||
/// statically generated, this will validate that the constant shape is as expected, too.
|
/// statically generated, this will validate that the constant shape is as expected, too.
|
||||||
pub fn get<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<Addr::Target, ConstantsError> {
|
pub fn get<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<Addr::Target, ConstantError> {
|
||||||
// 1. Validate constant shape if hash given:
|
// 1. Validate constant shape if hash given:
|
||||||
validate(address, metadata)?;
|
validate(address, metadata)?;
|
||||||
|
|
||||||
// 2. Attempt to decode the constant into the type given:
|
// 2. Attempt to decode the constant into the type given:
|
||||||
let constant = metadata
|
let constant = frame_decode::constants::decode_constant(
|
||||||
.pallet_by_name_err(address.pallet_name())?
|
address.pallet_name(),
|
||||||
.constant_by_name(address.constant_name())
|
address.constant_name(),
|
||||||
.ok_or_else(|| ConstantsError::ConstantNameNotFound(address.constant_name().to_owned()))?;
|
|
||||||
let value = <Addr::Target as DecodeWithMetadata>::decode_with_metadata(
|
|
||||||
&mut constant.value(),
|
|
||||||
constant.ty(),
|
|
||||||
metadata,
|
metadata,
|
||||||
)?;
|
metadata.types(),
|
||||||
Ok(value)
|
Addr::Target::into_visitor()
|
||||||
|
).map_err(ConstantError::CouldNotDecodeConstant)?;
|
||||||
|
|
||||||
|
Ok(constant)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,22 @@
|
|||||||
|
|
||||||
//! Construct addresses to access custom values with.
|
//! Construct addresses to access custom values with.
|
||||||
|
|
||||||
use crate::dynamic::DecodedValueThunk;
|
|
||||||
use crate::metadata::DecodeWithMetadata;
|
|
||||||
use derive_where::derive_where;
|
use derive_where::derive_where;
|
||||||
use crate::utils::YesNo;
|
use scale_decode::DecodeAsType;
|
||||||
|
use alloc::borrow::Cow;
|
||||||
|
|
||||||
/// Use this with [`Address::IsDecodable`].
|
/// Use this with [`Address::IsDecodable`].
|
||||||
pub use crate::utils::{Yes, No};
|
pub use crate::utils::{No, Maybe, NoMaybe};
|
||||||
|
|
||||||
/// This represents the address of a custom value in the metadata.
|
/// This represents the address of a custom value in the metadata.
|
||||||
/// Anything that implements it can be used to fetch custom values from the metadata.
|
/// Anything that implements it can be used to fetch custom values from the metadata.
|
||||||
/// The trait is implemented by [`str`] for dynamic lookup and [`StaticAddress`] for static queries.
|
/// The trait is implemented by [`str`] for dynamic lookup and [`StaticAddress`] for static queries.
|
||||||
pub trait Address {
|
pub trait Address {
|
||||||
/// The type of the custom value.
|
/// The type of the custom value.
|
||||||
type Target: DecodeWithMetadata;
|
type Target: DecodeAsType;
|
||||||
/// Should be set to `Yes` for Dynamic values and static values that have a valid type.
|
/// Should be set to `Yes` for Dynamic values and static values that have a valid type.
|
||||||
/// Should be `No` for custom values, that have an invalid type id.
|
/// Should be `No` for custom values, that have an invalid type id.
|
||||||
type IsDecodable: YesNo;
|
type IsDecodable: NoMaybe;
|
||||||
|
|
||||||
/// the name (key) by which the custom value can be accessed in the metadata.
|
/// the name (key) by which the custom value can be accessed in the metadata.
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &str;
|
||||||
@@ -31,31 +30,34 @@ pub trait Address {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Address for str {
|
|
||||||
type Target = DecodedValueThunk;
|
|
||||||
type IsDecodable = Yes;
|
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A static address to a custom value.
|
/// A static address to a custom value.
|
||||||
#[derive_where(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
#[derive_where(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
pub struct StaticAddress<ReturnTy, IsDecodable> {
|
pub struct StaticAddress<ReturnTy, IsDecodable> {
|
||||||
name: &'static str,
|
name: Cow<'static, str>,
|
||||||
hash: Option<[u8; 32]>,
|
hash: Option<[u8; 32]>,
|
||||||
phantom: core::marker::PhantomData<(ReturnTy, IsDecodable)>,
|
marker: core::marker::PhantomData<(ReturnTy, IsDecodable)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A dynamic address to a custom value.
|
||||||
|
pub type DynamicAddress<ReturnTy> = StaticAddress<ReturnTy, Maybe>;
|
||||||
|
|
||||||
impl<ReturnTy, IsDecodable> StaticAddress<ReturnTy, IsDecodable> {
|
impl<ReturnTy, IsDecodable> StaticAddress<ReturnTy, IsDecodable> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// Creates a new StaticAddress.
|
/// Creates a new StaticAddress.
|
||||||
pub fn new_static(name: &'static str, hash: [u8; 32]) -> StaticAddress<ReturnTy, IsDecodable> {
|
pub fn new_static(name: &'static str, hash: [u8; 32]) -> Self {
|
||||||
StaticAddress::<ReturnTy, IsDecodable> {
|
Self {
|
||||||
name,
|
name: Cow::Borrowed(name),
|
||||||
hash: Some(hash),
|
hash: Some(hash),
|
||||||
phantom: core::marker::PhantomData,
|
marker: core::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new [`StaticAddress`]
|
||||||
|
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
hash: None,
|
||||||
|
marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,20 +66,35 @@ impl<ReturnTy, IsDecodable> StaticAddress<ReturnTy, IsDecodable> {
|
|||||||
Self {
|
Self {
|
||||||
name: self.name,
|
name: self.name,
|
||||||
hash: None,
|
hash: None,
|
||||||
phantom: self.phantom,
|
marker: self.marker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Target: DecodeWithMetadata, IsDecodable: YesNo> Address for StaticAddress<Target, IsDecodable> {
|
impl<Target: DecodeAsType, IsDecodable: NoMaybe> Address for StaticAddress<Target, IsDecodable> {
|
||||||
type Target = Target;
|
type Target = Target;
|
||||||
type IsDecodable = IsDecodable;
|
type IsDecodable = IsDecodable;
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validation_hash(&self) -> Option<[u8; 32]> {
|
fn validation_hash(&self) -> Option<[u8; 32]> {
|
||||||
self.hash
|
self.hash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Support plain strings for looking up custom values (but prefer `dynamic` if you want to pick the return type)
|
||||||
|
impl Address for &str {
|
||||||
|
type Target = scale_value::Value;
|
||||||
|
type IsDecodable = Maybe;
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a new dynamic custom value lookup.
|
||||||
|
pub fn dynamic<ReturnTy: DecodeAsType>(custom_value_name: impl Into<Cow<'static, str>>) -> DynamicAddress<ReturnTy> {
|
||||||
|
DynamicAddress::new(custom_value_name)
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,27 +33,25 @@
|
|||||||
pub mod address;
|
pub mod address;
|
||||||
|
|
||||||
use crate::utils::Yes;
|
use crate::utils::Yes;
|
||||||
use crate::{Error, Metadata, error::MetadataError, metadata::DecodeWithMetadata};
|
use crate::{Metadata, error::CustomValueError};
|
||||||
use address::Address;
|
use address::Address;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use frame_decode::custom_values::CustomValueTypeInfo;
|
||||||
|
|
||||||
/// Run the validation logic against some custom value address you'd like to access. Returns `Ok(())`
|
/// Run the validation logic against some custom value address you'd like to access. Returns `Ok(())`
|
||||||
/// if the address is valid (or if it's not possible to check since the address has no validation hash).
|
/// if the address is valid (or if it's not possible to check since the address has no validation hash).
|
||||||
/// Returns an error if the address was not valid (wrong name, type or raw bytes)
|
/// Returns an error if the address was not valid (wrong name, type or raw bytes)
|
||||||
pub fn validate<Addr: Address + ?Sized>(address: &Addr, metadata: &Metadata) -> Result<(), Error> {
|
pub fn validate<Addr: Address + ?Sized>(address: &Addr, metadata: &Metadata) -> Result<(), CustomValueError> {
|
||||||
if let Some(actual_hash) = address.validation_hash() {
|
if let Some(actual_hash) = address.validation_hash() {
|
||||||
let custom = metadata.custom();
|
let custom = metadata.custom();
|
||||||
let custom_value = custom
|
let custom_value = custom
|
||||||
.get(address.name())
|
.get(address.name())
|
||||||
.ok_or_else(|| MetadataError::CustomValueNameNotFound(address.name().into()))?;
|
.ok_or_else(|| CustomValueError::NotFound(address.name().into()))?;
|
||||||
let expected_hash = custom_value.hash();
|
let expected_hash = custom_value.hash();
|
||||||
if actual_hash != expected_hash {
|
if actual_hash != expected_hash {
|
||||||
return Err(MetadataError::IncompatibleCodegen.into());
|
return Err(CustomValueError::IncompatibleCodegen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if metadata.custom().get(address.name()).is_none() {
|
|
||||||
return Err(MetadataError::IncompatibleCodegen.into());
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,17 +60,18 @@ pub fn validate<Addr: Address + ?Sized>(address: &Addr, metadata: &Metadata) ->
|
|||||||
pub fn get<Addr: Address<IsDecodable = Yes> + ?Sized>(
|
pub fn get<Addr: Address<IsDecodable = Yes> + ?Sized>(
|
||||||
address: &Addr,
|
address: &Addr,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
) -> Result<Addr::Target, Error> {
|
) -> Result<Addr::Target, CustomValueError> {
|
||||||
// 1. Validate custom value shape if hash given:
|
// 1. Validate custom value shape if hash given:
|
||||||
validate(address, metadata)?;
|
validate(address, metadata)?;
|
||||||
|
|
||||||
// 2. Attempt to decode custom value:
|
// 2. Attempt to decode custom value:
|
||||||
let custom_value = metadata.custom_value_by_name_err(address.name())?;
|
let value = frame_decode::custom_values::decode_custom_value(
|
||||||
let value = <Addr::Target as DecodeWithMetadata>::decode_with_metadata(
|
address.name(),
|
||||||
&mut custom_value.bytes(),
|
|
||||||
custom_value.type_id(),
|
|
||||||
metadata,
|
metadata,
|
||||||
)?;
|
metadata.types(),
|
||||||
|
Addr::Target::into_visitor()
|
||||||
|
).map_err(CustomValueError::CouldNotDecodeCustomValue)?;
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,13 +79,14 @@ pub fn get<Addr: Address<IsDecodable = Yes> + ?Sized>(
|
|||||||
pub fn get_bytes<Addr: Address + ?Sized>(
|
pub fn get_bytes<Addr: Address + ?Sized>(
|
||||||
address: &Addr,
|
address: &Addr,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, CustomValueError> {
|
||||||
// 1. Validate custom value shape if hash given:
|
// 1. Validate custom value shape if hash given:
|
||||||
validate(address, metadata)?;
|
validate(address, metadata)?;
|
||||||
|
|
||||||
// 2. Return the underlying bytes:
|
// 2. Return the underlying bytes:
|
||||||
let custom_value = metadata.custom_value_by_name_err(address.name())?;
|
let custom_value = metadata.custom_value_info(address.name())
|
||||||
Ok(custom_value.bytes().to_vec())
|
.map_err(|e| CustomValueError::NotFound(e.not_found))?;
|
||||||
|
Ok(custom_value.bytes.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
+47
-9
@@ -28,7 +28,9 @@ pub enum Error {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Extrinsic(#[from] ExtrinsicError),
|
Extrinsic(#[from] ExtrinsicError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Constants(#[from] ConstantsError),
|
Constant(#[from] ConstantError),
|
||||||
|
#[error(transparent)]
|
||||||
|
CustomValueError(CustomValueError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl From<scale_decode::visitor::DecodeError> for Error {
|
// impl From<scale_decode::visitor::DecodeError> for Error {
|
||||||
@@ -91,15 +93,46 @@ pub enum MetadataError {
|
|||||||
CustomValueNameNotFound(String),
|
CustomValueNameNotFound(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DeriveError)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum RuntimeApiError {
|
||||||
|
#[error("The static Runtime API address used is not compatible with the live chain")]
|
||||||
|
IncompatibleCodegen,
|
||||||
|
#[error("Failed to encode Runtime API inputs: {0}")]
|
||||||
|
CouldNotEncodeInputs(frame_decode::runtime_apis::RuntimeApiInputsEncodeError),
|
||||||
|
#[error("Failed to decode Runtime API: {0}")]
|
||||||
|
CouldNotDecodeResponse(frame_decode::runtime_apis::RuntimeApiDecodeError<u32>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DeriveError)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum CustomValueError {
|
||||||
|
#[error("The static custom value address used is not compatible with the live chain")]
|
||||||
|
IncompatibleCodegen,
|
||||||
|
#[error("The custom value '{0}' was not found")]
|
||||||
|
NotFound(String),
|
||||||
|
#[error("Failed to decode custom value: {0}")]
|
||||||
|
CouldNotDecodeCustomValue(frame_decode::custom_values::CustomValueDecodeError<u32>),
|
||||||
|
}
|
||||||
|
|
||||||
/// Something went wrong working with a constant.
|
/// Something went wrong working with a constant.
|
||||||
#[derive(Debug, DeriveError)]
|
#[derive(Debug, DeriveError)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum ConstantsError {
|
pub enum ConstantError {
|
||||||
#[error("The static constant address used is not compatible with the live chain")]
|
#[error("The static constant address used is not compatible with the live chain")]
|
||||||
IncompatibleCodegen,
|
IncompatibleCodegen,
|
||||||
#[error("Constant with name {0} not found in the live chain metadata")]
|
#[error("Can't find constant: pallet with name {0} not found")]
|
||||||
ConstantNameNotFound(String),
|
PalletNameNotFound(String),
|
||||||
|
#[error("Constant '{constant_name}' not found in pallet {pallet_name} in the live chain metadata")]
|
||||||
|
ConstantNameNotFound {
|
||||||
|
pallet_name: String,
|
||||||
|
constant_name: String
|
||||||
|
},
|
||||||
|
#[error("Failed to decode constant: {0}")]
|
||||||
|
CouldNotDecodeConstant(frame_decode::constants::ConstantDecodeError<u32>)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Something went wrong trying to encode or decode a storage address.
|
/// Something went wrong trying to encode or decode a storage address.
|
||||||
@@ -107,6 +140,15 @@ pub enum ConstantsError {
|
|||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum StorageError {
|
pub enum StorageError {
|
||||||
|
#[error("The static storage address used is not compatible with the live chain")]
|
||||||
|
IncompatibleCodegen,
|
||||||
|
#[error("Can't find storage value: pallet with name {0} not found")]
|
||||||
|
PalletNameNotFound(String),
|
||||||
|
#[error("Storage entry '{entry_name}' not found in pallet {pallet_name} in the live chain metadata")]
|
||||||
|
StorageEntryNotFound {
|
||||||
|
pallet_name: String,
|
||||||
|
entry_name: String
|
||||||
|
},
|
||||||
#[error("Cannot obtain storage information from metadata: {0}")]
|
#[error("Cannot obtain storage information from metadata: {0}")]
|
||||||
StorageInfoError(frame_decode::storage::StorageInfoError<'static>),
|
StorageInfoError(frame_decode::storage::StorageInfoError<'static>),
|
||||||
#[error("Cannot decode storage value: {0}")]
|
#[error("Cannot decode storage value: {0}")]
|
||||||
@@ -145,7 +187,7 @@ pub enum ExtrinsicError {
|
|||||||
/// Index of the extrinsic that failed to decode.
|
/// Index of the extrinsic that failed to decode.
|
||||||
extrinsic_index: usize,
|
extrinsic_index: usize,
|
||||||
/// The decode error.
|
/// The decode error.
|
||||||
error: ExtrinsicDecodeError,
|
error: frame_decode::extrinsics::ExtrinsicDecodeError,
|
||||||
},
|
},
|
||||||
#[error("Failed to decode the fields of an extrinsic at index {extrinsic_index}: {error}")]
|
#[error("Failed to decode the fields of an extrinsic at index {extrinsic_index}: {error}")]
|
||||||
CannotDecodeFields {
|
CannotDecodeFields {
|
||||||
@@ -163,10 +205,6 @@ pub enum ExtrinsicError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An alias for [`frame_decode::extrinsics::ExtrinsicDecodeError`].
|
|
||||||
///
|
|
||||||
pub type ExtrinsicDecodeError = frame_decode::extrinsics::ExtrinsicDecodeError;
|
|
||||||
|
|
||||||
/// An error that can be emitted when trying to construct an instance of [`crate::config::ExtrinsicParams`],
|
/// An error that can be emitted when trying to construct an instance of [`crate::config::ExtrinsicParams`],
|
||||||
/// encode data from the instance, or match on signed extensions.
|
/// encode data from the instance, or match on signed extensions.
|
||||||
#[derive(Debug, DeriveError)]
|
#[derive(Debug, DeriveError)]
|
||||||
|
|||||||
+4
-1
@@ -31,7 +31,6 @@ pub mod custom_values;
|
|||||||
pub mod dynamic;
|
pub mod dynamic;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod metadata;
|
|
||||||
pub mod runtime_api;
|
pub mod runtime_api;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
pub mod tx;
|
pub mod tx;
|
||||||
@@ -49,3 +48,7 @@ pub mod ext {
|
|||||||
pub use scale_encode;
|
pub use scale_encode;
|
||||||
pub use scale_value;
|
pub use scale_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod metadata {
|
||||||
|
pub use subxt_metadata::Metadata;
|
||||||
|
}
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
|
||||||
// see LICENSE for license details.
|
|
||||||
|
|
||||||
use super::Metadata;
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
/// This trait is implemented for all types that also implement [`scale_decode::DecodeAsType`].
|
|
||||||
pub trait DecodeWithMetadata: Sized {
|
|
||||||
/// Given some metadata and a type ID, attempt to SCALE decode the provided bytes into `Self`.
|
|
||||||
fn decode_with_metadata(
|
|
||||||
bytes: &mut &[u8],
|
|
||||||
type_id: u32,
|
|
||||||
metadata: &Metadata,
|
|
||||||
) -> Result<Self, scale_decode::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: scale_decode::DecodeAsType> DecodeWithMetadata for T {
|
|
||||||
fn decode_with_metadata(
|
|
||||||
bytes: &mut &[u8],
|
|
||||||
type_id: u32,
|
|
||||||
metadata: &Metadata,
|
|
||||||
) -> Result<T, scale_decode::Error> {
|
|
||||||
let val = T::decode_as_type(bytes, type_id, metadata.types())?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This trait is implemented for all types that also implement [`scale_encode::EncodeAsType`].
|
|
||||||
pub trait EncodeWithMetadata {
|
|
||||||
/// SCALE encode this type to bytes, possibly with the help of metadata.
|
|
||||||
fn encode_with_metadata(
|
|
||||||
&self,
|
|
||||||
type_id: u32,
|
|
||||||
metadata: &Metadata,
|
|
||||||
bytes: &mut Vec<u8>,
|
|
||||||
) -> Result<(), scale_encode::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: scale_encode::EncodeAsType> EncodeWithMetadata for T {
|
|
||||||
/// SCALE encode this type to bytes, possibly with the help of metadata.
|
|
||||||
fn encode_with_metadata(
|
|
||||||
&self,
|
|
||||||
type_id: u32,
|
|
||||||
metadata: &Metadata,
|
|
||||||
bytes: &mut Vec<u8>,
|
|
||||||
) -> Result<(), scale_encode::Error> {
|
|
||||||
self.encode_as_type_to(type_id, metadata.types(), bytes)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
|
||||||
// see LICENSE for license details.
|
|
||||||
|
|
||||||
use crate::error::MetadataError;
|
|
||||||
|
|
||||||
use alloc::borrow::ToOwned;
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
use frame_decode::extrinsics::{
|
|
||||||
ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoError,
|
|
||||||
ExtrinsicSignatureInfo,
|
|
||||||
};
|
|
||||||
use frame_decode::storage::{
|
|
||||||
StorageEntry, StorageInfo, StorageInfoError
|
|
||||||
};
|
|
||||||
use frame_decode::runtime_apis::{
|
|
||||||
RuntimeApi, RuntimeApiInfo, RuntimeApiInfoError
|
|
||||||
};
|
|
||||||
use frame_decode::view_functions::{
|
|
||||||
ViewFunction, ViewFunctionInfo, ViewFunctionInfoError
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A cheaply clone-able representation of the runtime metadata received from a node.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Metadata {
|
|
||||||
inner: Arc<subxt_metadata::Metadata>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::ops::Deref for Metadata {
|
|
||||||
type Target = subxt_metadata::Metadata;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl frame_decode::storage::StorageTypeInfo for Metadata {
|
|
||||||
type TypeId = u32;
|
|
||||||
|
|
||||||
fn storage_info(
|
|
||||||
&self,
|
|
||||||
pallet_name: &str,
|
|
||||||
storage_entry: &str,
|
|
||||||
) -> Result<StorageInfo<'_, Self::TypeId>, StorageInfoError<'_>> {
|
|
||||||
self.inner.storage_info(pallet_name, storage_entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn storage_entries(&self) -> impl Iterator<Item = StorageEntry<'_>> {
|
|
||||||
self.inner.storage_entries()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl frame_decode::runtime_apis::RuntimeApiTypeInfo for Metadata {
|
|
||||||
type TypeId = u32;
|
|
||||||
|
|
||||||
fn runtime_api_info(
|
|
||||||
&self,
|
|
||||||
trait_name: &str,
|
|
||||||
method_name: &str,
|
|
||||||
) -> Result<RuntimeApiInfo<'_, Self::TypeId>, RuntimeApiInfoError<'_>> {
|
|
||||||
self.inner.runtime_api_info(trait_name, method_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn runtime_apis(&self) -> impl Iterator<Item = RuntimeApi<'_>> {
|
|
||||||
self.inner.runtime_apis()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
|
|
||||||
type TypeId = u32;
|
|
||||||
|
|
||||||
fn extrinsic_call_info(
|
|
||||||
&self,
|
|
||||||
pallet_index: u8,
|
|
||||||
call_index: u8,
|
|
||||||
) -> Result<ExtrinsicCallInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
|
|
||||||
self.inner.extrinsic_call_info(pallet_index, call_index)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extrinsic_signature_info(
|
|
||||||
&self,
|
|
||||||
) -> Result<ExtrinsicSignatureInfo<Self::TypeId>, ExtrinsicInfoError<'_>> {
|
|
||||||
self.inner.extrinsic_signature_info()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extrinsic_extension_info(
|
|
||||||
&self,
|
|
||||||
extension_version: Option<u8>,
|
|
||||||
) -> Result<ExtrinsicExtensionInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
|
|
||||||
self.inner.extrinsic_extension_info(extension_version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl frame_decode::view_functions::ViewFunctionTypeInfo for Metadata {
|
|
||||||
type TypeId = u32;
|
|
||||||
|
|
||||||
fn view_function_info(
|
|
||||||
&self,
|
|
||||||
pallet_name: &str,
|
|
||||||
function_name: &str,
|
|
||||||
) -> Result<ViewFunctionInfo<'_, Self::TypeId>, ViewFunctionInfoError<'_>> {
|
|
||||||
self.inner.view_function_info(pallet_name, function_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view_functions(&self) -> impl Iterator<Item = ViewFunction<'_>> {
|
|
||||||
self.inner.view_functions()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Metadata {
|
|
||||||
/// Identical to `metadata.pallet_by_name()`, but returns an error if the pallet is not found.
|
|
||||||
pub fn pallet_by_name_err(
|
|
||||||
&self,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<subxt_metadata::PalletMetadata<'_>, MetadataError> {
|
|
||||||
self.pallet_by_name(name)
|
|
||||||
.ok_or_else(|| MetadataError::PalletNameNotFound(name.to_owned()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identical to `metadata.pallet_by_index()`, but returns an error if the pallet is not found.
|
|
||||||
pub fn pallet_by_index_err(
|
|
||||||
&self,
|
|
||||||
index: u8,
|
|
||||||
) -> Result<subxt_metadata::PalletMetadata<'_>, MetadataError> {
|
|
||||||
self.pallet_by_index(index)
|
|
||||||
.ok_or(MetadataError::PalletIndexNotFound(index))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identical to `metadata.runtime_api_trait_by_name()`, but returns an error if the trait is not found.
|
|
||||||
pub fn runtime_api_trait_by_name_err(
|
|
||||||
&self,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<subxt_metadata::RuntimeApiMetadata<'_>, MetadataError> {
|
|
||||||
self.runtime_api_trait_by_name(name)
|
|
||||||
.ok_or_else(|| MetadataError::RuntimeTraitNotFound(name.to_owned()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identical to `metadata.custom().get(name)`, but returns an error if the trait is not found.
|
|
||||||
pub fn custom_value_by_name_err(
|
|
||||||
&self,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<subxt_metadata::CustomValueMetadata<'_>, MetadataError> {
|
|
||||||
self.custom()
|
|
||||||
.get(name)
|
|
||||||
.ok_or_else(|| MetadataError::CustomValueNameNotFound(name.to_owned()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<subxt_metadata::Metadata> for Metadata {
|
|
||||||
fn from(md: subxt_metadata::Metadata) -> Self {
|
|
||||||
Metadata {
|
|
||||||
inner: Arc::new(md),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<frame_metadata::RuntimeMetadataPrefixed> for Metadata {
|
|
||||||
type Error = subxt_metadata::TryFromError;
|
|
||||||
fn try_from(value: frame_metadata::RuntimeMetadataPrefixed) -> Result<Self, Self::Error> {
|
|
||||||
subxt_metadata::Metadata::try_from(value).map(Metadata::from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl codec::Decode for Metadata {
|
|
||||||
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
|
|
||||||
subxt_metadata::Metadata::decode(input).map(Metadata::from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
|
||||||
// see LICENSE for license details.
|
|
||||||
|
|
||||||
//! A [`Metadata`] type, which is used through this crate.
|
|
||||||
//!
|
|
||||||
//! This can be decoded from the bytes handed back from a node when asking for metadata.
|
|
||||||
//!
|
|
||||||
//! # Examples
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! use subxt_core::metadata;
|
|
||||||
//!
|
|
||||||
//! // We need to fetch the bytes from somewhere, and then we can decode them:
|
|
||||||
//! let metadata_bytes = include_bytes!("../../../artifacts/polkadot_metadata_small.scale");
|
|
||||||
//! let metadata = metadata::decode_from(&metadata_bytes[..]).unwrap();
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
mod decode_encode_traits;
|
|
||||||
mod metadata_type;
|
|
||||||
|
|
||||||
use codec::Decode;
|
|
||||||
|
|
||||||
pub use decode_encode_traits::{DecodeWithMetadata, EncodeWithMetadata};
|
|
||||||
pub use metadata_type::Metadata;
|
|
||||||
|
|
||||||
/// Attempt to decode some bytes into [`Metadata`], returning an error
|
|
||||||
/// if decoding fails.
|
|
||||||
///
|
|
||||||
/// This is a shortcut for importing [`codec::Decode`] and using the
|
|
||||||
/// implementation of that on [`Metadata`].
|
|
||||||
pub fn decode_from(bytes: &[u8]) -> Result<Metadata, codec::Error> {
|
|
||||||
Metadata::decode(&mut &*bytes)
|
|
||||||
}
|
|
||||||
+22
-17
@@ -43,9 +43,8 @@
|
|||||||
|
|
||||||
pub mod payload;
|
pub mod payload;
|
||||||
|
|
||||||
use crate::error::{Error, MetadataError};
|
use crate::error::{RuntimeApiError, MetadataError};
|
||||||
use crate::metadata::{DecodeWithMetadata, Metadata};
|
use crate::metadata::Metadata;
|
||||||
use alloc::borrow::ToOwned;
|
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
@@ -55,7 +54,7 @@ use payload::Payload;
|
|||||||
/// if the payload is valid (or if it's not possible to check since the payload has no validation hash).
|
/// if the payload is valid (or if it's not possible to check since the payload has no validation hash).
|
||||||
/// Return an error if the payload was not valid or something went wrong trying to validate it (ie
|
/// Return an error if the payload was not valid or something went wrong trying to validate it (ie
|
||||||
/// the runtime API in question do not exist at all)
|
/// the runtime API in question do not exist at all)
|
||||||
pub fn validate<P: Payload>(payload: &P, metadata: &Metadata) -> Result<(), Error> {
|
pub fn validate<P: Payload>(payload: &P, metadata: &Metadata) -> Result<(), RuntimeApiError> {
|
||||||
let Some(static_hash) = payload.validation_hash() else {
|
let Some(static_hash) = payload.validation_hash() else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
@@ -78,8 +77,16 @@ pub fn call_name<P: Payload>(payload: &P) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the encoded call args given a runtime API payload.
|
/// Return the encoded call args given a runtime API payload.
|
||||||
pub fn call_args<P: Payload>(payload: &P, metadata: &Metadata) -> Result<Vec<u8>, Error> {
|
pub fn call_args<P: Payload>(payload: &P, metadata: &Metadata) -> Result<Vec<u8>, RuntimeApiError> {
|
||||||
payload.encode_args(metadata)
|
let value = frame_decode::runtime_apis::encode_runtime_api_inputs(
|
||||||
|
payload.trait_name(),
|
||||||
|
payload.method_name(),
|
||||||
|
payload.args(),
|
||||||
|
metadata,
|
||||||
|
metadata.types()
|
||||||
|
).map_err(RuntimeApiError::CouldNotEncodeInputs)?;
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decode the value bytes at the location given by the provided runtime API payload.
|
/// Decode the value bytes at the location given by the provided runtime API payload.
|
||||||
@@ -87,17 +94,15 @@ pub fn decode_value<P: Payload>(
|
|||||||
bytes: &mut &[u8],
|
bytes: &mut &[u8],
|
||||||
payload: &P,
|
payload: &P,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
) -> Result<P::ReturnType, Error> {
|
) -> Result<P::ReturnType, RuntimeApiError> {
|
||||||
let api_method = metadata
|
let value = frame_decode::runtime_apis::decode_runtime_api_response(
|
||||||
.runtime_api_trait_by_name_err(payload.trait_name())?
|
payload.trait_name(),
|
||||||
.method_by_name(payload.method_name())
|
payload.method_name(),
|
||||||
.ok_or_else(|| MetadataError::RuntimeMethodNotFound(payload.method_name().to_owned()))?;
|
bytes,
|
||||||
|
|
||||||
let val = <P::ReturnType as DecodeWithMetadata>::decode_with_metadata(
|
|
||||||
&mut &bytes[..],
|
|
||||||
api_method.output_ty(),
|
|
||||||
metadata,
|
metadata,
|
||||||
)?;
|
metadata.types(),
|
||||||
|
P::ReturnType::into_visitor()
|
||||||
|
).map_err(RuntimeApiError::CouldNotDecodeResponse)?;
|
||||||
|
|
||||||
Ok(val)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,45 +6,18 @@
|
|||||||
//! runtime API calls that can be made.
|
//! runtime API calls that can be made.
|
||||||
|
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
use alloc::borrow::ToOwned;
|
|
||||||
use alloc::string::String;
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use derive_where::derive_where;
|
use derive_where::derive_where;
|
||||||
use scale_encode::EncodeAsFields;
|
use scale_decode::DecodeAsType;
|
||||||
use scale_value::Composite;
|
use frame_decode::runtime_apis::IntoEncodableValues;
|
||||||
|
|
||||||
use crate::Error;
|
/// This represents a runtime API payload that can be used to call a Runtime API on
|
||||||
use crate::dynamic::DecodedValueThunk;
|
/// a chain and decode the response.
|
||||||
use crate::error::MetadataError;
|
|
||||||
|
|
||||||
use crate::metadata::{DecodeWithMetadata, Metadata};
|
|
||||||
|
|
||||||
/// This represents a runtime API payload that can call into the runtime of node.
|
|
||||||
///
|
|
||||||
/// # Components
|
|
||||||
///
|
|
||||||
/// - associated return type
|
|
||||||
///
|
|
||||||
/// Resulting bytes of the call are interpreted into this type.
|
|
||||||
///
|
|
||||||
/// - runtime function name
|
|
||||||
///
|
|
||||||
/// The function name of the runtime API call. This is obtained by concatenating
|
|
||||||
/// the runtime trait name with the trait's method.
|
|
||||||
///
|
|
||||||
/// For example, the substrate runtime trait [Metadata](https://github.com/paritytech/substrate/blob/cb954820a8d8d765ce75021e244223a3b4d5722d/primitives/api/src/lib.rs#L745)
|
|
||||||
/// contains the `metadata_at_version` function. The corresponding runtime function
|
|
||||||
/// is `Metadata_metadata_at_version`.
|
|
||||||
///
|
|
||||||
/// - encoded arguments
|
|
||||||
///
|
|
||||||
/// Each argument of the runtime function must be scale-encoded.
|
|
||||||
pub trait Payload {
|
pub trait Payload {
|
||||||
|
/// Type of the arguments.
|
||||||
|
type ArgsType: IntoEncodableValues;
|
||||||
/// The return type of the function call.
|
/// The return type of the function call.
|
||||||
// Note: `DecodeWithMetadata` is needed to decode the function call result
|
type ReturnType: DecodeAsType;
|
||||||
// with the `subxt::Metadata.
|
|
||||||
type ReturnType: DecodeWithMetadata;
|
|
||||||
|
|
||||||
/// The runtime API trait name.
|
/// The runtime API trait name.
|
||||||
fn trait_name(&self) -> &str;
|
fn trait_name(&self) -> &str;
|
||||||
@@ -52,16 +25,8 @@ pub trait Payload {
|
|||||||
/// The runtime API method name.
|
/// The runtime API method name.
|
||||||
fn method_name(&self) -> &str;
|
fn method_name(&self) -> &str;
|
||||||
|
|
||||||
/// Scale encode the arguments data.
|
/// The input arguments.
|
||||||
fn encode_args_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), Error>;
|
fn args(&self) -> &Self::ArgsType;
|
||||||
|
|
||||||
/// Encode arguments data and return the output. This is a convenience
|
|
||||||
/// wrapper around [`Payload::encode_args_to`].
|
|
||||||
fn encode_args(&self, metadata: &Metadata) -> Result<Vec<u8>, Error> {
|
|
||||||
let mut v = Vec::new();
|
|
||||||
self.encode_args_to(metadata, &mut v)?;
|
|
||||||
Ok(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the statically generated validation hash.
|
/// Returns the statically generated validation hash.
|
||||||
fn validation_hash(&self) -> Option<[u8; 32]> {
|
fn validation_hash(&self) -> Option<[u8; 32]> {
|
||||||
@@ -74,24 +39,23 @@ pub trait Payload {
|
|||||||
///
|
///
|
||||||
/// This can be created from static values (ie those generated
|
/// This can be created from static values (ie those generated
|
||||||
/// via the `subxt` macro) or dynamic values via [`dynamic`].
|
/// via the `subxt` macro) or dynamic values via [`dynamic`].
|
||||||
#[derive_where(Clone, Debug, Eq, Ord, PartialEq, PartialOrd; ArgsData)]
|
#[derive_where(Clone, Debug, Eq, Ord, PartialEq, PartialOrd; ArgsType)]
|
||||||
pub struct DefaultPayload<ArgsData, ReturnTy> {
|
pub struct StaticPayload<ArgsType, ReturnType> {
|
||||||
trait_name: Cow<'static, str>,
|
trait_name: Cow<'static, str>,
|
||||||
method_name: Cow<'static, str>,
|
method_name: Cow<'static, str>,
|
||||||
args_data: ArgsData,
|
args: ArgsType,
|
||||||
validation_hash: Option<[u8; 32]>,
|
validation_hash: Option<[u8; 32]>,
|
||||||
_marker: PhantomData<ReturnTy>,
|
_marker: PhantomData<ReturnType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A statically generated runtime API payload.
|
|
||||||
pub type StaticPayload<ArgsData, ReturnTy> = DefaultPayload<ArgsData, ReturnTy>;
|
|
||||||
/// A dynamic runtime API payload.
|
/// A dynamic runtime API payload.
|
||||||
pub type DynamicPayload = DefaultPayload<Composite<()>, DecodedValueThunk>;
|
pub type DynamicPayload<ArgsType, ReturnType> = StaticPayload<ArgsType, ReturnType>;
|
||||||
|
|
||||||
impl<ArgsData: EncodeAsFields, ReturnTy: DecodeWithMetadata> Payload
|
impl<ArgsType: IntoEncodableValues, ReturnType: DecodeAsType> Payload
|
||||||
for DefaultPayload<ArgsData, ReturnTy>
|
for StaticPayload<ArgsType, ReturnType>
|
||||||
{
|
{
|
||||||
type ReturnType = ReturnTy;
|
type ArgsType = ArgsType;
|
||||||
|
type ReturnType = ReturnType;
|
||||||
|
|
||||||
fn trait_name(&self) -> &str {
|
fn trait_name(&self) -> &str {
|
||||||
&self.trait_name
|
&self.trait_name
|
||||||
@@ -101,18 +65,8 @@ impl<ArgsData: EncodeAsFields, ReturnTy: DecodeWithMetadata> Payload
|
|||||||
&self.method_name
|
&self.method_name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_args_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), Error> {
|
fn args(&self) -> &Self::ArgsType {
|
||||||
let api_method = metadata
|
&self.args
|
||||||
.runtime_api_trait_by_name_err(&self.trait_name)?
|
|
||||||
.method_by_name(&self.method_name)
|
|
||||||
.ok_or_else(|| MetadataError::RuntimeMethodNotFound((*self.method_name).to_owned()))?;
|
|
||||||
let mut fields = api_method
|
|
||||||
.inputs()
|
|
||||||
.map(|input| scale_encode::Field::named(input.id, &input.name));
|
|
||||||
|
|
||||||
self.args_data
|
|
||||||
.encode_as_fields_to(&mut fields, metadata.types(), out)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validation_hash(&self) -> Option<[u8; 32]> {
|
fn validation_hash(&self) -> Option<[u8; 32]> {
|
||||||
@@ -120,23 +74,23 @@ impl<ArgsData: EncodeAsFields, ReturnTy: DecodeWithMetadata> Payload
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ReturnTy, ArgsData> DefaultPayload<ArgsData, ReturnTy> {
|
impl<ArgsType, ReturnTy> StaticPayload<ArgsType, ReturnTy> {
|
||||||
/// Create a new [`DefaultPayload`].
|
/// Create a new [`StaticPayload`].
|
||||||
pub fn new(
|
pub fn new(
|
||||||
trait_name: impl Into<String>,
|
trait_name: impl Into<Cow<'static, str>>,
|
||||||
method_name: impl Into<String>,
|
method_name: impl Into<Cow<'static, str>>,
|
||||||
args_data: ArgsData,
|
args: ArgsType,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
DefaultPayload {
|
StaticPayload {
|
||||||
trait_name: Cow::Owned(trait_name.into()),
|
trait_name: Cow::Owned(trait_name.into()),
|
||||||
method_name: Cow::Owned(method_name.into()),
|
method_name: Cow::Owned(method_name.into()),
|
||||||
args_data,
|
args,
|
||||||
validation_hash: None,
|
validation_hash: None,
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new static [`DefaultPayload`] using static function name
|
/// Create a new static [`StaticPayload`] using static function name
|
||||||
/// and scale-encoded argument data.
|
/// and scale-encoded argument data.
|
||||||
///
|
///
|
||||||
/// This is only expected to be used from codegen.
|
/// This is only expected to be used from codegen.
|
||||||
@@ -144,13 +98,13 @@ impl<ReturnTy, ArgsData> DefaultPayload<ArgsData, ReturnTy> {
|
|||||||
pub fn new_static(
|
pub fn new_static(
|
||||||
trait_name: &'static str,
|
trait_name: &'static str,
|
||||||
method_name: &'static str,
|
method_name: &'static str,
|
||||||
args_data: ArgsData,
|
args: ArgsType,
|
||||||
hash: [u8; 32],
|
hash: [u8; 32],
|
||||||
) -> DefaultPayload<ArgsData, ReturnTy> {
|
) -> StaticPayload<ArgsType, ReturnTy> {
|
||||||
DefaultPayload {
|
StaticPayload {
|
||||||
trait_name: Cow::Borrowed(trait_name),
|
trait_name: Cow::Borrowed(trait_name),
|
||||||
method_name: Cow::Borrowed(method_name),
|
method_name: Cow::Borrowed(method_name),
|
||||||
args_data,
|
args,
|
||||||
validation_hash: Some(hash),
|
validation_hash: Some(hash),
|
||||||
_marker: core::marker::PhantomData,
|
_marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
@@ -173,18 +127,13 @@ impl<ReturnTy, ArgsData> DefaultPayload<ArgsData, ReturnTy> {
|
|||||||
pub fn method_name(&self) -> &str {
|
pub fn method_name(&self) -> &str {
|
||||||
&self.method_name
|
&self.method_name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the arguments data.
|
|
||||||
pub fn args_data(&self) -> &ArgsData {
|
|
||||||
&self.args_data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`DynamicPayload`].
|
/// Create a new [`DynamicPayload`].
|
||||||
pub fn dynamic(
|
pub fn dynamic<ArgsType, ReturnType>(
|
||||||
trait_name: impl Into<String>,
|
trait_name: impl Into<Cow<'static, str>>,
|
||||||
method_name: impl Into<String>,
|
method_name: impl Into<Cow<'static, str>>,
|
||||||
args_data: impl Into<Composite<()>>,
|
args_data: ArgsType,
|
||||||
) -> DynamicPayload {
|
) -> DynamicPayload<ArgsType, ReturnType> {
|
||||||
DefaultPayload::new(trait_name, method_name, args_data.into())
|
DynamicPayload::new(trait_name, method_name, args_data.into())
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-16
@@ -45,10 +45,7 @@ mod prefix_of;
|
|||||||
|
|
||||||
pub mod address;
|
pub mod address;
|
||||||
|
|
||||||
use crate::{
|
use crate::{Metadata, error::StorageError};
|
||||||
Error, Metadata,
|
|
||||||
error::{MetadataError, StorageError},
|
|
||||||
};
|
|
||||||
use address::Address;
|
use address::Address;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use frame_decode::storage::StorageTypeInfo;
|
use frame_decode::storage::StorageTypeInfo;
|
||||||
@@ -61,7 +58,7 @@ pub use prefix_of::{ EqualOrPrefixOf, PrefixOf };
|
|||||||
///
|
///
|
||||||
/// When the provided `address` is dynamic (and thus does not come with any expectation of the
|
/// When the provided `address` is dynamic (and thus does not come with any expectation of the
|
||||||
/// shape of the constant value), this just returns `Ok(())`
|
/// shape of the constant value), this just returns `Ok(())`
|
||||||
pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<(), Error> {
|
pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<(), StorageError> {
|
||||||
let Some(hash) = address.validation_hash() else {
|
let Some(hash) = address.validation_hash() else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
@@ -69,15 +66,19 @@ pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<()
|
|||||||
let pallet_name = address.pallet_name();
|
let pallet_name = address.pallet_name();
|
||||||
let entry_name = address.entry_name();
|
let entry_name = address.entry_name();
|
||||||
|
|
||||||
let pallet_metadata = metadata.pallet_by_name_err(pallet_name)?;
|
let pallet_metadata = metadata.pallet_by_name(pallet_name)
|
||||||
|
.ok_or_else(|| StorageError::PalletNameNotFound(pallet_name.to_string()))?;
|
||||||
|
let storage_hash = pallet_metadata.storage_hash(entry_name)
|
||||||
|
.ok_or_else(|| StorageError::StorageEntryNotFound {
|
||||||
|
pallet_name: pallet_name.to_string(),
|
||||||
|
entry_name: entry_name.to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
let Some(expected_hash) = pallet_metadata.storage_hash(entry_name) else {
|
if storage_hash != hash {
|
||||||
return Err(MetadataError::IncompatibleCodegen.into());
|
Err(StorageError::IncompatibleCodegen)
|
||||||
};
|
} else {
|
||||||
if expected_hash != hash {
|
Ok(())
|
||||||
return Err(MetadataError::IncompatibleCodegen.into());
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a storage address and some metadata, this encodes the address into bytes which can be
|
/// Given a storage address and some metadata, this encodes the address into bytes which can be
|
||||||
@@ -86,7 +87,7 @@ pub fn get_address_bytes<Addr: Address, Keys: EqualOrPrefixOf<Addr::KeyParts>>(
|
|||||||
address: &Addr,
|
address: &Addr,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
keys: Keys,
|
keys: Keys,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, StorageError> {
|
||||||
frame_decode::storage::encode_storage_key(
|
frame_decode::storage::encode_storage_key(
|
||||||
address.pallet_name(),
|
address.pallet_name(),
|
||||||
address.entry_name(),
|
address.entry_name(),
|
||||||
@@ -101,7 +102,10 @@ pub fn get_address_bytes<Addr: Address, Keys: EqualOrPrefixOf<Addr::KeyParts>>(
|
|||||||
/// and storage entry part) into bytes. If the entry being addressed is inside a map, this returns
|
/// and storage entry part) into bytes. If the entry being addressed is inside a map, this returns
|
||||||
/// the bytes needed to iterate over all of the entries within it.
|
/// the bytes needed to iterate over all of the entries within it.
|
||||||
pub fn get_address_root_bytes<Addr: Address>(address: &Addr) -> [u8; 32] {
|
pub fn get_address_root_bytes<Addr: Address>(address: &Addr) -> [u8; 32] {
|
||||||
frame_decode::storage::encode_storage_key_prefix(address.pallet_name(), address.entry_name())
|
frame_decode::storage::encode_storage_key_prefix(
|
||||||
|
address.pallet_name(),
|
||||||
|
address.entry_name()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given some storage value that we've retrieved from a node, the address used to retrieve it, and
|
/// Given some storage value that we've retrieved from a node, the address used to retrieve it, and
|
||||||
@@ -111,7 +115,7 @@ pub fn decode_value<Addr: Address>(
|
|||||||
bytes: &mut &[u8],
|
bytes: &mut &[u8],
|
||||||
address: &Addr,
|
address: &Addr,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
) -> Result<Addr::Value, Error> {
|
) -> Result<Addr::Value, StorageError> {
|
||||||
frame_decode::storage::decode_storage_value(
|
frame_decode::storage::decode_storage_value(
|
||||||
address.pallet_name(),
|
address.pallet_name(),
|
||||||
address.entry_name(),
|
address.entry_name(),
|
||||||
@@ -127,7 +131,7 @@ pub fn decode_value<Addr: Address>(
|
|||||||
pub fn default_value<Addr: Address>(
|
pub fn default_value<Addr: Address>(
|
||||||
address: &Addr,
|
address: &Addr,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
) -> Result<Option<Addr::Value>, Error> {
|
) -> Result<Option<Addr::Value>, StorageError> {
|
||||||
let storage_info = metadata
|
let storage_info = metadata
|
||||||
.storage_info(address.pallet_name(), address.entry_name())
|
.storage_info(address.pallet_name(), address.entry_name())
|
||||||
.map_err(|e| StorageError::StorageInfoError(e.into_owned()))?;
|
.map_err(|e| StorageError::StorageInfoError(e.into_owned()))?;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use alloc::vec::Vec;
|
|||||||
use codec::{Compact, Decode, Encode};
|
use codec::{Compact, Decode, Encode};
|
||||||
use derive_where::derive_where;
|
use derive_where::derive_where;
|
||||||
|
|
||||||
pub use yesnomaybe::{Yes, No, Maybe, YesMaybe, YesNo};
|
pub use yesnomaybe::{Yes, No, Maybe, YesMaybe, NoMaybe, YesNo};
|
||||||
pub use account_id::AccountId32;
|
pub use account_id::AccountId32;
|
||||||
pub use account_id20::AccountId20;
|
pub use account_id20::AccountId20;
|
||||||
pub use era::Era;
|
pub use era::Era;
|
||||||
|
|||||||
@@ -39,4 +39,20 @@ impl YesMaybe for Yes {
|
|||||||
}
|
}
|
||||||
impl YesMaybe for Maybe {
|
impl YesMaybe for Maybe {
|
||||||
fn is_maybe() -> bool { true }
|
fn is_maybe() -> bool { true }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is implemented for [`No`] and [`Maybe`] and
|
||||||
|
/// allows us to check at runtime which of these types is present.
|
||||||
|
pub trait NoMaybe {
|
||||||
|
/// [`No`]
|
||||||
|
fn is_no() -> bool { false }
|
||||||
|
/// [`Maybe`]
|
||||||
|
fn is_maybe() -> bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoMaybe for No {
|
||||||
|
fn is_no() -> bool { true }
|
||||||
|
}
|
||||||
|
impl NoMaybe for Maybe {
|
||||||
|
fn is_maybe() -> bool { true }
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ mod extrinsic_info;
|
|||||||
mod extrinsic_transaction_extensions;
|
mod extrinsic_transaction_extensions;
|
||||||
mod extrinsics_type;
|
mod extrinsics_type;
|
||||||
|
|
||||||
pub use extrinsic_transaction_extensions::ExtrinsicTransactionExtensions;
|
pub use extrinsic_transaction_extensions::ExtrinsicExtrinsicParams;
|
||||||
pub use extrinsics_type::{Extrinsic, Extrinsics};
|
pub use extrinsics_type::{Extrinsic, Extrinsics};
|
||||||
|
|
||||||
/// Work with extrinsics.
|
/// Work with extrinsics.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ struct ExtrinsicExtensionsInfo<'extrinsics, 'atblock, TypeId, Resolver> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This represents the transaction extensions of an extrinsic.
|
/// This represents the transaction extensions of an extrinsic.
|
||||||
pub struct ExtrinsicTransactionExtensions<'extrinsics, 'atblock> {
|
pub struct ExtrinsicExtrinsicParams<'extrinsics, 'atblock> {
|
||||||
all_bytes: &'extrinsics [u8],
|
all_bytes: &'extrinsics [u8],
|
||||||
info: AnyExtrinsicExtensionsInfo<'extrinsics, 'atblock>,
|
info: AnyExtrinsicExtensionsInfo<'extrinsics, 'atblock>,
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ macro_rules! with_extensions_info {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'extrinsics, 'atblock> ExtrinsicTransactionExtensions<'extrinsics, 'atblock> {
|
impl<'extrinsics, 'atblock> ExtrinsicExtrinsicParams<'extrinsics, 'atblock> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
all_bytes: &'extrinsics [u8],
|
all_bytes: &'extrinsics [u8],
|
||||||
info: &'extrinsics AnyExtrinsicInfo<'atblock>,
|
info: &'extrinsics AnyExtrinsicInfo<'atblock>,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::extrinsic_call::ExtrinsicCall;
|
use super::extrinsic_call::ExtrinsicCall;
|
||||||
use super::extrinsic_info::{AnyExtrinsicInfo, with_info};
|
use super::extrinsic_info::{AnyExtrinsicInfo, with_info};
|
||||||
use super::extrinsic_transaction_extensions::ExtrinsicTransactionExtensions;
|
use super::extrinsic_transaction_extensions::ExtrinsicExtrinsicParams;
|
||||||
use crate::client::OfflineClientAtBlockT;
|
use crate::client::OfflineClientAtBlockT;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::error::ExtrinsicsError;
|
use crate::error::ExtrinsicsError;
|
||||||
@@ -106,8 +106,8 @@ impl<'extrinsics, 'atblock> Extrinsic<'extrinsics, 'atblock> {
|
|||||||
/// Get information about the transaction extensions of this extrinsic.
|
/// Get information about the transaction extensions of this extrinsic.
|
||||||
pub fn transaction_extensions(
|
pub fn transaction_extensions(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<ExtrinsicTransactionExtensions<'extrinsics, 'atblock>> {
|
) -> Option<ExtrinsicExtrinsicParams<'extrinsics, 'atblock>> {
|
||||||
ExtrinsicTransactionExtensions::new(self.bytes, self.info)
|
ExtrinsicExtrinsicParams::new(self.bytes, self.info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ use frame_decode::runtime_apis::{
|
|||||||
use frame_decode::view_functions::{
|
use frame_decode::view_functions::{
|
||||||
ViewFunction, ViewFunctionInfo, ViewFunctionInfoError, ViewFunctionInput
|
ViewFunction, ViewFunctionInfo, ViewFunctionInfoError, ViewFunctionInput
|
||||||
};
|
};
|
||||||
|
use frame_decode::constants::{
|
||||||
|
ConstantInfo, ConstantInfoError, Constant
|
||||||
|
};
|
||||||
|
use frame_decode::custom_values::{
|
||||||
|
CustomValueInfo, CustomValueInfoError, CustomValue
|
||||||
|
};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use scale_info::{PortableRegistry, Variant, form::PortableForm};
|
use scale_info::{PortableRegistry, Variant, form::PortableForm};
|
||||||
@@ -256,6 +262,64 @@ impl frame_decode::view_functions::ViewFunctionTypeInfo for Metadata {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl frame_decode::constants::ConstantTypeInfo for Metadata {
|
||||||
|
type TypeId = u32;
|
||||||
|
|
||||||
|
fn constant_info(
|
||||||
|
&self,
|
||||||
|
pallet_name: &str,
|
||||||
|
constant_name: &str,
|
||||||
|
) -> Result<ConstantInfo<'_, Self::TypeId>, ConstantInfoError<'_>> {
|
||||||
|
let pallet = self.pallet_by_name("pallet_name")
|
||||||
|
.ok_or_else(|| ConstantInfoError::PalletNotFound { pallet_name: pallet_name.to_string() })?;
|
||||||
|
let constant = pallet.constant_by_name(constant_name)
|
||||||
|
.ok_or_else(|| ConstantInfoError::ConstantNotFound { pallet_name: Cow::Borrowed(pallet.name()), constant_name: constant_name.to_string() })?;
|
||||||
|
|
||||||
|
let info = ConstantInfo {
|
||||||
|
bytes: &constant.value,
|
||||||
|
type_id: constant.ty
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constants(&self) -> impl Iterator<Item = Constant<'_>> {
|
||||||
|
self.pallets().flat_map(|pallet| {
|
||||||
|
let pallet_name = pallet.name();
|
||||||
|
pallet.constants().map(|constant| {
|
||||||
|
Constant {
|
||||||
|
pallet_name: Cow::Borrowed(pallet_name),
|
||||||
|
constant_name: Cow::Borrowed(constant.name())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl frame_decode::custom_values::CustomValueTypeInfo for Metadata {
|
||||||
|
type TypeId = u32;
|
||||||
|
|
||||||
|
fn custom_value_info(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<CustomValueInfo<'_, Self::TypeId>, CustomValueInfoError> {
|
||||||
|
let custom_value = self.custom()
|
||||||
|
.get(name)
|
||||||
|
.ok_or_else(|| CustomValueInfoError { not_found: name.to_string() })?;
|
||||||
|
|
||||||
|
let info = CustomValueInfo {
|
||||||
|
bytes: &custom_value.data,
|
||||||
|
type_id: custom_value.type_id
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom_values(&self) -> impl Iterator<Item = CustomValue<'_>> {
|
||||||
|
self.custom.map.iter().map(|(name, _)| {
|
||||||
|
CustomValue { name: Cow::Borrowed(name) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Metadata {
|
impl Metadata {
|
||||||
/// Access the underlying type registry.
|
/// Access the underlying type registry.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use subxt_core::blocks::{ExtrinsicDetails as CoreExtrinsicDetails, Extrinsics as
|
|||||||
|
|
||||||
// Re-export anything that's directly returned/used in the APIs below.
|
// Re-export anything that's directly returned/used in the APIs below.
|
||||||
pub use subxt_core::blocks::{
|
pub use subxt_core::blocks::{
|
||||||
ExtrinsicMetadataDetails, ExtrinsicTransactionExtension, ExtrinsicTransactionExtensions,
|
ExtrinsicMetadataDetails, ExtrinsicTransactionExtension, ExtrinsicExtrinsicParams,
|
||||||
StaticExtrinsic,
|
StaticExtrinsic,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// See [`subxt_core::blocks::ExtrinsicDetails::transaction_extensions()`].
|
/// See [`subxt_core::blocks::ExtrinsicDetails::transaction_extensions()`].
|
||||||
pub fn transaction_extensions(&self) -> Option<ExtrinsicTransactionExtensions<'_, T>> {
|
pub fn transaction_extensions(&self) -> Option<ExtrinsicExtrinsicParams<'_, T>> {
|
||||||
self.inner.transaction_extensions()
|
self.inner.transaction_extensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub use block_types::Block;
|
|||||||
pub use blocks_client::BlocksClient;
|
pub use blocks_client::BlocksClient;
|
||||||
pub use extrinsic_types::{
|
pub use extrinsic_types::{
|
||||||
ExtrinsicDetails, ExtrinsicEvents, ExtrinsicTransactionExtension,
|
ExtrinsicDetails, ExtrinsicEvents, ExtrinsicTransactionExtension,
|
||||||
ExtrinsicTransactionExtensions, Extrinsics, FoundExtrinsic, StaticExtrinsic,
|
ExtrinsicExtrinsicParams, Extrinsics, FoundExtrinsic, StaticExtrinsic,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We get account nonce info in tx_client, too, so re-use the logic:
|
// We get account nonce info in tx_client, too, so re-use the logic:
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
//! get only [the first one](crate::blocks::Extrinsics::find_first), or [the last one](crate::blocks::Extrinsics::find_last).
|
//! get only [the first one](crate::blocks::Extrinsics::find_first), or [the last one](crate::blocks::Extrinsics::find_last).
|
||||||
//!
|
//!
|
||||||
//! The following example monitors `TransferKeepAlive` extrinsics on the Polkadot network.
|
//! The following example monitors `TransferKeepAlive` extrinsics on the Polkadot network.
|
||||||
//! We statically decode them and access the [tip](crate::blocks::ExtrinsicTransactionExtensions::tip()) and [account nonce](crate::blocks::ExtrinsicTransactionExtensions::nonce())
|
//! We statically decode them and access the [tip](crate::blocks::ExtrinsicExtrinsicParams::tip()) and [account nonce](crate::blocks::ExtrinsicExtrinsicParams::nonce())
|
||||||
//! transaction extensions.
|
//! transaction extensions.
|
||||||
//!
|
//!
|
||||||
//! ```rust,ignore
|
//! ```rust,ignore
|
||||||
@@ -90,10 +90,10 @@
|
|||||||
//! The [Config](crate::Config) implementation for your chain defines which transaction extensions you expect.
|
//! The [Config](crate::Config) implementation for your chain defines which transaction extensions you expect.
|
||||||
//! Once you get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails) for an extrinsic you are interested in,
|
//! Once you get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails) for an extrinsic you are interested in,
|
||||||
//! you can try to [get its transaction extensions](crate::blocks::ExtrinsicDetails::transaction_extensions()).
|
//! you can try to [get its transaction extensions](crate::blocks::ExtrinsicDetails::transaction_extensions()).
|
||||||
//! These are only available on V4 signed extrinsics or V5 general extrinsics. You can try to [find a specific transaction extension](crate::blocks::ExtrinsicTransactionExtensions::find),
|
//! These are only available on V4 signed extrinsics or V5 general extrinsics. You can try to [find a specific transaction extension](crate::blocks::ExtrinsicExtrinsicParams::find),
|
||||||
//! in the returned [transaction extensions](crate::blocks::ExtrinsicTransactionExtensions).
|
//! in the returned [transaction extensions](crate::blocks::ExtrinsicExtrinsicParams).
|
||||||
//!
|
//!
|
||||||
//! Subxt also provides utility functions to get the [tip](crate::blocks::ExtrinsicTransactionExtensions::tip()) and the
|
//! Subxt also provides utility functions to get the [tip](crate::blocks::ExtrinsicExtrinsicParams::tip()) and the
|
||||||
//! [account nonce](crate::blocks::ExtrinsicTransactionExtensions::tip()) associated with an extrinsic, given its transaction extensions.
|
//! [account nonce](crate::blocks::ExtrinsicExtrinsicParams::tip()) associated with an extrinsic, given its transaction extensions.
|
||||||
//! If you prefer to do things dynamically you can get the data of the transaction extension as a [scale value](crate::blocks::ExtrinsicTransactionExtension::value()).
|
//! If you prefer to do things dynamically you can get the data of the transaction extension as a [scale value](crate::blocks::ExtrinsicTransactionExtension::value()).
|
||||||
//!
|
//!
|
||||||
|
|||||||
+1
-1
@@ -68,7 +68,7 @@ pub mod config {
|
|||||||
|
|
||||||
/// Types representing the metadata obtained from a node.
|
/// Types representing the metadata obtained from a node.
|
||||||
pub mod metadata {
|
pub mod metadata {
|
||||||
pub use subxt_core::metadata::{DecodeWithMetadata, EncodeWithMetadata, Metadata};
|
pub use subxt_core::metadata::{DecodeWithMetadata, Metadata};
|
||||||
// Expose metadata types under a sub module in case somebody needs to reference them:
|
// Expose metadata types under a sub module in case somebody needs to reference them:
|
||||||
pub use subxt_metadata as types;
|
pub use subxt_metadata as types;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user