-
Notifications
You must be signed in to change notification settings - Fork 254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add runtime_metadata_url to pull metadata directly from a node #689
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use jsonrpsee::{ | ||
async_client::ClientBuilder, | ||
client_transport::ws::{ | ||
Uri, | ||
WsTransportClientBuilder, | ||
}, | ||
core::{ | ||
client::ClientT, | ||
Error, | ||
}, | ||
http_client::HttpClientBuilder, | ||
rpc_params, | ||
}; | ||
|
||
/// Returns the metadata bytes from the provided URL, blocking the current thread. | ||
pub fn fetch_metadata_bytes_blocking(url: &Uri) -> Result<Vec<u8>, FetchMetadataError> { | ||
tokio::runtime::Builder::new_multi_thread() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. right, tokio is not initialized here because it's a compile time however you could have another helper function to avoid repeating the tokio runtime init: fn tokio_block_on<T, Fut: Future<Output = T>>(fut: Fut) -> Result<T, FetchMetadataError> {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(fut)
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea! |
||
.enable_all() | ||
.build() | ||
.unwrap() | ||
.block_on(fetch_metadata_bytes(url)) | ||
} | ||
|
||
/// Returns the raw, 0x prefixed metadata hex from the provided URL, blocking the current thread. | ||
pub fn fetch_metadata_hex_blocking(url: &Uri) -> Result<String, FetchMetadataError> { | ||
tokio::runtime::Builder::new_multi_thread() | ||
.enable_all() | ||
.build() | ||
.unwrap() | ||
.block_on(fetch_metadata_hex(url)) | ||
} | ||
|
||
/// Returns the metadata bytes from the provided URL. | ||
pub async fn fetch_metadata_bytes(url: &Uri) -> Result<Vec<u8>, FetchMetadataError> { | ||
let hex = fetch_metadata_hex(url).await?; | ||
let bytes = hex::decode(hex.trim_start_matches("0x"))?; | ||
Ok(bytes) | ||
} | ||
|
||
/// Returns the raw, 0x prefixed metadata hex from the provided URL. | ||
pub async fn fetch_metadata_hex(url: &Uri) -> Result<String, FetchMetadataError> { | ||
let hex_data = match url.scheme_str() { | ||
Some("http") => fetch_metadata_http(url).await, | ||
niklasad1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Some("ws") | Some("wss") => fetch_metadata_ws(url).await, | ||
invalid_scheme => { | ||
let scheme = invalid_scheme.unwrap_or("no scheme"); | ||
Err(FetchMetadataError::InvalidScheme(scheme.to_owned())) | ||
} | ||
}?; | ||
Ok(hex_data) | ||
} | ||
|
||
async fn fetch_metadata_ws(url: &Uri) -> Result<String, FetchMetadataError> { | ||
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) -> Result<String, FetchMetadataError> { | ||
let client = HttpClientBuilder::default().build(url.to_string())?; | ||
|
||
Ok(client.request::<String>("state_getMetadata", None).await?) | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum FetchMetadataError { | ||
DecodeError(hex::FromHexError), | ||
RequestError(jsonrpsee::core::Error), | ||
InvalidScheme(String), | ||
} | ||
|
||
impl std::fmt::Display for FetchMetadataError { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
FetchMetadataError::DecodeError(e) => { | ||
write!(f, "Cannot decode hex value: {e}") | ||
} | ||
FetchMetadataError::RequestError(e) => write!(f, "Request error: {e}"), | ||
FetchMetadataError::InvalidScheme(s) => { | ||
write!( | ||
f, | ||
"'{s}' not supported, supported URl schemes are http, ws or wss." | ||
) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl std::error::Error for FetchMetadataError {} | ||
|
||
impl From<hex::FromHexError> for FetchMetadataError { | ||
fn from(e: hex::FromHexError) -> Self { | ||
FetchMetadataError::DecodeError(e) | ||
} | ||
} | ||
impl From<jsonrpsee::core::Error> for FetchMetadataError { | ||
fn from(e: jsonrpsee::core::Error) -> Self { | ||
FetchMetadataError::RequestError(e) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
mod fetch_metadata; | ||
|
||
// easy access to this type needed for fetching metadata: | ||
pub use jsonrpsee::client_transport::ws::Uri; | ||
|
||
pub use fetch_metadata::{ | ||
fetch_metadata_bytes, | ||
fetch_metadata_bytes_blocking, | ||
fetch_metadata_hex, | ||
fetch_metadata_hex_blocking, | ||
FetchMetadataError, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// 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. | ||
|
||
// If you'd like to use metadata directly from a running node, you | ||
// can provide a URL to that node here. Note that if the metadata cannot | ||
// be retrieved from this node URL at compile time, compilation will fail. | ||
#[subxt::subxt(runtime_metadata_url = "wss://rpc.polkadot.io:443")] | ||
pub mod polkadot {} | ||
|
||
fn main() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: we could also update the
RuntimeGenerator
doc to reflect this changeThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh good point; our docs CI thing caught that also :)