Add runtime_metadata_url to pull metadata directly from a node (#689)

* Allow metadata to be pulled directly from a node with runtime_metadata_url

* Update docs

* https too, and abstract out block_on fn

* tweak a comment in the example
This commit is contained in:
James Wilson
2022-10-19 11:07:12 +01:00
committed by GitHub
parent d7546db843
commit d03e599684
14 changed files with 286 additions and 79 deletions
+8 -52
View File
@@ -5,24 +5,13 @@
use clap::Parser as ClapParser;
use color_eyre::eyre;
use frame_metadata::RuntimeMetadataPrefixed;
use jsonrpsee::{
async_client::ClientBuilder,
client_transport::ws::{
Uri,
WsTransportClientBuilder,
},
core::{
client::ClientT,
Error,
},
http_client::HttpClientBuilder,
rpc_params,
};
use jsonrpsee::client_transport::ws::Uri;
use scale::Decode;
use std::io::{
self,
Write,
};
use subxt_codegen::utils::fetch_metadata_hex;
/// Download metadata from a substrate node, for use with `subxt` codegen.
#[derive(Debug, ClapParser)]
@@ -41,10 +30,11 @@ pub struct Opts {
}
pub async fn run(opts: Opts) -> color_eyre::Result<()> {
let (hex_data, bytes) = fetch_metadata(&opts.url).await?;
let hex_data = fetch_metadata_hex(&opts.url).await?;
match opts.format.as_str() {
"json" => {
let bytes = hex::decode(hex_data.trim_start_matches("0x"))?;
let metadata = <RuntimeMetadataPrefixed as Decode>::decode(&mut &bytes[..])?;
let json = serde_json::to_string_pretty(&metadata)?;
println!("{}", json);
@@ -54,7 +44,10 @@ pub async fn run(opts: Opts) -> color_eyre::Result<()> {
println!("{}", hex_data);
Ok(())
}
"bytes" => Ok(io::stdout().write_all(&bytes)?),
"bytes" => {
let bytes = hex::decode(hex_data.trim_start_matches("0x"))?;
Ok(io::stdout().write_all(&bytes)?)
}
_ => {
Err(eyre::eyre!(
"Unsupported format `{}`, expected `json`, `hex` or `bytes`",
@@ -63,40 +56,3 @@ pub async fn run(opts: Opts) -> color_eyre::Result<()> {
}
}
}
pub async fn fetch_metadata(url: &Uri) -> color_eyre::Result<(String, Vec<u8>)> {
let hex_data = match url.scheme_str() {
Some("http") => fetch_metadata_http(url).await,
Some("ws") | Some("wss") => fetch_metadata_ws(url).await,
invalid_scheme => {
let scheme = invalid_scheme.unwrap_or("no scheme");
Err(eyre::eyre!(format!(
"`{}` not supported, expects 'http', 'ws', or 'wss'",
scheme
)))
}
}?;
let bytes = hex::decode(hex_data.trim_start_matches("0x"))?;
Ok((hex_data, bytes))
}
async fn fetch_metadata_ws(url: &Uri) -> color_eyre::Result<String> {
let (sender, receiver) = WsTransportClientBuilder::default()
.build(url.to_string().parse::<Uri>().unwrap())
.await
.map_err(|e| Error::Transport(e.into()))?;
let client = ClientBuilder::default()
.max_notifs_per_subscription(4096)
.build_with_tokio(sender, receiver);
Ok(client.request("state_getMetadata", rpc_params![]).await?)
}
async fn fetch_metadata_http(url: &Uri) -> color_eyre::Result<String> {
let client = HttpClientBuilder::default().build(url.to_string())?;
Ok(client.request::<String>("state_getMetadata", None).await?)
}