mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-06 10:18:02 +00:00
Get subxt-core compiling
This commit is contained in:
@@ -37,6 +37,7 @@ use crate::{Metadata, error::CustomValueError};
|
||||
use address::Address;
|
||||
use alloc::vec::Vec;
|
||||
use frame_decode::custom_values::CustomValueTypeInfo;
|
||||
use scale_decode::IntoVisitor;
|
||||
|
||||
/// 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).
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
//! This module provides the entry points to create dynamic
|
||||
//! transactions, storage and constant lookups.
|
||||
|
||||
use crate::metadata::{DecodeWithMetadata, Metadata};
|
||||
use alloc::vec::Vec;
|
||||
use scale_decode::DecodeAsType;
|
||||
pub use scale_value::{At, Value};
|
||||
|
||||
/// A [`scale_value::Value`] type endowed with contextual information
|
||||
@@ -30,57 +27,3 @@ pub use crate::runtime_api::payload::dynamic as runtime_api_call;
|
||||
|
||||
// Execute View Function API function call dynamically.
|
||||
pub use crate::view_functions::payload::dynamic as view_function_call;
|
||||
|
||||
/// This is the result of making a dynamic request to a node. From this,
|
||||
/// we can return the raw SCALE bytes that we were handed back, or we can
|
||||
/// complete the decoding of the bytes into a [`DecodedValue`] type.
|
||||
pub struct DecodedValueThunk {
|
||||
type_id: u32,
|
||||
metadata: Metadata,
|
||||
scale_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DecodeWithMetadata for DecodedValueThunk {
|
||||
fn decode_with_metadata(
|
||||
bytes: &mut &[u8],
|
||||
type_id: u32,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Self, scale_decode::Error> {
|
||||
let mut v = Vec::with_capacity(bytes.len());
|
||||
v.extend_from_slice(bytes);
|
||||
*bytes = &[];
|
||||
Ok(DecodedValueThunk {
|
||||
type_id,
|
||||
metadata: metadata.clone(),
|
||||
scale_bytes: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DecodedValueThunk {
|
||||
/// Return the SCALE encoded bytes handed back from the node.
|
||||
pub fn into_encoded(self) -> Vec<u8> {
|
||||
self.scale_bytes
|
||||
}
|
||||
/// Return the SCALE encoded bytes handed back from the node without taking ownership of them.
|
||||
pub fn encoded(&self) -> &[u8] {
|
||||
&self.scale_bytes
|
||||
}
|
||||
/// Decode the SCALE encoded storage entry into a dynamic [`DecodedValue`] type.
|
||||
pub fn to_value(&self) -> Result<DecodedValue, scale_decode::Error> {
|
||||
let val = scale_value::scale::decode_as_type(
|
||||
&mut &*self.scale_bytes,
|
||||
self.type_id,
|
||||
self.metadata.types(),
|
||||
)?;
|
||||
Ok(val)
|
||||
}
|
||||
/// decode the `DecodedValueThunk` into a concrete type.
|
||||
pub fn as_type<T: DecodeAsType>(&self) -> Result<T, scale_decode::Error> {
|
||||
T::decode_as_type(
|
||||
&mut &self.scale_bytes[..],
|
||||
self.type_id,
|
||||
self.metadata.types(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+79
-67
@@ -12,85 +12,79 @@ use thiserror::Error as DeriveError;
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Error {
|
||||
// /// Codec error.
|
||||
// #[error("Codec error: {0}")]
|
||||
// Codec(codec::Error),
|
||||
#[error(transparent)]
|
||||
Metadata(#[from] MetadataError),
|
||||
#[error(transparent)]
|
||||
StorageError(#[from] StorageError),
|
||||
// /// Error decoding to a [`crate::dynamic::Value`].
|
||||
// #[error("Error decoding into dynamic value: {0}")]
|
||||
// Decode(#[from] scale_decode::Error),
|
||||
// /// Error encoding from a [`crate::dynamic::Value`].
|
||||
// #[error("Error encoding from dynamic value: {0}")]
|
||||
// Encode(#[from] scale_encode::Error),
|
||||
#[error(transparent)]
|
||||
Extrinsic(#[from] ExtrinsicError),
|
||||
#[error(transparent)]
|
||||
Constant(#[from] ConstantError),
|
||||
#[error(transparent)]
|
||||
CustomValueError(CustomValueError)
|
||||
CustomValue(#[from] CustomValueError),
|
||||
#[error(transparent)]
|
||||
RuntimeApi(#[from] RuntimeApiError),
|
||||
#[error(transparent)]
|
||||
ViewFunction(#[from] ViewFunctionError),
|
||||
#[error(transparent)]
|
||||
Events(#[from] EventsError),
|
||||
}
|
||||
|
||||
// impl From<scale_decode::visitor::DecodeError> for Error {
|
||||
// fn from(err: scale_decode::visitor::DecodeError) -> Error {
|
||||
// Error::Decode(err.into())
|
||||
// }
|
||||
// }
|
||||
|
||||
// // TODO: when `codec::Error` implements `core::Error`
|
||||
// // remove this impl and replace it by thiserror #[from]
|
||||
// impl From<codec::Error> for Error {
|
||||
// fn from(err: codec::Error) -> Error {
|
||||
// Error::Codec(err)
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Something went wrong trying to access details in the metadata.
|
||||
#[derive(Clone, Debug, PartialEq, DeriveError)]
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum MetadataError {
|
||||
// /// The DispatchError type isn't available in the metadata
|
||||
// #[error("The DispatchError type isn't available")]
|
||||
// DispatchErrorNotFound,
|
||||
// /// Type not found in metadata.
|
||||
// #[error("Type with ID {0} not found")]
|
||||
// TypeNotFound(u32),
|
||||
/// Pallet not found (index).
|
||||
// /// Call type not found in metadata.
|
||||
// #[error("Call type not found in pallet with index {0}")]
|
||||
// CallTypeNotFoundInPallet(u8),
|
||||
// /// Event type not found in metadata.
|
||||
// #[error("Event type not found in pallet with index {0}")]
|
||||
// EventTypeNotFoundInPallet(u8),
|
||||
// // /// Storage details not found in metadata.
|
||||
// // #[error("Storage details not found in pallet with name {0}")]
|
||||
// // StorageNotFoundInPallet(String),
|
||||
// // /// Storage entry not found.
|
||||
// // #[error("Storage entry {0} not found")]
|
||||
// // StorageEntryNotFound(String),
|
||||
#[error("Pallet with index {0} not found")]
|
||||
PalletIndexNotFound(u8),
|
||||
#[error("Pallet with name {0} not found")]
|
||||
PalletNameNotFound(String),
|
||||
#[error("Variant with index {0} not found")]
|
||||
VariantIndexNotFound(u8),
|
||||
#[error("Constant with name {0} not found")]
|
||||
ConstantNameNotFound(String),
|
||||
#[error("Call with name {0} not found")]
|
||||
CallNameNotFound(String),
|
||||
#[error("Runtime trait with name {0} not found")]
|
||||
RuntimeTraitNotFound(String),
|
||||
#[error("Runtime method with name {0} not found")]
|
||||
RuntimeMethodNotFound(String),
|
||||
#[error("View Function with query ID {} not found", hex::encode(.0))]
|
||||
ViewFunctionNotFound([u8; 32]),
|
||||
#[error("The generated code is not compatible with the node")]
|
||||
pub enum EventsError {
|
||||
#[error("Can't decode event: can't decode phase: {0}")]
|
||||
CannotDecodePhase(codec::Error),
|
||||
#[error("Can't decode event: can't decode pallet index: {0}")]
|
||||
CannotDecodePalletIndex(codec::Error),
|
||||
#[error("Can't decode event: can't decode variant index: {0}")]
|
||||
CannotDecodeVariantIndex(codec::Error),
|
||||
#[error("Can't decode event: can't find pallet with index {0}")]
|
||||
CannotFindPalletWithIndex(u8),
|
||||
#[error("Can't decode event: can't find variant with index {variant_index} in pallet {pallet_name}")]
|
||||
CannotFindVariantWithIndex {
|
||||
pallet_name: String,
|
||||
variant_index: u8
|
||||
},
|
||||
#[error("Can't decode field {field_name:?} in event {pallet_name}.{event_name}: {reason}")]
|
||||
CannotDecodeFieldInEvent {
|
||||
pallet_name: String,
|
||||
event_name: String,
|
||||
field_name: String,
|
||||
reason: scale_decode::visitor::DecodeError
|
||||
},
|
||||
#[error("Can't decode event topics: {0}")]
|
||||
CannotDecodeEventTopics(codec::Error),
|
||||
#[error("Can't decode the fields of event {pallet_name}.{event_name}: {reason}")]
|
||||
CannotDecodeEventFields {
|
||||
pallet_name: String,
|
||||
event_name: String,
|
||||
reason: scale_decode::Error
|
||||
},
|
||||
#[error("Can't decode event {pallet_name}.{event_name} to Event enum: {reason}")]
|
||||
CannotDecodeEventEnum {
|
||||
pallet_name: String,
|
||||
event_name: String,
|
||||
reason: scale_decode::Error
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ViewFunctionError {
|
||||
#[error("The static View Function address used is not compatible with the live chain")]
|
||||
IncompatibleCodegen,
|
||||
#[error("Custom value with name {0} not found")]
|
||||
CustomValueNameNotFound(String),
|
||||
#[error("Can't find View Function: pallet {0} not found")]
|
||||
PalletNotFound(String),
|
||||
#[error("Can't find View Function {function_name} in pallet {pallet_name}")]
|
||||
ViewFunctionNotFound {
|
||||
pallet_name: String,
|
||||
function_name: String,
|
||||
},
|
||||
#[error("Failed to encode View Function inputs: {0}")]
|
||||
CouldNotEncodeInputs(frame_decode::view_functions::ViewFunctionInputsEncodeError),
|
||||
#[error("Failed to decode View Function: {0}")]
|
||||
CouldNotDecodeResponse(frame_decode::view_functions::ViewFunctionDecodeError<u32>),
|
||||
}
|
||||
|
||||
#[derive(Debug, DeriveError)]
|
||||
@@ -99,6 +93,13 @@ pub enum MetadataError {
|
||||
pub enum RuntimeApiError {
|
||||
#[error("The static Runtime API address used is not compatible with the live chain")]
|
||||
IncompatibleCodegen,
|
||||
#[error("Runtime API trait not found: {0}")]
|
||||
TraitNotFound(String),
|
||||
#[error("Runtime API method {method_name} not found in trait {trait_name}")]
|
||||
MethodNotFound {
|
||||
trait_name: String,
|
||||
method_name: String,
|
||||
},
|
||||
#[error("Failed to encode Runtime API inputs: {0}")]
|
||||
CouldNotEncodeInputs(frame_decode::runtime_apis::RuntimeApiInputsEncodeError),
|
||||
#[error("Failed to decode Runtime API: {0}")]
|
||||
@@ -162,6 +163,17 @@ pub enum StorageError {
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ExtrinsicError {
|
||||
#[error("The extrinsic payload is not compatible with the live chain")]
|
||||
IncompatibleCodegen,
|
||||
#[error("Can't find extrinsic: pallet with name {0} not found")]
|
||||
PalletNameNotFound(String),
|
||||
#[error("Can't find extrinsic: call name {call_name} doesn't exist in pallet {pallet_name}")]
|
||||
CallNameNotFound {
|
||||
pallet_name: String,
|
||||
call_name: String
|
||||
},
|
||||
#[error("Can't encode the extrinsic call data: {0}")]
|
||||
CannotEncodeCallData(scale_encode::Error),
|
||||
#[error("Subxt does not support the extrinsic versions expected by the chain")]
|
||||
UnsupportedVersion,
|
||||
#[error("Cannot construct the required transaction extensions: {0}")]
|
||||
|
||||
+52
-22
@@ -46,9 +46,8 @@ use scale_decode::{DecodeAsFields, DecodeAsType};
|
||||
use subxt_metadata::PalletMetadata;
|
||||
|
||||
use crate::{
|
||||
Error, Metadata,
|
||||
error::EventsError, Metadata,
|
||||
config::{Config, HashFor},
|
||||
error::MetadataError,
|
||||
};
|
||||
|
||||
/// Create a new [`Events`] instance from the given bytes.
|
||||
@@ -148,7 +147,7 @@ impl<T: Config> Events<T> {
|
||||
// use of it with our `FilterEvents` stuff.
|
||||
pub fn iter(
|
||||
&self,
|
||||
) -> impl Iterator<Item = Result<EventDetails<T>, Error>> + Send + Sync + 'static {
|
||||
) -> impl Iterator<Item = Result<EventDetails<T>, EventsError>> + Send + Sync + 'static {
|
||||
// The event bytes ignoring the compact encoded length on the front:
|
||||
let event_bytes = self.event_bytes.clone();
|
||||
let metadata = self.metadata.clone();
|
||||
@@ -184,25 +183,25 @@ impl<T: Config> Events<T> {
|
||||
/// Iterate through the events using metadata to dynamically decode and skip
|
||||
/// them, and return only those which should decode to the provided `Ev` type.
|
||||
/// If an error occurs, all subsequent iterations return `None`.
|
||||
pub fn find<Ev: StaticEvent>(&self) -> impl Iterator<Item = Result<Ev, Error>> {
|
||||
pub fn find<Ev: StaticEvent>(&self) -> impl Iterator<Item = Result<Ev, EventsError>> {
|
||||
self.iter()
|
||||
.filter_map(|ev| ev.and_then(|ev| ev.as_event::<Ev>()).transpose())
|
||||
}
|
||||
|
||||
/// Iterate through the events using metadata to dynamically decode and skip
|
||||
/// them, and return the first event found which decodes to the provided `Ev` type.
|
||||
pub fn find_first<Ev: StaticEvent>(&self) -> Result<Option<Ev>, Error> {
|
||||
pub fn find_first<Ev: StaticEvent>(&self) -> Result<Option<Ev>, EventsError> {
|
||||
self.find::<Ev>().next().transpose()
|
||||
}
|
||||
|
||||
/// Iterate through the events using metadata to dynamically decode and skip
|
||||
/// them, and return the last event found which decodes to the provided `Ev` type.
|
||||
pub fn find_last<Ev: StaticEvent>(&self) -> Result<Option<Ev>, Error> {
|
||||
pub fn find_last<Ev: StaticEvent>(&self) -> Result<Option<Ev>, EventsError> {
|
||||
self.find::<Ev>().last().transpose()
|
||||
}
|
||||
|
||||
/// Find an event that decodes to the type provided. Returns true if it was found.
|
||||
pub fn has<Ev: StaticEvent>(&self) -> Result<bool, Error> {
|
||||
pub fn has<Ev: StaticEvent>(&self) -> Result<bool, EventsError> {
|
||||
Ok(self.find::<Ev>().next().transpose()?.is_some())
|
||||
}
|
||||
}
|
||||
@@ -246,23 +245,32 @@ impl<T: Config> EventDetails<T> {
|
||||
all_bytes: Arc<[u8]>,
|
||||
start_idx: usize,
|
||||
index: u32,
|
||||
) -> Result<EventDetails<T>, Error> {
|
||||
) -> Result<EventDetails<T>, EventsError> {
|
||||
let input = &mut &all_bytes[start_idx..];
|
||||
|
||||
let phase = Phase::decode(input)?;
|
||||
let phase = Phase::decode(input)
|
||||
.map_err(EventsError::CannotDecodePhase)?;
|
||||
|
||||
let event_start_idx = all_bytes.len() - input.len();
|
||||
|
||||
let pallet_index = u8::decode(input)?;
|
||||
let variant_index = u8::decode(input)?;
|
||||
let pallet_index = u8::decode(input)
|
||||
.map_err(EventsError::CannotDecodePalletIndex)?;
|
||||
let variant_index = u8::decode(input)
|
||||
.map_err(EventsError::CannotDecodeVariantIndex)?;
|
||||
|
||||
let event_fields_start_idx = all_bytes.len() - input.len();
|
||||
|
||||
// Get metadata for the event:
|
||||
let event_pallet = metadata.pallet_by_index_err(pallet_index)?;
|
||||
let event_pallet = metadata
|
||||
.pallet_by_index(pallet_index)
|
||||
.ok_or_else(|| EventsError::CannotFindPalletWithIndex(pallet_index))?;
|
||||
let event_variant = event_pallet
|
||||
.event_variant_by_index(variant_index)
|
||||
.ok_or(MetadataError::VariantIndexNotFound(variant_index))?;
|
||||
.ok_or_else(|| EventsError::CannotFindVariantWithIndex {
|
||||
pallet_name: event_pallet.name().to_string(),
|
||||
variant_index: variant_index,
|
||||
})?;
|
||||
|
||||
tracing::debug!(
|
||||
"Decoding Event '{}::{}'",
|
||||
event_pallet.name(),
|
||||
@@ -278,14 +286,20 @@ impl<T: Config> EventDetails<T> {
|
||||
metadata.types(),
|
||||
scale_decode::visitor::IgnoreVisitor::new(),
|
||||
)
|
||||
.map_err(scale_decode::Error::from)?;
|
||||
.map_err(|e| EventsError::CannotDecodeFieldInEvent {
|
||||
pallet_name: event_pallet.name().to_string(),
|
||||
event_name: event_variant.name.clone(),
|
||||
field_name: field_metadata.name.clone().unwrap_or("<unknown>".to_string()),
|
||||
reason: e
|
||||
})?;
|
||||
}
|
||||
|
||||
// the end of the field bytes.
|
||||
let event_fields_end_idx = all_bytes.len() - input.len();
|
||||
|
||||
// topics come after the event data in EventRecord.
|
||||
let topics = Vec::<HashFor<T>>::decode(input)?;
|
||||
let topics = Vec::<HashFor<T>>::decode(input)
|
||||
.map_err(EventsError::CannotDecodeEventTopics)?;
|
||||
|
||||
// what bytes did we skip over in total, including topics.
|
||||
let end_idx = all_bytes.len() - input.len();
|
||||
@@ -367,7 +381,7 @@ impl<T: Config> EventDetails<T> {
|
||||
|
||||
/// Decode and provide the event fields back in the form of a [`scale_value::Composite`]
|
||||
/// type which represents the named or unnamed fields that were present in the event.
|
||||
pub fn field_values(&self) -> Result<scale_value::Composite<u32>, Error> {
|
||||
pub fn decode_fields_as<E: DecodeAsFields>(&self) -> Result<E, EventsError> {
|
||||
let bytes = &mut self.field_bytes();
|
||||
let event_metadata = self.event_metadata();
|
||||
|
||||
@@ -377,15 +391,19 @@ impl<T: Config> EventDetails<T> {
|
||||
.iter()
|
||||
.map(|f| scale_decode::Field::new(f.ty.id, f.name.as_deref()));
|
||||
|
||||
let decoded =
|
||||
scale_value::scale::decode_as_fields(bytes, &mut fields, self.metadata.types())?;
|
||||
let decoded = E::decode_as_fields(bytes, &mut fields, self.metadata.types())
|
||||
.map_err(|e| EventsError::CannotDecodeEventFields {
|
||||
pallet_name: event_metadata.pallet.name().to_string(),
|
||||
event_name: event_metadata.variant.name.clone(),
|
||||
reason: e
|
||||
})?;
|
||||
|
||||
Ok(decoded)
|
||||
}
|
||||
|
||||
/// Attempt to decode these [`EventDetails`] into a type representing the event fields.
|
||||
/// Such types are exposed in the codegen as `pallet_name::events::EventName` types.
|
||||
pub fn as_event<E: StaticEvent>(&self) -> Result<Option<E>, Error> {
|
||||
pub fn as_event<E: StaticEvent>(&self) -> Result<Option<E>, EventsError> {
|
||||
let ev_metadata = self.event_metadata();
|
||||
if ev_metadata.pallet.name() == E::PALLET && ev_metadata.variant.name == E::EVENT {
|
||||
let mut fields = ev_metadata
|
||||
@@ -394,7 +412,12 @@ impl<T: Config> EventDetails<T> {
|
||||
.iter()
|
||||
.map(|f| scale_decode::Field::new(f.ty.id, f.name.as_deref()));
|
||||
let decoded =
|
||||
E::decode_as_fields(&mut self.field_bytes(), &mut fields, self.metadata.types())?;
|
||||
E::decode_as_fields(&mut self.field_bytes(), &mut fields, self.metadata.types())
|
||||
.map_err(|e| EventsError::CannotDecodeEventFields {
|
||||
pallet_name: E::PALLET.to_string(),
|
||||
event_name: E::EVENT.to_string(),
|
||||
reason: e
|
||||
})?;
|
||||
Ok(Some(decoded))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -404,14 +427,21 @@ 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: DecodeAsType>(&self) -> Result<E, Error> {
|
||||
pub fn as_root_event<E: DecodeAsType>(&self) -> Result<E, EventsError> {
|
||||
let bytes = &self.all_bytes[self.event_start_idx..self.event_fields_end_idx];
|
||||
|
||||
let decoded = E::decode_as_type(
|
||||
&mut &bytes[..],
|
||||
self.metadata.outer_enums().event_enum_ty(),
|
||||
self.metadata.types(),
|
||||
)?;
|
||||
).map_err(|e| {
|
||||
let md = self.event_metadata();
|
||||
EventsError::CannotDecodeEventEnum {
|
||||
pallet_name: md.pallet.name().to_string(),
|
||||
event_name: md.variant.name.clone(),
|
||||
reason: e
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(decoded)
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ pub mod ext {
|
||||
pub use scale_value;
|
||||
}
|
||||
|
||||
/// Re-exports the [`subxt_metadata::Metadata`] type.
|
||||
pub mod metadata {
|
||||
pub use subxt_metadata::Metadata;
|
||||
}
|
||||
+17
-10
@@ -43,32 +43,39 @@
|
||||
|
||||
pub mod payload;
|
||||
|
||||
use crate::error::{RuntimeApiError, MetadataError};
|
||||
use crate::error::RuntimeApiError;
|
||||
use crate::metadata::Metadata;
|
||||
use alloc::format;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use payload::Payload;
|
||||
use scale_decode::IntoVisitor;
|
||||
|
||||
/// Run the validation logic against some runtime API payload you'd like to use. Returns `Ok(())`
|
||||
/// 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
|
||||
/// the runtime API in question do not exist at all)
|
||||
pub fn validate<P: Payload>(payload: &P, metadata: &Metadata) -> Result<(), RuntimeApiError> {
|
||||
let Some(static_hash) = payload.validation_hash() else {
|
||||
let Some(hash) = payload.validation_hash() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let api_trait = metadata.runtime_api_trait_by_name_err(payload.trait_name())?;
|
||||
let Some(api_method) = api_trait.method_by_name(payload.method_name()) else {
|
||||
return Err(MetadataError::IncompatibleCodegen.into());
|
||||
};
|
||||
let trait_name = payload.trait_name();
|
||||
let method_name = payload.method_name();
|
||||
|
||||
let runtime_hash = api_method.hash();
|
||||
if static_hash != runtime_hash {
|
||||
return Err(MetadataError::IncompatibleCodegen.into());
|
||||
let api_trait = metadata.runtime_api_trait_by_name(trait_name)
|
||||
.ok_or_else(|| RuntimeApiError::TraitNotFound(trait_name.to_string()))?;
|
||||
let api_method = api_trait.method_by_name(method_name)
|
||||
.ok_or_else(|| RuntimeApiError::MethodNotFound {
|
||||
trait_name: trait_name.to_string(),
|
||||
method_name: method_name.to_string()
|
||||
})?;
|
||||
|
||||
if hash != api_method.hash() {
|
||||
Err(RuntimeApiError::IncompatibleCodegen)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the name of the runtime API call from the payload.
|
||||
|
||||
@@ -82,8 +82,8 @@ impl<ArgsType, ReturnTy> StaticPayload<ArgsType, ReturnTy> {
|
||||
args: ArgsType,
|
||||
) -> Self {
|
||||
StaticPayload {
|
||||
trait_name: Cow::Owned(trait_name.into()),
|
||||
method_name: Cow::Owned(method_name.into()),
|
||||
trait_name: trait_name.into(),
|
||||
method_name: method_name.into(),
|
||||
args,
|
||||
validation_hash: None,
|
||||
_marker: PhantomData,
|
||||
|
||||
@@ -92,7 +92,7 @@ pub fn get_address_bytes<Addr: Address, Keys: EqualOrPrefixOf<Addr::KeyParts>>(
|
||||
address.pallet_name(),
|
||||
address.entry_name(),
|
||||
&keys,
|
||||
&**metadata,
|
||||
metadata,
|
||||
metadata.types(),
|
||||
)
|
||||
.map_err(|e| StorageError::StorageKeyEncodeError(e).into())
|
||||
@@ -120,7 +120,7 @@ pub fn decode_value<Addr: Address>(
|
||||
address.pallet_name(),
|
||||
address.entry_name(),
|
||||
bytes,
|
||||
&**metadata,
|
||||
metadata,
|
||||
metadata.types(),
|
||||
Addr::Value::into_visitor(),
|
||||
)
|
||||
@@ -135,6 +135,7 @@ pub fn default_value<Addr: Address>(
|
||||
let storage_info = metadata
|
||||
.storage_info(address.pallet_name(), address.entry_name())
|
||||
.map_err(|e| StorageError::StorageInfoError(e.into_owned()))?;
|
||||
|
||||
let value = frame_decode::storage::decode_default_storage_value_with_info(
|
||||
&storage_info,
|
||||
metadata.types(),
|
||||
|
||||
+30
-20
@@ -60,10 +60,10 @@ pub mod payload;
|
||||
pub mod signer;
|
||||
|
||||
use crate::config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder, HashFor, Hasher};
|
||||
use crate::error::{Error, ExtrinsicError, MetadataError};
|
||||
use crate::error::ExtrinsicError;
|
||||
use crate::metadata::Metadata;
|
||||
use crate::utils::Encoded;
|
||||
use alloc::borrow::{Cow, ToOwned};
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::vec::Vec;
|
||||
use codec::{Compact, Encode};
|
||||
use payload::Payload;
|
||||
@@ -77,18 +77,28 @@ pub use crate::client::{ClientState, RuntimeVersion};
|
||||
/// if the call is valid (or if it's not possible to check since the call has no validation hash).
|
||||
/// Return an error if the call was not valid or something went wrong trying to validate it (ie
|
||||
/// the pallet or call in question do not exist at all).
|
||||
pub fn validate<Call: Payload>(call: &Call, metadata: &Metadata) -> Result<(), Error> {
|
||||
if let Some(details) = call.validation_details() {
|
||||
let expected_hash = metadata
|
||||
.pallet_by_name_err(details.pallet_name)?
|
||||
.call_hash(details.call_name)
|
||||
.ok_or_else(|| MetadataError::CallNameNotFound(details.call_name.to_owned()))?;
|
||||
pub fn validate<Call: Payload>(call: &Call, metadata: &Metadata) -> Result<(), ExtrinsicError> {
|
||||
let Some(details) = call.validation_details() else {
|
||||
return Ok(())
|
||||
};
|
||||
|
||||
if details.hash != expected_hash {
|
||||
return Err(MetadataError::IncompatibleCodegen.into());
|
||||
}
|
||||
let pallet_name = details.pallet_name;
|
||||
let call_name = details.call_name;
|
||||
|
||||
let expected_hash = metadata
|
||||
.pallet_by_name(pallet_name)
|
||||
.ok_or_else(|| ExtrinsicError::PalletNameNotFound(pallet_name.to_string()))?
|
||||
.call_hash(call_name)
|
||||
.ok_or_else(|| ExtrinsicError::CallNameNotFound {
|
||||
pallet_name: pallet_name.to_string(),
|
||||
call_name: call_name.to_string()
|
||||
})?;
|
||||
|
||||
if details.hash != expected_hash {
|
||||
Err(ExtrinsicError::IncompatibleCodegen)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the suggested transaction versions to build for a given chain, or an error
|
||||
@@ -96,7 +106,7 @@ pub fn validate<Call: Payload>(call: &Call, metadata: &Metadata) -> Result<(), E
|
||||
///
|
||||
/// If the result is [`TransactionVersion::V4`], use the `v4` methods in this module. If it's
|
||||
/// [`TransactionVersion::V5`], use the `v5` ones.
|
||||
pub fn suggested_version(metadata: &Metadata) -> Result<TransactionVersion, Error> {
|
||||
pub fn suggested_version(metadata: &Metadata) -> Result<TransactionVersion, ExtrinsicError> {
|
||||
let versions = metadata.extrinsic().supported_versions();
|
||||
|
||||
if versions.contains(&4) {
|
||||
@@ -104,7 +114,7 @@ pub fn suggested_version(metadata: &Metadata) -> Result<TransactionVersion, Erro
|
||||
} else if versions.contains(&5) {
|
||||
Ok(TransactionVersion::V5)
|
||||
} else {
|
||||
Err(ExtrinsicError::UnsupportedVersion.into())
|
||||
Err(ExtrinsicError::UnsupportedVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +128,7 @@ pub enum TransactionVersion {
|
||||
}
|
||||
|
||||
/// Return the SCALE encoded bytes representing the call data of the transaction.
|
||||
pub fn call_data<Call: Payload>(call: &Call, metadata: &Metadata) -> Result<Vec<u8>, Error> {
|
||||
pub fn call_data<Call: Payload>(call: &Call, metadata: &Metadata) -> Result<Vec<u8>, ExtrinsicError> {
|
||||
let mut bytes = Vec::new();
|
||||
call.encode_call_data_to(metadata, &mut bytes)?;
|
||||
Ok(bytes)
|
||||
@@ -128,7 +138,7 @@ pub fn call_data<Call: Payload>(call: &Call, metadata: &Metadata) -> Result<Vec<
|
||||
pub fn create_v4_unsigned<T: Config, Call: Payload>(
|
||||
call: &Call,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Transaction<T>, Error> {
|
||||
) -> Result<Transaction<T>, ExtrinsicError> {
|
||||
create_unsigned_at_version(call, 4, metadata)
|
||||
}
|
||||
|
||||
@@ -136,7 +146,7 @@ pub fn create_v4_unsigned<T: Config, Call: Payload>(
|
||||
pub fn create_v5_bare<T: Config, Call: Payload>(
|
||||
call: &Call,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Transaction<T>, Error> {
|
||||
) -> Result<Transaction<T>, ExtrinsicError> {
|
||||
create_unsigned_at_version(call, 5, metadata)
|
||||
}
|
||||
|
||||
@@ -145,7 +155,7 @@ fn create_unsigned_at_version<T: Config, Call: Payload>(
|
||||
call: &Call,
|
||||
tx_version: u8,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Transaction<T>, Error> {
|
||||
) -> Result<Transaction<T>, ExtrinsicError> {
|
||||
// 1. Validate this call against the current node metadata if the call comes
|
||||
// with a hash allowing us to do so.
|
||||
validate(call, metadata)?;
|
||||
@@ -176,7 +186,7 @@ pub fn create_v4_signed<T: Config, Call: Payload>(
|
||||
call: &Call,
|
||||
client_state: &ClientState<T>,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<PartialTransactionV4<T>, Error> {
|
||||
) -> Result<PartialTransactionV4<T>, ExtrinsicError> {
|
||||
// 1. Validate this call against the current node metadata if the call comes
|
||||
// with a hash allowing us to do so.
|
||||
validate(call, &client_state.metadata)?;
|
||||
@@ -200,7 +210,7 @@ pub fn create_v5_general<T: Config, Call: Payload>(
|
||||
call: &Call,
|
||||
client_state: &ClientState<T>,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<PartialTransactionV5<T>, Error> {
|
||||
) -> Result<PartialTransactionV5<T>, ExtrinsicError> {
|
||||
// 1. Validate this call against the current node metadata if the call comes
|
||||
// with a hash allowing us to do so.
|
||||
validate(call, &client_state.metadata)?;
|
||||
|
||||
+15
-11
@@ -5,10 +5,9 @@
|
||||
//! This module contains the trait and types used to represent
|
||||
//! transactions that can be submitted.
|
||||
|
||||
use crate::Error;
|
||||
use crate::error::MetadataError;
|
||||
use crate::error::ExtrinsicError;
|
||||
use crate::metadata::Metadata;
|
||||
use alloc::borrow::{Cow, ToOwned};
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
|
||||
@@ -21,11 +20,11 @@ use scale_value::{Composite, Value, ValueDef, Variant};
|
||||
/// to a node.
|
||||
pub trait Payload {
|
||||
/// Encode call data to the provided output.
|
||||
fn encode_call_data_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), Error>;
|
||||
fn encode_call_data_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), ExtrinsicError>;
|
||||
|
||||
/// Encode call data and return the output. This is a convenience
|
||||
/// wrapper around [`Payload::encode_call_data_to`].
|
||||
fn encode_call_data(&self, metadata: &Metadata) -> Result<Vec<u8>, Error> {
|
||||
fn encode_call_data(&self, metadata: &Metadata) -> Result<Vec<u8>, ExtrinsicError> {
|
||||
let mut v = Vec::new();
|
||||
self.encode_call_data_to(metadata, &mut v)?;
|
||||
Ok(v)
|
||||
@@ -46,10 +45,10 @@ macro_rules! boxed_payload {
|
||||
&self,
|
||||
metadata: &Metadata,
|
||||
out: &mut Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), ExtrinsicError> {
|
||||
self.as_ref().encode_call_data_to(metadata, out)
|
||||
}
|
||||
fn encode_call_data(&self, metadata: &Metadata) -> Result<Vec<u8>, Error> {
|
||||
fn encode_call_data(&self, metadata: &Metadata) -> Result<Vec<u8>, ExtrinsicError> {
|
||||
self.as_ref().encode_call_data(metadata)
|
||||
}
|
||||
fn validation_details(&self) -> Option<ValidationDetails<'_>> {
|
||||
@@ -164,11 +163,15 @@ impl DefaultPayload<Composite<()>> {
|
||||
}
|
||||
|
||||
impl<CallData: EncodeAsFields> Payload for DefaultPayload<CallData> {
|
||||
fn encode_call_data_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), Error> {
|
||||
let pallet = metadata.pallet_by_name_err(&self.pallet_name)?;
|
||||
fn encode_call_data_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), ExtrinsicError> {
|
||||
let pallet = metadata.pallet_by_name(&self.pallet_name)
|
||||
.ok_or_else(|| ExtrinsicError::PalletNameNotFound(self.pallet_name.to_string()))?;
|
||||
let call = pallet
|
||||
.call_variant_by_name(&self.call_name)
|
||||
.ok_or_else(|| MetadataError::CallNameNotFound((*self.call_name).to_owned()))?;
|
||||
.ok_or_else(|| ExtrinsicError::CallNameNotFound {
|
||||
pallet_name: pallet.name().to_string(),
|
||||
call_name: self.call_name.to_string()
|
||||
})?;
|
||||
|
||||
let pallet_index = pallet.index();
|
||||
let call_index = call.index;
|
||||
@@ -182,7 +185,8 @@ impl<CallData: EncodeAsFields> Payload for DefaultPayload<CallData> {
|
||||
.map(|f| scale_encode::Field::new(f.ty.id, f.name.as_deref()));
|
||||
|
||||
self.call_data
|
||||
.encode_as_fields_to(&mut fields, metadata.types(), out)?;
|
||||
.encode_as_fields_to(&mut fields, metadata.types(), out)
|
||||
.map_err(ExtrinsicError::CannotEncodeCallData)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -7,28 +7,37 @@
|
||||
|
||||
pub mod payload;
|
||||
|
||||
use crate::error::{Error, MetadataError};
|
||||
use crate::metadata::{DecodeWithMetadata, Metadata};
|
||||
use crate::error::ViewFunctionError;
|
||||
use crate::metadata::Metadata;
|
||||
use alloc::vec::Vec;
|
||||
use payload::Payload;
|
||||
use scale_decode::IntoVisitor;
|
||||
|
||||
/// Run the validation logic against some View Function payload you'd like to use. Returns `Ok(())`
|
||||
/// 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
|
||||
/// the View Function in question do not exist at all)
|
||||
pub fn validate<P: Payload>(payload: &P, metadata: &Metadata) -> Result<(), Error> {
|
||||
let Some(static_hash) = payload.validation_hash() else {
|
||||
pub fn validate<P: Payload>(payload: &P, metadata: &Metadata) -> Result<(), ViewFunctionError> {
|
||||
let Some(hash) = payload.validation_hash() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let view_function = metadata
|
||||
.view_function_by_query_id(payload.query_id())
|
||||
.ok_or_else(|| MetadataError::ViewFunctionNotFound(*payload.query_id()))?;
|
||||
if static_hash != view_function.hash() {
|
||||
return Err(MetadataError::IncompatibleCodegen.into());
|
||||
}
|
||||
let pallet_name = payload.pallet_name();
|
||||
let function_name = payload.function_name();
|
||||
|
||||
Ok(())
|
||||
let view_function = metadata.pallet_by_name(pallet_name)
|
||||
.ok_or_else(|| ViewFunctionError::PalletNotFound(pallet_name.to_string()))?
|
||||
.view_function_by_name(function_name)
|
||||
.ok_or_else(|| ViewFunctionError::ViewFunctionNotFound {
|
||||
pallet_name: pallet_name.to_string(),
|
||||
function_name: function_name.to_string()
|
||||
})?;
|
||||
|
||||
if hash != view_function.hash() {
|
||||
Err(ViewFunctionError::IncompatibleCodegen)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of the Runtime API call which can execute
|
||||
@@ -36,17 +45,16 @@ pub const CALL_NAME: &str = "RuntimeViewFunction_execute_view_function";
|
||||
|
||||
/// Encode the bytes that will be passed to the "execute_view_function" Runtime API call,
|
||||
/// to execute the View Function represented by the given payload.
|
||||
pub fn call_args<P: Payload>(payload: &P, metadata: &Metadata) -> Result<Vec<u8>, Error> {
|
||||
let mut call_args = Vec::with_capacity(32);
|
||||
call_args.extend_from_slice(payload.query_id());
|
||||
pub fn call_args<P: Payload>(payload: &P, metadata: &Metadata) -> Result<Vec<u8>, ViewFunctionError> {
|
||||
let inputs = frame_decode::view_functions::encode_view_function_inputs(
|
||||
payload.pallet_name(),
|
||||
payload.function_name(),
|
||||
payload.args(),
|
||||
metadata,
|
||||
metadata.types()
|
||||
).map_err(ViewFunctionError::CouldNotEncodeInputs)?;
|
||||
|
||||
let mut call_arg_params = Vec::new();
|
||||
payload.encode_args_to(metadata, &mut call_arg_params)?;
|
||||
|
||||
use codec::Encode;
|
||||
call_arg_params.encode_to(&mut call_args);
|
||||
|
||||
Ok(call_args)
|
||||
Ok(inputs)
|
||||
}
|
||||
|
||||
/// Decode the value bytes at the location given by the provided View Function payload.
|
||||
@@ -54,16 +62,15 @@ pub fn decode_value<P: Payload>(
|
||||
bytes: &mut &[u8],
|
||||
payload: &P,
|
||||
metadata: &Metadata,
|
||||
) -> Result<P::ReturnType, Error> {
|
||||
let view_function = metadata
|
||||
.view_function_by_query_id(payload.query_id())
|
||||
.ok_or_else(|| MetadataError::ViewFunctionNotFound(*payload.query_id()))?;
|
||||
|
||||
let val = <P::ReturnType as DecodeWithMetadata>::decode_with_metadata(
|
||||
&mut &bytes[..],
|
||||
view_function.output_ty(),
|
||||
) -> Result<P::ReturnType, ViewFunctionError> {
|
||||
let value = frame_decode::view_functions::decode_view_function_response(
|
||||
payload.pallet_name(),
|
||||
payload.function_name(),
|
||||
bytes,
|
||||
metadata,
|
||||
)?;
|
||||
metadata.types(),
|
||||
P::ReturnType::into_visitor()
|
||||
).map_err(ViewFunctionError::CouldNotDecodeResponse)?;
|
||||
|
||||
Ok(val)
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
@@ -5,17 +5,11 @@
|
||||
//! This module contains the trait and types used to represent
|
||||
//! View Function calls that can be made.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
use derive_where::derive_where;
|
||||
use scale_encode::EncodeAsFields;
|
||||
use scale_value::Composite;
|
||||
|
||||
use crate::Error;
|
||||
use crate::dynamic::DecodedValueThunk;
|
||||
use crate::error::MetadataError;
|
||||
|
||||
use crate::metadata::{DecodeWithMetadata, Metadata};
|
||||
use scale_decode::DecodeAsType;
|
||||
use frame_decode::view_functions::IntoEncodableValues;
|
||||
use alloc::borrow::Cow;
|
||||
|
||||
/// This represents a View Function payload that can call into the runtime of node.
|
||||
///
|
||||
@@ -33,24 +27,19 @@ use crate::metadata::{DecodeWithMetadata, Metadata};
|
||||
///
|
||||
/// Each argument of the View Function must be scale-encoded.
|
||||
pub trait Payload {
|
||||
/// Type of the arguments for this call.
|
||||
type ArgsType: IntoEncodableValues;
|
||||
/// The return type of the function call.
|
||||
// Note: `DecodeWithMetadata` is needed to decode the function call result
|
||||
// with the `subxt::Metadata.
|
||||
type ReturnType: DecodeWithMetadata;
|
||||
type ReturnType: DecodeAsType;
|
||||
|
||||
/// The payload target.
|
||||
fn query_id(&self) -> &[u8; 32];
|
||||
/// The View Function pallet name.
|
||||
fn pallet_name(&self) -> &str;
|
||||
|
||||
/// Scale encode the arguments data.
|
||||
fn encode_args_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), Error>;
|
||||
/// The View Function function name.
|
||||
fn function_name(&self) -> &str;
|
||||
|
||||
/// 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)
|
||||
}
|
||||
/// The arguments.
|
||||
fn args(&self) -> &Self::ArgsType;
|
||||
|
||||
/// Returns the statically generated validation hash.
|
||||
fn validation_hash(&self) -> Option<[u8; 32]> {
|
||||
@@ -59,44 +48,38 @@ pub trait Payload {
|
||||
}
|
||||
|
||||
/// A View Function payload containing the generic argument data
|
||||
/// and interpreting the result of the call as `ReturnTy`.
|
||||
/// and interpreting the result of the call as `ReturnType`.
|
||||
///
|
||||
/// This can be created from static values (ie those generated
|
||||
/// via the `subxt` macro) or dynamic values via [`dynamic`].
|
||||
#[derive_where(Clone, Debug, Eq, Ord, PartialEq, PartialOrd; ArgsData)]
|
||||
pub struct DefaultPayload<ArgsData, ReturnTy> {
|
||||
query_id: [u8; 32],
|
||||
args_data: ArgsData,
|
||||
#[derive_where(Clone, Debug, Eq, Ord, PartialEq, PartialOrd; ArgsType)]
|
||||
pub struct StaticPayload<ArgsType, ReturnType> {
|
||||
pallet_name: Cow<'static, str>,
|
||||
function_name: Cow<'static, str>,
|
||||
args: ArgsType,
|
||||
validation_hash: Option<[u8; 32]>,
|
||||
_marker: PhantomData<ReturnTy>,
|
||||
_marker: PhantomData<ReturnType>,
|
||||
}
|
||||
|
||||
/// A statically generated View Function payload.
|
||||
pub type StaticPayload<ArgsData, ReturnTy> = DefaultPayload<ArgsData, ReturnTy>;
|
||||
/// A dynamic View Function payload.
|
||||
pub type DynamicPayload = DefaultPayload<Composite<()>, DecodedValueThunk>;
|
||||
pub type DynamicPayload<ArgsType, ReturnType> = StaticPayload<ArgsType, ReturnType>;
|
||||
|
||||
impl<ArgsData: EncodeAsFields, ReturnTy: DecodeWithMetadata> Payload
|
||||
for DefaultPayload<ArgsData, ReturnTy>
|
||||
impl<ArgsType: IntoEncodableValues, ReturnType: DecodeAsType> Payload
|
||||
for StaticPayload<ArgsType, ReturnType>
|
||||
{
|
||||
type ReturnType = ReturnTy;
|
||||
type ArgsType = ArgsType;
|
||||
type ReturnType = ReturnType;
|
||||
|
||||
fn query_id(&self) -> &[u8; 32] {
|
||||
&self.query_id
|
||||
fn pallet_name(&self) -> &str {
|
||||
&self.pallet_name
|
||||
}
|
||||
|
||||
fn encode_args_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), Error> {
|
||||
let view_function = metadata
|
||||
.view_function_by_query_id(&self.query_id)
|
||||
.ok_or(MetadataError::ViewFunctionNotFound(self.query_id))?;
|
||||
let mut fields = view_function
|
||||
.inputs()
|
||||
.map(|input| scale_encode::Field::named(input.id, &input.name));
|
||||
fn function_name(&self) -> &str {
|
||||
&self.function_name
|
||||
}
|
||||
|
||||
self.args_data
|
||||
.encode_as_fields_to(&mut fields, metadata.types(), out)?;
|
||||
|
||||
Ok(())
|
||||
fn args(&self) -> &Self::ArgsType {
|
||||
&self.args
|
||||
}
|
||||
|
||||
fn validation_hash(&self) -> Option<[u8; 32]> {
|
||||
@@ -104,30 +87,37 @@ impl<ArgsData: EncodeAsFields, ReturnTy: DecodeWithMetadata> Payload
|
||||
}
|
||||
}
|
||||
|
||||
impl<ReturnTy, ArgsData> DefaultPayload<ArgsData, ReturnTy> {
|
||||
/// Create a new [`DefaultPayload`] for a View Function call.
|
||||
pub fn new(query_id: [u8; 32], args_data: ArgsData) -> Self {
|
||||
DefaultPayload {
|
||||
query_id,
|
||||
args_data,
|
||||
impl<ReturnTy, ArgsType> StaticPayload<ArgsType, ReturnTy> {
|
||||
/// Create a new [`StaticPayload`] for a View Function call.
|
||||
pub fn new(
|
||||
pallet_name: impl Into<Cow<'static, str>>,
|
||||
function_name: impl Into<Cow<'static, str>>,
|
||||
args: ArgsType,
|
||||
) -> Self {
|
||||
StaticPayload {
|
||||
pallet_name: pallet_name.into(),
|
||||
function_name: function_name.into(),
|
||||
args,
|
||||
validation_hash: None,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new static [`DefaultPayload`] for a View Function call
|
||||
/// Create a new static [`StaticPayload`] for a View Function call
|
||||
/// using static function name and scale-encoded argument data.
|
||||
///
|
||||
/// This is only expected to be used from codegen.
|
||||
#[doc(hidden)]
|
||||
pub fn new_static(
|
||||
query_id: [u8; 32],
|
||||
args_data: ArgsData,
|
||||
pallet_name: &'static str,
|
||||
function_name: &'static str,
|
||||
args: ArgsType,
|
||||
hash: [u8; 32],
|
||||
) -> DefaultPayload<ArgsData, ReturnTy> {
|
||||
DefaultPayload {
|
||||
query_id,
|
||||
args_data,
|
||||
) -> StaticPayload<ArgsType, ReturnTy> {
|
||||
StaticPayload {
|
||||
pallet_name: Cow::Borrowed(pallet_name),
|
||||
function_name: Cow::Borrowed(function_name),
|
||||
args,
|
||||
validation_hash: Some(hash),
|
||||
_marker: core::marker::PhantomData,
|
||||
}
|
||||
@@ -140,14 +130,13 @@ impl<ReturnTy, ArgsData> DefaultPayload<ArgsData, ReturnTy> {
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the arguments data.
|
||||
pub fn args_data(&self) -> &ArgsData {
|
||||
&self.args_data
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`DynamicPayload`] to call a View Function.
|
||||
pub fn dynamic(query_id: [u8; 32], args_data: impl Into<Composite<()>>) -> DynamicPayload {
|
||||
DefaultPayload::new(query_id, args_data.into())
|
||||
pub fn dynamic<ArgsType, ReturnType>(
|
||||
pallet_name: impl Into<Cow<'static, str>>,
|
||||
function_name: impl Into<Cow<'static, str>>,
|
||||
args: ArgsType
|
||||
) -> DynamicPayload<ArgsType, ReturnType> {
|
||||
DynamicPayload::new(pallet_name, function_name, args)
|
||||
}
|
||||
|
||||
@@ -395,20 +395,6 @@ impl Metadata {
|
||||
})
|
||||
}
|
||||
|
||||
/// Access a view function given its query ID, if any.
|
||||
pub fn view_function_by_query_id(
|
||||
&'_ self,
|
||||
query_id: &[u8; 32],
|
||||
) -> Option<ViewFunctionMetadata<'_>> {
|
||||
// Dev note: currently, we only have pallet view functions, and here
|
||||
// we just do a naive thing of iterating over the pallets to find the one
|
||||
// we're looking for. Eventually we should construct a separate map of view
|
||||
// functions for easy querying here.
|
||||
self.pallets()
|
||||
.flat_map(|p| p.view_functions())
|
||||
.find(|vf| vf.query_id() == query_id)
|
||||
}
|
||||
|
||||
/// Returns custom user defined types
|
||||
pub fn custom(&self) -> CustomMetadata<'_> {
|
||||
CustomMetadata {
|
||||
|
||||
Reference in New Issue
Block a user