mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-10 19:17:22 +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:
@@ -0,0 +1,14 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! Types associated with executing View Function calls.
|
||||
|
||||
mod view_function_types;
|
||||
mod view_functions_client;
|
||||
|
||||
pub use subxt_core::view_functions::payload::{
|
||||
dynamic, DefaultPayload, DynamicPayload, Payload, StaticPayload,
|
||||
};
|
||||
pub use view_function_types::ViewFunctionsApi;
|
||||
pub use view_functions_client::ViewFunctionsClient;
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::Payload;
|
||||
use crate::{
|
||||
backend::BlockRef,
|
||||
client::OnlineClientT,
|
||||
config::{Config, HashFor},
|
||||
error::Error,
|
||||
};
|
||||
use derive_where::derive_where;
|
||||
use std::{future::Future, marker::PhantomData};
|
||||
|
||||
/// Execute View Function calls.
|
||||
#[derive_where(Clone; Client)]
|
||||
pub struct ViewFunctionsApi<T: Config, Client> {
|
||||
client: Client,
|
||||
block_ref: BlockRef<HashFor<T>>,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Config, Client> ViewFunctionsApi<T, Client> {
|
||||
/// Create a new [`ViewFunctionsApi`]
|
||||
pub(crate) fn new(client: Client, block_ref: BlockRef<HashFor<T>>) -> Self {
|
||||
Self {
|
||||
client,
|
||||
block_ref,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Client> ViewFunctionsApi<T, Client>
|
||||
where
|
||||
T: Config,
|
||||
Client: OnlineClientT<T>,
|
||||
{
|
||||
/// 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<Call: Payload>(&self, payload: &Call) -> Result<(), Error> {
|
||||
subxt_core::view_functions::validate(payload, &self.client.metadata()).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Execute a View Function call.
|
||||
pub fn call<Call: Payload>(
|
||||
&self,
|
||||
payload: Call,
|
||||
) -> impl Future<Output = Result<Call::ReturnType, Error>> {
|
||||
let client = self.client.clone();
|
||||
let block_hash = self.block_ref.hash();
|
||||
// Ensure that the returned future doesn't have a lifetime tied to api.view_functions(),
|
||||
// which is a temporary thing we'll be throwing away quickly:
|
||||
async move {
|
||||
let metadata = client.metadata();
|
||||
|
||||
// Validate the View Function payload hash against the compile hash from codegen.
|
||||
subxt_core::view_functions::validate(&payload, &metadata)?;
|
||||
|
||||
// Assemble the data to call the "execute_view_function" runtime API, which
|
||||
// then calls the relevant view function.
|
||||
let call_name = subxt_core::view_functions::CALL_NAME;
|
||||
let call_args = subxt_core::view_functions::call_args(&payload, &metadata)?;
|
||||
|
||||
// Make the call.
|
||||
let bytes = client
|
||||
.backend()
|
||||
.call(call_name, Some(call_args.as_slice()), block_hash)
|
||||
.await?;
|
||||
|
||||
// Decode the response.
|
||||
let value =
|
||||
subxt_core::view_functions::decode_value(&mut &*bytes, &payload, &metadata)?;
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::view_function_types::ViewFunctionsApi;
|
||||
|
||||
use crate::{
|
||||
backend::BlockRef,
|
||||
client::OnlineClientT,
|
||||
config::{Config, HashFor},
|
||||
error::Error,
|
||||
};
|
||||
use derive_where::derive_where;
|
||||
use std::{future::Future, marker::PhantomData};
|
||||
|
||||
/// Make View Function calls at some block.
|
||||
#[derive_where(Clone; Client)]
|
||||
pub struct ViewFunctionsClient<T, Client> {
|
||||
client: Client,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, Client> ViewFunctionsClient<T, Client> {
|
||||
/// Create a new [`ViewFunctionsClient`]
|
||||
pub fn new(client: Client) -> Self {
|
||||
Self {
|
||||
client,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Client> ViewFunctionsClient<T, Client>
|
||||
where
|
||||
T: Config,
|
||||
Client: OnlineClientT<T>,
|
||||
{
|
||||
/// Obtain an interface to call View Functions at some block hash.
|
||||
pub fn at(&self, block_ref: impl Into<BlockRef<HashFor<T>>>) -> ViewFunctionsApi<T, Client> {
|
||||
ViewFunctionsApi::new(self.client.clone(), block_ref.into())
|
||||
}
|
||||
|
||||
/// Obtain an interface to call View Functions at the latest block hash.
|
||||
pub fn at_latest(
|
||||
&self,
|
||||
) -> impl Future<Output = Result<ViewFunctionsApi<T, Client>, Error>> + Send + 'static {
|
||||
// Clone and pass the client in like this so that we can explicitly
|
||||
// return a Future that's Send + 'static, rather than tied to &self.
|
||||
let client = self.client.clone();
|
||||
async move {
|
||||
// get the ref for the latest finalized block and use that.
|
||||
let block_ref = client.backend().latest_finalized_block_ref().await?;
|
||||
|
||||
Ok(ViewFunctionsApi::new(client, block_ref))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user