mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 01:51:02 +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:
@@ -35,6 +35,7 @@ hex = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
scale-info = { workspace = true, features = ["bit-vec"] }
|
||||
scale-value = { workspace = true }
|
||||
sp-core = { workspace = true, features = ["std"] }
|
||||
syn = { workspace = true }
|
||||
subxt = { workspace = true, features = ["unstable-metadata", "native", "jsonrpsee", "reconnecting-rpc-client"] }
|
||||
|
||||
@@ -7,6 +7,7 @@ mod client;
|
||||
mod codegen;
|
||||
mod frame;
|
||||
mod metadata_validation;
|
||||
mod pallet_view_functions;
|
||||
mod runtime_api;
|
||||
mod storage;
|
||||
mod transactions;
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
use crate::{subxt_test, test_context};
|
||||
use test_runtime::node_runtime_unstable;
|
||||
|
||||
#[subxt_test]
|
||||
async fn call_view_function() -> Result<(), subxt::Error> {
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
use node_runtime_unstable::proxy::view_functions::check_permissions::{Call, ProxyType};
|
||||
|
||||
// This is one of only two view functions that currently exists at the time of writing.
|
||||
let call = Call::System(node_runtime_unstable::system::Call::remark {
|
||||
remark: b"hi".to_vec(),
|
||||
});
|
||||
let proxy_type = ProxyType::Any;
|
||||
let view_function_call = node_runtime_unstable::view_functions()
|
||||
.proxy()
|
||||
.check_permissions(call, proxy_type);
|
||||
|
||||
// Submit the call and get back a result.
|
||||
let _is_call_allowed = api
|
||||
.view_functions()
|
||||
.at_latest()
|
||||
.await?
|
||||
.call(view_function_call)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[subxt_test]
|
||||
async fn call_view_function_dynamically() -> Result<(), subxt::Error> {
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
let metadata = api.metadata();
|
||||
|
||||
let query_id = metadata
|
||||
.pallet_by_name("Proxy")
|
||||
.unwrap()
|
||||
.view_function_by_name("check_permissions")
|
||||
.unwrap()
|
||||
.query_id();
|
||||
|
||||
use scale_value::value;
|
||||
|
||||
let view_function_call = subxt::dynamic::view_function_call(
|
||||
*query_id,
|
||||
vec![value!(System(remark(b"hi".to_vec()))), value!(Any())],
|
||||
);
|
||||
|
||||
// Submit the call and get back a result.
|
||||
let _is_call_allowed = api
|
||||
.view_functions()
|
||||
.at_latest()
|
||||
.await?
|
||||
.call(view_function_call)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -9,6 +9,9 @@ use substrate_runner::{Error as SubstrateNodeError, SubstrateNode};
|
||||
// This variable accepts a single binary name or comma separated list.
|
||||
static SUBSTRATE_BIN_ENV_VAR: &str = "SUBSTRATE_NODE_PATH";
|
||||
|
||||
const V15_METADATA_VERSION: u32 = 15;
|
||||
const UNSTABLE_METADATA_VERSION: u32 = u32::MAX;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
run().await;
|
||||
@@ -37,11 +40,62 @@ async fn run() {
|
||||
};
|
||||
|
||||
let port = node.ws_port();
|
||||
let out_dir_env_var = env::var_os("OUT_DIR");
|
||||
let out_dir = out_dir_env_var.as_ref().unwrap().to_str().unwrap();
|
||||
|
||||
// Download metadata from binary. Avoid Subxt dep on `subxt::rpc::types::Bytes`and just impl here.
|
||||
// This may at least prevent this script from running so often (ie whenever we change Subxt).
|
||||
const V15_METADATA_VERSION: u32 = 15;
|
||||
let bytes = V15_METADATA_VERSION.encode();
|
||||
let (stable_metadata_path, unstable_metadata_path) = tokio::join!(
|
||||
download_and_save_metadata(V15_METADATA_VERSION, port, out_dir, "v15"),
|
||||
download_and_save_metadata(UNSTABLE_METADATA_VERSION, port, out_dir, "unstable")
|
||||
);
|
||||
|
||||
// Write out our expression to generate the runtime API to a file. Ideally, we'd just write this code
|
||||
// in lib.rs, but we must pass a string literal (and not `concat!(..)`) as an arg to `runtime_metadata_path`,
|
||||
// and so we need to spit it out here and include it verbatim instead.
|
||||
let runtime_api_contents = format!(
|
||||
r#"
|
||||
/// Generated types for the locally running Substrate node using V15 metadata.
|
||||
#[subxt::subxt(
|
||||
runtime_metadata_path = "{stable_metadata_path}",
|
||||
derive_for_all_types = "Eq, PartialEq",
|
||||
)]
|
||||
pub mod node_runtime {{}}
|
||||
|
||||
/// Generated types for the locally running Substrate node using the unstable metadata.
|
||||
#[subxt::subxt(
|
||||
runtime_metadata_path = "{unstable_metadata_path}",
|
||||
derive_for_all_types = "Eq, PartialEq",
|
||||
)]
|
||||
pub mod node_runtime_unstable {{}}
|
||||
"#
|
||||
);
|
||||
let runtime_path = Path::new(&out_dir).join("runtime.rs");
|
||||
fs::write(runtime_path, runtime_api_contents).expect("Couldn't write runtime rust output");
|
||||
|
||||
for substrate_node_path in substrate_bins_vec {
|
||||
let Ok(full_path) = which::which(substrate_node_path) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Re-build if the substrate binary we're pointed to changes (mtime):
|
||||
println!("cargo:rerun-if-changed={}", full_path.to_string_lossy());
|
||||
}
|
||||
|
||||
// Re-build if we point to a different substrate binary:
|
||||
println!("cargo:rerun-if-env-changed={SUBSTRATE_BIN_ENV_VAR}");
|
||||
// Re-build if this file changes:
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
|
||||
// Download metadata from binary. Avoid Subxt dep on `subxt::rpc::types::Bytes`and just impl here.
|
||||
// This may at least prevent this script from running so often (ie whenever we change Subxt).
|
||||
async fn download_and_save_metadata(
|
||||
version: u32,
|
||||
port: u16,
|
||||
out_dir: &str,
|
||||
suffix: &str,
|
||||
) -> String {
|
||||
// Download it:
|
||||
let bytes = version.encode();
|
||||
let version: String = format!("0x{}", hex::encode(&bytes));
|
||||
let raw: String = {
|
||||
use client::ClientT;
|
||||
@@ -61,42 +115,16 @@ async fn run() {
|
||||
.unwrap_or_else(|e| panic!("Failed to decode metadata bytes: {e}"));
|
||||
let metadata_bytes = bytes.expect("Metadata version not found");
|
||||
|
||||
// Save metadata to a file:
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let metadata_path = Path::new(&out_dir).join("test_node_runtime_metadata.scale");
|
||||
// Save it to a file:
|
||||
let metadata_path =
|
||||
Path::new(&out_dir).join(format!("test_node_runtime_metadata_{suffix}.scale"));
|
||||
fs::write(&metadata_path, metadata_bytes).expect("Couldn't write metadata output");
|
||||
|
||||
// Write out our expression to generate the runtime API to a file. Ideally, we'd just write this code
|
||||
// in lib.rs, but we must pass a string literal (and not `concat!(..)`) as an arg to `runtime_metadata_path`,
|
||||
// and so we need to spit it out here and include it verbatim instead.
|
||||
let runtime_api_contents = format!(
|
||||
r#"
|
||||
#[subxt::subxt(
|
||||
runtime_metadata_path = "{}",
|
||||
derive_for_all_types = "Eq, PartialEq",
|
||||
)]
|
||||
pub mod node_runtime {{}}
|
||||
"#,
|
||||
metadata_path
|
||||
.to_str()
|
||||
.expect("Path to metadata should be stringifiable")
|
||||
);
|
||||
let runtime_path = Path::new(&out_dir).join("runtime.rs");
|
||||
fs::write(runtime_path, runtime_api_contents).expect("Couldn't write runtime rust output");
|
||||
|
||||
for substrate_node_path in substrate_bins_vec {
|
||||
let Ok(full_path) = which::which(substrate_node_path) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Re-build if the substrate binary we're pointed to changes (mtime):
|
||||
println!("cargo:rerun-if-changed={}", full_path.to_string_lossy());
|
||||
}
|
||||
|
||||
// Re-build if we point to a different substrate binary:
|
||||
println!("cargo:rerun-if-env-changed={SUBSTRATE_BIN_ENV_VAR}");
|
||||
// Re-build if this file changes:
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
// Convert path to string because we need this to interpolate into string
|
||||
metadata_path
|
||||
.to_str()
|
||||
.expect("Path to metadata should be stringifiable")
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
// Use jsonrpsee to obtain metadata from the node.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/// The SCALE encoded metadata obtained from a local run of a substrate node.
|
||||
pub static METADATA: &[u8] = include_bytes!(concat!(
|
||||
env!("OUT_DIR"),
|
||||
"/test_node_runtime_metadata.scale"
|
||||
"/test_node_runtime_metadata_v15.scale"
|
||||
));
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/runtime.rs"));
|
||||
|
||||
Reference in New Issue
Block a user