mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-10 00:38:07 +00:00
XXX: Generate Runtime API
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
This commit is contained in:
@@ -8,9 +8,9 @@ use color_eyre::eyre::{
|
||||
WrapErr,
|
||||
};
|
||||
use frame_metadata::{
|
||||
v15::RuntimeMetadataV15,
|
||||
RuntimeMetadata,
|
||||
RuntimeMetadataPrefixed,
|
||||
RuntimeMetadataV15,
|
||||
META_RESERVED,
|
||||
};
|
||||
use jsonrpsee::client_transport::ws::Uri;
|
||||
|
||||
File diff suppressed because one or more lines are too long
+18
-8
@@ -7,11 +7,14 @@
|
||||
mod calls;
|
||||
mod constants;
|
||||
mod events;
|
||||
mod runtime_api;
|
||||
mod storage;
|
||||
|
||||
use scale_info::form::PortableForm;
|
||||
use subxt_metadata::get_metadata_per_pallet_hash;
|
||||
|
||||
use self::runtime_api::generate_runtime_api;
|
||||
|
||||
use super::DerivesRegistry;
|
||||
use crate::{
|
||||
ir,
|
||||
@@ -139,7 +142,11 @@ pub fn generate_runtime_api_from_bytes(
|
||||
type_substitutes: TypeSubstitutes,
|
||||
crate_path: CratePath,
|
||||
) -> TokenStream2 {
|
||||
let metadata = frame_metadata::RuntimeMetadataPrefixed::decode(&mut &bytes[..])
|
||||
let decoded: Option<frame_metadata::OpaqueMetadata> = Decode::decode(&mut &*bytes)
|
||||
.unwrap_or_else(|e| abort_call_site!("Failed to decode opaque metadata: {}", e));
|
||||
let decoded = decoded.unwrap();
|
||||
let bytes = &decoded.0;
|
||||
let metadata: RuntimeMetadataPrefixed = Decode::decode(&mut &bytes[..])
|
||||
.unwrap_or_else(|e| abort_call_site!("Failed to decode metadata: {}", e));
|
||||
|
||||
let generator = RuntimeGenerator::new(metadata);
|
||||
@@ -157,8 +164,6 @@ fn generate_runtime_call_api(
|
||||
) -> TokenStream2 {
|
||||
let mut result = quote!();
|
||||
|
||||
println!("inside runtime: {:?}", runtime);
|
||||
|
||||
for trait_ in runtime {
|
||||
for method in &trait_.methods {
|
||||
let trait_name = trait_.name.clone();
|
||||
@@ -188,8 +193,6 @@ fn generate_runtime_call_api(
|
||||
}
|
||||
}
|
||||
|
||||
println!("Code gen would generate: {}", result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
@@ -247,6 +250,10 @@ impl RuntimeGenerator {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Generate the runtime API.
|
||||
let runtime_api =
|
||||
generate_runtime_api(&self.metadata, &type_gen, types_mod_ident, &crate_path);
|
||||
|
||||
// Pallet names and their length are used to create PALLETS array.
|
||||
// The array is used to identify the pallets composing the metadata for
|
||||
// validation of just those pallets.
|
||||
@@ -377,9 +384,9 @@ impl RuntimeGenerator {
|
||||
TransactionApi
|
||||
}
|
||||
|
||||
pub mod runtime_api {
|
||||
#runtime_api_fns
|
||||
}
|
||||
// pub mod runtime_api {
|
||||
// #runtime_api_fns
|
||||
// }
|
||||
|
||||
pub struct ConstantsApi;
|
||||
impl ConstantsApi {
|
||||
@@ -417,6 +424,9 @@ impl RuntimeGenerator {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Runtime API.
|
||||
#runtime_api
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::{
|
||||
types::TypeGenerator,
|
||||
CratePath,
|
||||
};
|
||||
use frame_metadata::v15::{
|
||||
RuntimeMetadataV15,
|
||||
TraitMetadata,
|
||||
};
|
||||
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{
|
||||
format_ident,
|
||||
quote,
|
||||
};
|
||||
use scale_info::form::PortableForm;
|
||||
|
||||
/// Generates the accessor functions for the given trait.
|
||||
fn generate_trait_api(
|
||||
trait_: &TraitMetadata<PortableForm>,
|
||||
type_gen: &TypeGenerator,
|
||||
types_mod_ident: &syn::Ident,
|
||||
crate_path: &CratePath,
|
||||
) -> TokenStream2 {
|
||||
let trait_name = &trait_.name;
|
||||
let docs = &trait_.docs;
|
||||
|
||||
const VEC_ACC: &'static str = "result";
|
||||
let vec_acc = format_ident!("{}", VEC_ACC);
|
||||
|
||||
let methods: Vec<_> = trait_.methods.iter().map(|method| {
|
||||
let method_name = format_ident!("{}", &method.name);
|
||||
let func_name = format!("{}_{}", trait_name, method_name);
|
||||
let docs = &method.docs;
|
||||
|
||||
let inputs: Vec<_> = method.inputs.iter().map(|input| {
|
||||
let name = format_ident!("{}", &input.name);
|
||||
let ty = type_gen.resolve_type_path(input.ty.id());
|
||||
|
||||
let param = quote!(#name: #ty);
|
||||
let encoded = quote!(#name.encode_to(&mut #vec_acc));
|
||||
(param, encoded)
|
||||
}).collect();
|
||||
|
||||
let params = inputs.iter().map(|(param, _)| param);
|
||||
let encoded = inputs.iter().map(|(_, encoded)| encoded);
|
||||
|
||||
quote!(
|
||||
#( #[doc = #docs ] )*
|
||||
pub fn #method_name( #( #params, )* ) -> #crate_path::runtime_api::RuntimeAPIPayload {
|
||||
let mut #vec_acc = Vec::new();
|
||||
#( #encoded; )*
|
||||
|
||||
#crate_path::runtime_api::RuntimeAPIPayload::new(
|
||||
#func_name,
|
||||
#vec_acc,
|
||||
[0; 32],
|
||||
)
|
||||
}
|
||||
)
|
||||
}).collect();
|
||||
|
||||
let trait_name = format_ident!("{}", &trait_.name);
|
||||
|
||||
quote!(
|
||||
#( #[doc = #docs ] )*
|
||||
pub mod #trait_name {
|
||||
use super::root_mod;
|
||||
use super::#types_mod_ident;
|
||||
|
||||
use #crate_path::ext::codec::Encode;
|
||||
|
||||
#( #methods )*
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate the runtime API.
|
||||
pub fn generate_runtime_api(
|
||||
metadata: &RuntimeMetadataV15,
|
||||
type_gen: &TypeGenerator,
|
||||
types_mod_ident: &syn::Ident,
|
||||
crate_path: &CratePath,
|
||||
) -> TokenStream2 {
|
||||
let runtime = &metadata.runtime;
|
||||
|
||||
if runtime.is_empty() {
|
||||
return quote!()
|
||||
}
|
||||
|
||||
let runtime_mods = runtime
|
||||
.iter()
|
||||
.map(|rt| generate_trait_api(rt, type_gen, &types_mod_ident, crate_path));
|
||||
|
||||
quote! {
|
||||
pub mod runtime_api {
|
||||
use super::root_mod;
|
||||
use super::#types_mod_ident;
|
||||
|
||||
#( #runtime_mods )*
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,16 @@ async fn fetch_metadata_ws(url: &Uri) -> Result<String, FetchMetadataError> {
|
||||
.max_notifs_per_subscription(4096)
|
||||
.build_with_tokio(sender, receiver);
|
||||
|
||||
Ok(client.request("state_getMetadata", rpc_params![]).await?)
|
||||
use codec::Encode;
|
||||
let bytes = 15u32.encode();
|
||||
let param = format!("0x{}", hex::encode(&bytes));
|
||||
|
||||
Ok(client
|
||||
.request(
|
||||
"state_call",
|
||||
rpc_params!["Metadata_metadata_at_version", ¶m],
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
async fn fetch_metadata_http(url: &Uri) -> Result<String, FetchMetadataError> {
|
||||
@@ -71,7 +80,16 @@ async fn fetch_metadata_http(url: &Uri) -> Result<String, FetchMetadataError> {
|
||||
.request_timeout(Duration::from_secs(180))
|
||||
.build(url.to_string())?;
|
||||
|
||||
Ok(client.request("state_getMetadata", rpc_params![]).await?)
|
||||
use codec::Encode;
|
||||
let bytes = 15u32.encode();
|
||||
let param = format!("0x{}", hex::encode(&bytes));
|
||||
|
||||
Ok(client
|
||||
.request(
|
||||
"state_call",
|
||||
rpc_params!["Metadata_metadata_at_version", ¶m],
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -24,14 +24,22 @@ use subxt::{
|
||||
OnlineClient,
|
||||
};
|
||||
|
||||
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")]
|
||||
use codec::Encode;
|
||||
|
||||
#[subxt::subxt(runtime_metadata_url = "http://localhost:9933")]
|
||||
pub mod polkadot {}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
polkadot::runtime_api::Metadata_metadata();
|
||||
let api_tx = polkadot::runtime_api::Core::version();
|
||||
println!("RuntimeApi payload: {:?}", api_tx);
|
||||
|
||||
let api = OnlineClient::<PolkadotConfig>::new().await?;
|
||||
let bytes = api.runtime_api().at(None).await?.call(api_tx).await?;
|
||||
|
||||
println!("Result: {:?}", bytes);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -159,30 +159,16 @@ impl<T: Config> OnlineClient<T> {
|
||||
async fn fetch_metadata(rpc: &Rpc<T>) -> Result<Metadata, Error> {
|
||||
use codec::Encode;
|
||||
|
||||
|
||||
let param = 15u32.encode();
|
||||
let bytes = rpc
|
||||
.state_call("Metadata_metadata_at_version", Some(¶m), None)
|
||||
.await?;
|
||||
|
||||
// println!("GOT BYTES: {:?}", bytes);
|
||||
|
||||
let decoded: Option<OpaqueMetadata> = Decode::decode(&mut &*bytes)?;
|
||||
|
||||
println!("Decoded opaque");
|
||||
|
||||
let decoded = decoded.unwrap();
|
||||
let bytes = &decoded.0;
|
||||
let meta: RuntimeMetadataPrefixed = Decode::decode(&mut &bytes[..])?;
|
||||
|
||||
// let metadata: Metadata = meta.try_into()?;
|
||||
|
||||
// println!("Availb methods {:?}", decoded.0);
|
||||
|
||||
// let cursor = &mut &*bytes;
|
||||
// let _ = <Compact<u32>>::decode(cursor)?;
|
||||
// let meta: frame_metadata::RuntimeMetadataPrefixed = Decode::decode(cursor)?;
|
||||
|
||||
println!("METADATA {:#?}", meta);
|
||||
|
||||
let metadata: Metadata = meta.try_into()?;
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
//! Types associated with executing runtime API calls.
|
||||
|
||||
mod runtime_client;
|
||||
mod runtime_payload;
|
||||
mod runtime_types;
|
||||
|
||||
pub use runtime_client::RuntimeApiClient;
|
||||
pub use runtime_payload::RuntimeAPIPayload;
|
||||
pub use runtime_types::RuntimeApi;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
/// Payload for a runtime API fn.
|
||||
#[derive(Debug)]
|
||||
pub struct RuntimeAPIPayload {
|
||||
func_name: &'static str,
|
||||
data: Vec<u8>,
|
||||
validation_hash: Option<[u8; 32]>,
|
||||
}
|
||||
|
||||
impl RuntimeAPIPayload {
|
||||
/// Create a new [`RuntimeAPIPayload`] from static data.
|
||||
pub fn new(
|
||||
func_name: &'static str,
|
||||
data: Vec<u8>,
|
||||
validation_hash: [u8; 32],
|
||||
) -> Self {
|
||||
RuntimeAPIPayload {
|
||||
func_name,
|
||||
data,
|
||||
validation_hash: Some(validation_hash),
|
||||
}
|
||||
}
|
||||
|
||||
/// Do not validate this prior to submitting it.
|
||||
pub fn unvalidated(self) -> Self {
|
||||
Self {
|
||||
validation_hash: None,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the function name.
|
||||
pub fn func_name(&self) -> &'static str {
|
||||
&self.func_name
|
||||
}
|
||||
|
||||
/// Returns the parameter data.
|
||||
pub fn param_data(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ use std::{
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
use super::RuntimeAPIPayload;
|
||||
|
||||
/// Execute runtime API calls.
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Clone(bound = "Client: Clone"))]
|
||||
@@ -56,4 +58,26 @@ where
|
||||
Ok(data.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute a runtime API call for the given payload.
|
||||
pub fn call(
|
||||
&self,
|
||||
payload: RuntimeAPIPayload,
|
||||
) -> impl Future<Output = Result<Vec<u8>, Error>> {
|
||||
let client = self.client.clone();
|
||||
let block_hash = self.block_hash;
|
||||
// Ensure that the returned future doesn't have a lifetime tied to api.runtime_api(),
|
||||
// which is a temporary thing we'll be throwing away quickly:
|
||||
async move {
|
||||
let payload = payload;
|
||||
let function = payload.func_name();
|
||||
let call_parameters = Some(payload.param_data());
|
||||
|
||||
let data = client
|
||||
.rpc()
|
||||
.state_call(function, call_parameters, Some(block_hash))
|
||||
.await?;
|
||||
Ok(data.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user