mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-19 07:35:41 +00:00
Metadata V16: Implement support for Pallet View Functions (#1981)
* Support Pallet View Functions in Subxt * fmt * clippy * Move a little view function logic to subxt_core * clippy * Add back check that prob isnt needed * avoid vec macro in core * Add view funciton test and apply various fixes to get it working * Add test for dynamic view fn call and fix issues * clippy * fix test-runtime * fmt * remove export * avoid vec for nostd core * use const instead of fn for view fn call name * Update to support latest unstable metadata * Update metadata stripping tests for new v16 version
This commit is contained in:
@@ -68,7 +68,7 @@ impl TryFrom<v14::RuntimeMetadataV14> for Metadata {
|
||||
error_ty: p.error.map(|e| e.ty.id),
|
||||
error_variant_index,
|
||||
constants: constants.collect(),
|
||||
view_functions: vec![],
|
||||
view_functions: Default::default(),
|
||||
associated_types: Default::default(),
|
||||
docs: vec![],
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@ impl TryFrom<v15::RuntimeMetadataV15> for Metadata {
|
||||
error_ty: p.error.map(|e| e.ty.id),
|
||||
error_variant_index,
|
||||
constants: constants.collect(),
|
||||
view_functions: vec![],
|
||||
view_functions: Default::default(),
|
||||
associated_types: Default::default(),
|
||||
docs: p.docs,
|
||||
},
|
||||
|
||||
+16
-12
@@ -7,10 +7,9 @@ use super::TryFromError;
|
||||
use crate::utils::variant_index::VariantIndex;
|
||||
use crate::{
|
||||
utils::ordered_map::OrderedMap, ArcStr, ConstantMetadata, ExtrinsicMetadata, Metadata,
|
||||
MethodParamMetadata, OuterEnumsMetadata, PalletMetadataInner, PalletViewFunctionMetadataInner,
|
||||
RuntimeApiMetadataInner, RuntimeApiMethodMetadataInner, StorageEntryMetadata,
|
||||
StorageEntryModifier, StorageEntryType, StorageHasher, StorageMetadata,
|
||||
TransactionExtensionMetadataInner,
|
||||
MethodParamMetadata, OuterEnumsMetadata, PalletMetadataInner, RuntimeApiMetadataInner,
|
||||
RuntimeApiMethodMetadataInner, StorageEntryMetadata, StorageEntryModifier, StorageEntryType,
|
||||
StorageHasher, StorageMetadata, TransactionExtensionMetadataInner, ViewFunctionMetadataInner,
|
||||
};
|
||||
use frame_metadata::{v15, v16};
|
||||
use hashbrown::HashMap;
|
||||
@@ -41,10 +40,10 @@ impl TryFrom<v16::RuntimeMetadataV16> for Metadata {
|
||||
let name: ArcStr = c.name.clone().into();
|
||||
(name.clone(), from_constant_metadata(name, c))
|
||||
});
|
||||
let view_functions = p
|
||||
.view_functions
|
||||
.into_iter()
|
||||
.map(from_view_function_metadata);
|
||||
let view_functions = p.view_functions.into_iter().map(|v| {
|
||||
let name: ArcStr = v.name.clone().into();
|
||||
(name.clone(), from_view_function_metadata(name, v))
|
||||
});
|
||||
|
||||
let call_variant_index = VariantIndex::build(p.calls.as_ref().map(|c| c.ty.id), &types);
|
||||
let error_variant_index =
|
||||
@@ -133,7 +132,11 @@ fn from_transaction_extension_metadata(
|
||||
fn from_extrinsic_metadata(value: v16::ExtrinsicMetadata<PortableForm>) -> ExtrinsicMetadata {
|
||||
ExtrinsicMetadata {
|
||||
supported_versions: value.versions,
|
||||
transaction_extensions_by_version: value.transaction_extensions_by_version,
|
||||
transaction_extensions_by_version: value
|
||||
.transaction_extensions_by_version
|
||||
.into_iter()
|
||||
.map(|(version, idxs)| (version, idxs.into_iter().map(|idx| idx.0).collect()))
|
||||
.collect(),
|
||||
transaction_extensions: value
|
||||
.transaction_extensions
|
||||
.into_iter()
|
||||
@@ -241,10 +244,11 @@ fn from_runtime_api_method_metadata(
|
||||
}
|
||||
|
||||
fn from_view_function_metadata(
|
||||
name: ArcStr,
|
||||
s: v16::PalletViewFunctionMetadata<PortableForm>,
|
||||
) -> PalletViewFunctionMetadataInner {
|
||||
PalletViewFunctionMetadataInner {
|
||||
name: s.name,
|
||||
) -> ViewFunctionMetadataInner {
|
||||
ViewFunctionMetadataInner {
|
||||
name,
|
||||
query_id: s.id,
|
||||
inputs: s
|
||||
.inputs
|
||||
|
||||
+53
-14
@@ -216,6 +216,20 @@ 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 {
|
||||
@@ -293,12 +307,29 @@ impl<'a> PalletMetadata<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Does this pallet have any view functions?
|
||||
pub fn has_view_functions(&self) -> bool {
|
||||
!self.inner.view_functions.is_empty()
|
||||
}
|
||||
|
||||
/// Return an iterator over the View Functions in this pallet, if any.
|
||||
pub fn view_functions(&self) -> impl ExactSizeIterator<Item = PalletViewFunctionMetadata<'a>> {
|
||||
pub fn view_functions(&self) -> impl ExactSizeIterator<Item = ViewFunctionMetadata<'a>> {
|
||||
self.inner
|
||||
.view_functions
|
||||
.values()
|
||||
.iter()
|
||||
.map(|vf: &'a _| PalletViewFunctionMetadata {
|
||||
.map(|vf: &'a _| ViewFunctionMetadata {
|
||||
inner: vf,
|
||||
types: self.types,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the view function with a given name, if any
|
||||
pub fn view_function_by_name(&self, name: &str) -> Option<ViewFunctionMetadata<'a>> {
|
||||
self.inner
|
||||
.view_functions
|
||||
.get_by_key(name)
|
||||
.map(|vf: &'a _| ViewFunctionMetadata {
|
||||
inner: vf,
|
||||
types: self.types,
|
||||
})
|
||||
@@ -404,7 +435,7 @@ struct PalletMetadataInner {
|
||||
/// Map from constant name to constant details.
|
||||
constants: OrderedMap<ArcStr, ConstantMetadata>,
|
||||
/// Details about each of the pallet view functions.
|
||||
view_functions: Vec<PalletViewFunctionMetadataInner>,
|
||||
view_functions: OrderedMap<ArcStr, ViewFunctionMetadataInner>,
|
||||
/// Mapping from associated type to type ID describing its shape.
|
||||
associated_types: BTreeMap<String, u32>,
|
||||
/// Pallet documentation.
|
||||
@@ -832,41 +863,48 @@ struct RuntimeApiMethodMetadataInner {
|
||||
docs: Vec<String>,
|
||||
}
|
||||
|
||||
/// Metadata for the available pallet View Functions.
|
||||
/// Metadata for the available View Functions. Currently these exist only
|
||||
/// at the pallet level, but eventually they could exist at the runtime level too.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PalletViewFunctionMetadata<'a> {
|
||||
inner: &'a PalletViewFunctionMetadataInner,
|
||||
pub struct ViewFunctionMetadata<'a> {
|
||||
inner: &'a ViewFunctionMetadataInner,
|
||||
types: &'a PortableRegistry,
|
||||
}
|
||||
|
||||
impl PalletViewFunctionMetadata<'_> {
|
||||
impl<'a> ViewFunctionMetadata<'a> {
|
||||
/// Method name.
|
||||
pub fn name(&self) -> &str {
|
||||
pub fn name(&self) -> &'a str {
|
||||
&self.inner.name
|
||||
}
|
||||
/// Query ID. This is used to query the function. Roughly, it is constructed by doing
|
||||
/// `twox_128(pallet_name) ++ twox_128("fn_name(fnarg_types) -> return_ty")` .
|
||||
pub fn query_id(&self) -> [u8; 32] {
|
||||
self.inner.query_id
|
||||
pub fn query_id(&self) -> &'a [u8; 32] {
|
||||
&self.inner.query_id
|
||||
}
|
||||
/// Method documentation.
|
||||
pub fn docs(&self) -> &[String] {
|
||||
pub fn docs(&self) -> &'a [String] {
|
||||
&self.inner.docs
|
||||
}
|
||||
/// Method inputs.
|
||||
pub fn inputs(&self) -> impl ExactSizeIterator<Item = &MethodParamMetadata> {
|
||||
pub fn inputs(&self) -> impl ExactSizeIterator<Item = &'a MethodParamMetadata> {
|
||||
self.inner.inputs.iter()
|
||||
}
|
||||
/// Method return type.
|
||||
pub fn output_ty(&self) -> u32 {
|
||||
self.inner.output_ty
|
||||
}
|
||||
/// Return a hash for the method. The query ID of a view function validates it to some
|
||||
/// degree, but only takes type _names_ into account. This hash takes into account the
|
||||
/// actual _shape_ of each argument and the return type.
|
||||
pub fn hash(&self) -> [u8; HASH_LEN] {
|
||||
crate::utils::validation::get_view_function_hash(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct PalletViewFunctionMetadataInner {
|
||||
struct ViewFunctionMetadataInner {
|
||||
/// View function name.
|
||||
name: String,
|
||||
name: ArcStr,
|
||||
/// View function query ID.
|
||||
query_id: [u8; 32],
|
||||
/// Input types.
|
||||
@@ -966,6 +1004,7 @@ impl codec::Decode for Metadata {
|
||||
let metadata = match metadata.1 {
|
||||
frame_metadata::RuntimeMetadata::V14(md) => md.try_into(),
|
||||
frame_metadata::RuntimeMetadata::V15(md) => md.try_into(),
|
||||
frame_metadata::RuntimeMetadata::V16(md) => md.try_into(),
|
||||
_ => return Err("Cannot try_into() to Metadata: unsupported metadata version".into()),
|
||||
};
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
use crate::{
|
||||
CustomMetadata, CustomValueMetadata, ExtrinsicMetadata, Metadata, PalletMetadata,
|
||||
PalletViewFunctionMetadata, RuntimeApiMetadata, RuntimeApiMethodMetadata, StorageEntryMetadata,
|
||||
StorageEntryType,
|
||||
RuntimeApiMetadata, RuntimeApiMethodMetadata, StorageEntryMetadata, StorageEntryType,
|
||||
ViewFunctionMetadata,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use hashbrown::HashMap;
|
||||
@@ -406,12 +406,12 @@ pub fn get_runtime_apis_hash(trait_metadata: RuntimeApiMetadata) -> Hash {
|
||||
})
|
||||
}
|
||||
|
||||
/// Obtain the hash of a specific pallet view function, or an error if it's not found.
|
||||
pub fn get_pallet_view_function_hash(view_function: &PalletViewFunctionMetadata) -> Hash {
|
||||
/// Obtain the hash of a specific view function, or an error if it's not found.
|
||||
pub fn get_view_function_hash(view_function: &ViewFunctionMetadata) -> Hash {
|
||||
let registry = view_function.types;
|
||||
|
||||
// The Query ID is `twox_128(pallet_name) ++ twox_128("fn_name(fnarg_types) -> return_ty")`.
|
||||
let mut bytes = view_function.query_id();
|
||||
let mut bytes = *view_function.query_id();
|
||||
|
||||
// This only takes type _names_ into account, so we beef this up by combining with actual
|
||||
// type hashes, in a similar approach to runtime APIs..
|
||||
@@ -439,7 +439,7 @@ fn get_pallet_view_functions_hash(pallet_metadata: &PalletMetadata) -> Hash {
|
||||
// be identical regardless. For this, we can just XOR the hashes for each method
|
||||
// together; we'll get the same output whichever order they are XOR'd together in,
|
||||
// so long as each individual method is the same.
|
||||
xor(bytes, get_pallet_view_function_hash(&method_metadata))
|
||||
xor(bytes, get_view_function_hash(&method_metadata))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user