mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 22:51:13 +00:00
Initial rebrand from paritytech/subxt to pezkuwichain/pezkuwi-subxt
- Renamed all subxt crates to pezkuwi-subxt - Updated internal references - Configured for Pezkuwi ecosystem
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
// 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.
|
||||
|
||||
//! Encode runtime API payloads, decode the associated values returned from them, and validate
|
||||
//! static runtime API payloads.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! use pezkuwi_subxt_macro::subxt;
|
||||
//! use pezkuwi_subxt_core::runtime_api;
|
||||
//! use pezkuwi_subxt_core::Metadata;
|
||||
//!
|
||||
//! // If we generate types without `subxt`, we need to point to `::pezkuwi_subxt_core`:
|
||||
//! #[subxt(
|
||||
//! crate = "::pezkuwi_subxt_core",
|
||||
//! runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale",
|
||||
//! )]
|
||||
//! pub mod polkadot {}
|
||||
//!
|
||||
//! // Some metadata we'll use to work with storage entries:
|
||||
//! let metadata_bytes = include_bytes!("../../../artifacts/polkadot_metadata_small.scale");
|
||||
//! let metadata = Metadata::decode_from(&metadata_bytes[..]).unwrap();
|
||||
//!
|
||||
//! // Build a storage query to access account information.
|
||||
//! let payload = polkadot::apis().metadata().metadata_versions();
|
||||
//!
|
||||
//! // We can validate that the payload is compatible with the given metadata.
|
||||
//! runtime_api::validate(&payload, &metadata).unwrap();
|
||||
//!
|
||||
//! // Encode the payload name and arguments to hand to a node:
|
||||
//! let _call_name = runtime_api::call_name(&payload);
|
||||
//! let _call_args = runtime_api::call_args(&payload, &metadata).unwrap();
|
||||
//!
|
||||
//! // If we were to obtain a value back from the node, we could
|
||||
//! // then decode it using the same payload and metadata like so:
|
||||
//! let value_bytes = hex::decode("080e0000000f000000").unwrap();
|
||||
//! let value = runtime_api::decode_value(&mut &*value_bytes, &payload, &metadata).unwrap();
|
||||
//!
|
||||
//! println!("Available metadata versions: {value:?}");
|
||||
//! ```
|
||||
|
||||
pub mod payload;
|
||||
|
||||
use crate::{Metadata, error::RuntimeApiError};
|
||||
use alloc::{
|
||||
format,
|
||||
string::{String, ToString},
|
||||
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(hash) = payload.validation_hash() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let trait_name = payload.trait_name();
|
||||
let method_name = payload.method_name();
|
||||
|
||||
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(()) }
|
||||
}
|
||||
|
||||
/// Return the name of the runtime API call from the payload.
|
||||
pub fn call_name<P: Payload>(payload: P) -> String {
|
||||
format!("{}_{}", payload.trait_name(), payload.method_name())
|
||||
}
|
||||
|
||||
/// Return the encoded call args given a runtime API payload.
|
||||
pub fn call_args<P: Payload>(payload: P, metadata: &Metadata) -> Result<Vec<u8>, RuntimeApiError> {
|
||||
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.
|
||||
pub fn decode_value<P: Payload>(
|
||||
bytes: &mut &[u8],
|
||||
payload: P,
|
||||
metadata: &Metadata,
|
||||
) -> Result<P::ReturnType, RuntimeApiError> {
|
||||
let value = frame_decode::runtime_apis::decode_runtime_api_response(
|
||||
payload.trait_name(),
|
||||
payload.method_name(),
|
||||
bytes,
|
||||
metadata,
|
||||
metadata.types(),
|
||||
P::ReturnType::into_visitor(),
|
||||
)
|
||||
.map_err(RuntimeApiError::CouldNotDecodeResponse)?;
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// 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.
|
||||
|
||||
//! This module contains the trait and types used to represent
|
||||
//! runtime API calls that can be made.
|
||||
|
||||
use alloc::{borrow::Cow, string::String};
|
||||
use core::marker::PhantomData;
|
||||
use derive_where::derive_where;
|
||||
use frame_decode::runtime_apis::IntoEncodableValues;
|
||||
use scale_decode::DecodeAsType;
|
||||
|
||||
/// This represents a runtime API payload that can be used to call a Runtime API on
|
||||
/// a chain and decode the response.
|
||||
pub trait Payload {
|
||||
/// Type of the arguments.
|
||||
type ArgsType: IntoEncodableValues;
|
||||
/// The return type of the function call.
|
||||
type ReturnType: DecodeAsType;
|
||||
|
||||
/// The runtime API trait name.
|
||||
fn trait_name(&self) -> &str;
|
||||
|
||||
/// The runtime API method name.
|
||||
fn method_name(&self) -> &str;
|
||||
|
||||
/// The input arguments.
|
||||
fn args(&self) -> &Self::ArgsType;
|
||||
|
||||
/// Returns the statically generated validation hash.
|
||||
fn validation_hash(&self) -> Option<[u8; 32]> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Any reference to a payload is a valid payload.
|
||||
impl<P: Payload + ?Sized> Payload for &'_ P {
|
||||
type ArgsType = P::ArgsType;
|
||||
type ReturnType = P::ReturnType;
|
||||
|
||||
fn trait_name(&self) -> &str {
|
||||
P::trait_name(*self)
|
||||
}
|
||||
|
||||
fn method_name(&self) -> &str {
|
||||
P::method_name(*self)
|
||||
}
|
||||
|
||||
fn args(&self) -> &Self::ArgsType {
|
||||
P::args(*self)
|
||||
}
|
||||
|
||||
fn validation_hash(&self) -> Option<[u8; 32]> {
|
||||
P::validation_hash(*self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A runtime API payload containing the generic argument data
|
||||
/// and interpreting the result of the call as `ReturnTy`.
|
||||
///
|
||||
/// 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; ArgsType)]
|
||||
pub struct StaticPayload<ArgsType, ReturnType> {
|
||||
trait_name: Cow<'static, str>,
|
||||
method_name: Cow<'static, str>,
|
||||
args: ArgsType,
|
||||
validation_hash: Option<[u8; 32]>,
|
||||
_marker: PhantomData<ReturnType>,
|
||||
}
|
||||
|
||||
/// A dynamic runtime API payload.
|
||||
pub type DynamicPayload<ArgsType, ReturnType> = StaticPayload<ArgsType, ReturnType>;
|
||||
|
||||
impl<ArgsType: IntoEncodableValues, ReturnType: DecodeAsType> Payload
|
||||
for StaticPayload<ArgsType, ReturnType>
|
||||
{
|
||||
type ArgsType = ArgsType;
|
||||
type ReturnType = ReturnType;
|
||||
|
||||
fn trait_name(&self) -> &str {
|
||||
&self.trait_name
|
||||
}
|
||||
|
||||
fn method_name(&self) -> &str {
|
||||
&self.method_name
|
||||
}
|
||||
|
||||
fn args(&self) -> &Self::ArgsType {
|
||||
&self.args
|
||||
}
|
||||
|
||||
fn validation_hash(&self) -> Option<[u8; 32]> {
|
||||
self.validation_hash
|
||||
}
|
||||
}
|
||||
|
||||
impl<ArgsType, ReturnTy> StaticPayload<ArgsType, ReturnTy> {
|
||||
/// Create a new [`StaticPayload`].
|
||||
pub fn new(
|
||||
trait_name: impl Into<String>,
|
||||
method_name: impl Into<String>,
|
||||
args: ArgsType,
|
||||
) -> Self {
|
||||
StaticPayload {
|
||||
trait_name: trait_name.into().into(),
|
||||
method_name: method_name.into().into(),
|
||||
args,
|
||||
validation_hash: None,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new static [`StaticPayload`] using static function name
|
||||
/// and scale-encoded argument data.
|
||||
///
|
||||
/// This is only expected to be used from codegen.
|
||||
#[doc(hidden)]
|
||||
pub fn new_static(
|
||||
trait_name: &'static str,
|
||||
method_name: &'static str,
|
||||
args: ArgsType,
|
||||
hash: [u8; 32],
|
||||
) -> StaticPayload<ArgsType, ReturnTy> {
|
||||
StaticPayload {
|
||||
trait_name: Cow::Borrowed(trait_name),
|
||||
method_name: Cow::Borrowed(method_name),
|
||||
args,
|
||||
validation_hash: Some(hash),
|
||||
_marker: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Do not validate this call prior to submitting it.
|
||||
pub fn unvalidated(self) -> Self {
|
||||
Self { validation_hash: None, ..self }
|
||||
}
|
||||
|
||||
/// Returns the trait name.
|
||||
pub fn trait_name(&self) -> &str {
|
||||
&self.trait_name
|
||||
}
|
||||
|
||||
/// Returns the method name.
|
||||
pub fn method_name(&self) -> &str {
|
||||
&self.method_name
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`DynamicPayload`].
|
||||
pub fn dynamic<ArgsType, ReturnType>(
|
||||
trait_name: impl Into<String>,
|
||||
method_name: impl Into<String>,
|
||||
args_data: ArgsType,
|
||||
) -> DynamicPayload<ArgsType, ReturnType> {
|
||||
DynamicPayload::new(trait_name, method_name, args_data)
|
||||
}
|
||||
Reference in New Issue
Block a user