mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 15:51:12 +00:00
move fetch metadata to a separate crate subxt_utils_fetchmetadata (#1829)
* macros: feature-gate jsonrpsee/fetch metadata url * make CI happy * Update codegen/src/error.rs * extract `fetch-metdata` to separate crate * add missing license headers * introduce subxt-utils crate * add missing files * codegen: remove unused hex crate * fix test build * move subxt_utils -> subxt_utils_fetchmetadata * cargo fmt * runtime-path -> runtime-metadata-path * Update utils/fetch-metadata/src/lib.rs
This commit is contained in:
Generated
+15
-3
@@ -10612,6 +10612,7 @@ dependencies = [
|
||||
"subxt",
|
||||
"subxt-codegen",
|
||||
"subxt-metadata",
|
||||
"subxt-utils-fetchmetadata",
|
||||
"syn 2.0.77",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
@@ -10624,8 +10625,6 @@ dependencies = [
|
||||
"frame-metadata 17.0.0",
|
||||
"getrandom",
|
||||
"heck 0.5.0",
|
||||
"hex",
|
||||
"jsonrpsee",
|
||||
"parity-scale-codec",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -10634,7 +10633,6 @@ dependencies = [
|
||||
"subxt-metadata",
|
||||
"syn 2.0.77",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10704,6 +10702,7 @@ dependencies = [
|
||||
"quote",
|
||||
"scale-typegen",
|
||||
"subxt-codegen",
|
||||
"subxt-utils-fetchmetadata",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
@@ -10759,6 +10758,19 @@ dependencies = [
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subxt-utils-fetchmetadata"
|
||||
version = "0.37.0"
|
||||
dependencies = [
|
||||
"frame-metadata 17.0.0",
|
||||
"hex",
|
||||
"jsonrpsee",
|
||||
"parity-scale-codec",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
||||
@@ -15,6 +15,7 @@ members = [
|
||||
"signer",
|
||||
"subxt",
|
||||
"scripts/artifacts",
|
||||
"utils/fetch-metadata",
|
||||
]
|
||||
|
||||
# We exclude any crates that would depend on non mutually
|
||||
@@ -140,6 +141,7 @@ polkadot-sdk = { version = "0.7", default-features = false }
|
||||
# Subxt workspace crates:
|
||||
subxt = { version = "0.37.0", path = "subxt", default-features = false }
|
||||
subxt-core = { version = "0.37.0", path = "core", default-features = false }
|
||||
subxt-utils-fetchmetadata = { version = "0.37.0", path = "utils/fetch-metadata", default-features = false }
|
||||
subxt-macro = { version = "0.37.0", path = "macro" }
|
||||
subxt-metadata = { version = "0.37.0", path = "metadata", default-features = false }
|
||||
subxt-codegen = { version = "0.37.0", path = "codegen" }
|
||||
|
||||
+3
-2
@@ -26,9 +26,10 @@ workspace = true
|
||||
chain-spec-pruning = ["smoldot"]
|
||||
|
||||
[dependencies]
|
||||
subxt-codegen = { workspace = true, features = ["fetch-metadata"] }
|
||||
subxt-codegen = { workspace = true }
|
||||
subxt-utils-fetchmetadata = { workspace = true, features = ["url"] }
|
||||
subxt-metadata = { workspace = true }
|
||||
subxt = { workspace = true, features = ["native", "jsonrpsee"] }
|
||||
subxt = { workspace = true, features = ["default"] }
|
||||
clap = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
color-eyre = { workspace = true }
|
||||
|
||||
@@ -9,7 +9,7 @@ use jsonrpsee::{
|
||||
http_client::HttpClientBuilder,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use subxt_codegen::fetch_metadata::Url;
|
||||
use subxt_utils_fetchmetadata::Url;
|
||||
|
||||
/// Returns the node's chainSpec from the provided URL.
|
||||
pub async fn fetch_chain_spec(url: Url) -> Result<serde_json::Value, FetchSpecError> {
|
||||
|
||||
@@ -6,7 +6,7 @@ use clap::Parser as ClapParser;
|
||||
#[cfg(feature = "chain-spec-pruning")]
|
||||
use serde_json::Value;
|
||||
use std::{io::Write, path::PathBuf};
|
||||
use subxt_codegen::fetch_metadata::Url;
|
||||
use subxt_utils_fetchmetadata::Url;
|
||||
|
||||
mod fetch;
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ use color_eyre::eyre::WrapErr;
|
||||
use jsonrpsee::client_transport::ws::Url;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use subxt_codegen::fetch_metadata::MetadataVersion;
|
||||
use subxt_metadata::Metadata;
|
||||
use subxt_utils_fetchmetadata::MetadataVersion;
|
||||
|
||||
use crate::utils::validate_url_security;
|
||||
|
||||
@@ -137,7 +137,7 @@ async fn fetch_runtime_metadata(
|
||||
url: Url,
|
||||
version: MetadataVersion,
|
||||
) -> color_eyre::Result<Metadata> {
|
||||
let bytes = subxt_codegen::fetch_metadata::fetch_metadata_from_url(url, version).await?;
|
||||
let bytes = subxt_utils_fetchmetadata::from_url(url, version).await?;
|
||||
let metadata = Metadata::decode(&mut &bytes[..])?;
|
||||
Ok(metadata)
|
||||
}
|
||||
|
||||
+3
-3
@@ -14,7 +14,7 @@ use std::{fs, io::Read, path::PathBuf};
|
||||
use subxt::{OnlineClient, PolkadotConfig};
|
||||
|
||||
use scale_value::Value;
|
||||
use subxt_codegen::fetch_metadata::{fetch_metadata_from_url, MetadataVersion, Url};
|
||||
use subxt_utils_fetchmetadata::{self as fetch_metadata, MetadataVersion, Url};
|
||||
|
||||
/// The source of the metadata.
|
||||
#[derive(Debug, Args, Clone)]
|
||||
@@ -117,12 +117,12 @@ impl FileOrUrl {
|
||||
}
|
||||
// Fetch from --url
|
||||
(None, Some(uri), version) => {
|
||||
Ok(fetch_metadata_from_url(uri.clone(), version.unwrap_or_default()).await?)
|
||||
Ok(fetch_metadata::from_url(uri.clone(), version.unwrap_or_default()).await?)
|
||||
}
|
||||
// Default if neither is provided; fetch from local url
|
||||
(None, None, version) => {
|
||||
let url = Url::parse("ws://localhost:9944").expect("Valid URL; qed");
|
||||
Ok(fetch_metadata_from_url(url, version.unwrap_or_default()).await?)
|
||||
Ok(fetch_metadata::from_url(url, version.unwrap_or_default()).await?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-6
@@ -13,8 +13,7 @@ description = "Generate an API for interacting with a substrate node from FRAME
|
||||
|
||||
[features]
|
||||
default = []
|
||||
fetch-metadata = ["dep:jsonrpsee", "dep:tokio", "dep:frame-metadata"]
|
||||
web = ["jsonrpsee?/async-wasm-client", "jsonrpsee?/client-web-transport", "getrandom/js"]
|
||||
web = ["getrandom/js"]
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", workspace = true, features = ["derive"] }
|
||||
@@ -25,9 +24,6 @@ quote = { workspace = true }
|
||||
syn = { workspace = true }
|
||||
scale-info = { workspace = true }
|
||||
subxt-metadata = { workspace = true }
|
||||
jsonrpsee = { workspace = true, features = ["async-client", "client-ws-transport-tls", "http-client"], optional = true }
|
||||
hex = { workspace = true, features = ["std"] }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
|
||||
thiserror = { workspace = true }
|
||||
scale-typegen = { workspace = true }
|
||||
|
||||
@@ -36,9 +32,10 @@ getrandom = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
scale-info = { workspace = true, features = ["bit-vec"] }
|
||||
frame-metadata = { workspace = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["fetch-metadata"]
|
||||
features = ["default"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.playground]
|
||||
|
||||
+3
-28
@@ -11,9 +11,6 @@ use scale_typegen::TypegenError;
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum CodegenError {
|
||||
/// Cannot fetch the metadata bytes.
|
||||
#[error("Failed to fetch metadata, make sure that you're pointing at a node which is providing substrate-based metadata: {0}")]
|
||||
Fetch(#[from] FetchMetadataError),
|
||||
/// Cannot decode the metadata bytes.
|
||||
#[error("Could not decode metadata, only V14 and V15 metadata are supported: {0}")]
|
||||
Decode(#[from] codec::Error),
|
||||
@@ -60,6 +57,9 @@ pub enum CodegenError {
|
||||
/// Error when generating metadata from Wasm-runtime
|
||||
#[error("Failed to generate metadata from wasm file. reason: {0}")]
|
||||
Wasm(String),
|
||||
/// Other error.
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl CodegenError {
|
||||
@@ -81,28 +81,3 @@ impl CodegenError {
|
||||
syn::Error::new(span, msg).into_compile_error()
|
||||
}
|
||||
}
|
||||
|
||||
/// Error attempting to load metadata.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum FetchMetadataError {
|
||||
/// Error decoding from a hex value.
|
||||
#[error("Cannot decode hex value: {0}")]
|
||||
DecodeError(#[from] hex::FromHexError),
|
||||
/// Some SCALE codec error.
|
||||
#[error("Cannot scale encode/decode value: {0}")]
|
||||
CodecError(#[from] codec::Error),
|
||||
/// JSON-RPC error fetching metadata.
|
||||
#[cfg(feature = "fetch-metadata")]
|
||||
#[error("Request error: {0}")]
|
||||
RequestError(#[from] jsonrpsee::core::ClientError),
|
||||
/// Failed IO when fetching from a file.
|
||||
#[error("Failed IO for {0}, make sure that you are providing the correct file path for metadata: {1}")]
|
||||
Io(String, std::io::Error),
|
||||
/// URL scheme is not http, https, ws or wss.
|
||||
#[error("'{0}' not supported, supported URI schemes are http, https, ws or wss.")]
|
||||
InvalidScheme(String),
|
||||
/// Some other error.
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
+1
-8
@@ -6,20 +6,13 @@
|
||||
//! This is used by the `#[subxt]` macro and `subxt codegen` CLI command, but can also
|
||||
//! be used directly if preferable.
|
||||
|
||||
#![deny(unused_crate_dependencies, missing_docs)]
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
mod api;
|
||||
pub mod error;
|
||||
mod ir;
|
||||
|
||||
// These should probably be in a separate crate; they are used by the
|
||||
// macro and CLI tool, so they only live here because this is a common
|
||||
// crate that both depend on.
|
||||
#[cfg(feature = "fetch-metadata")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "fetch-metadata")))]
|
||||
pub mod fetch_metadata;
|
||||
|
||||
#[cfg(feature = "web")]
|
||||
use getrandom as _;
|
||||
|
||||
|
||||
+4
-2
@@ -15,7 +15,8 @@ description = "Generate types and helpers for interacting with Substrate runtime
|
||||
|
||||
[features]
|
||||
web = ["subxt-codegen/web"]
|
||||
runtime-path = ["polkadot-sdk"]
|
||||
runtime-metadata-path = ["polkadot-sdk"]
|
||||
runtime-metadata-insecure-url = ["subxt-utils-fetchmetadata/url"]
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
@@ -26,7 +27,8 @@ darling = { workspace = true }
|
||||
proc-macro-error2 = { workspace = true }
|
||||
syn = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
subxt-codegen = { workspace = true, features = ["fetch-metadata"] }
|
||||
subxt-codegen = { workspace = true }
|
||||
subxt-utils-fetchmetadata = { workspace = true }
|
||||
scale-typegen = { workspace = true }
|
||||
polkadot-sdk = { workspace = true, optional = true, features = ["sp-io", "sc-executor-common", "sp-state-machine", "sp-maybe-compressed-blob", "sc-executor"] }
|
||||
|
||||
|
||||
+21
-17
@@ -13,15 +13,10 @@ use scale_typegen::typegen::{
|
||||
settings::substitutes::path_segments,
|
||||
validation::{registry_contains_type_path, similar_type_paths_in_registry},
|
||||
};
|
||||
use subxt_codegen::{
|
||||
fetch_metadata::{
|
||||
fetch_metadata_from_file_blocking, fetch_metadata_from_url_blocking, MetadataVersion, Url,
|
||||
},
|
||||
CodegenBuilder, CodegenError, Metadata,
|
||||
};
|
||||
use subxt_codegen::{CodegenBuilder, CodegenError, Metadata};
|
||||
use syn::{parse_macro_input, punctuated::Punctuated};
|
||||
|
||||
#[cfg(feature = "runtime-path")]
|
||||
#[cfg(feature = "runtime-metadata-path")]
|
||||
mod wasm_loader;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -61,7 +56,7 @@ struct RuntimeMetadataArgs {
|
||||
no_default_substitutions: bool,
|
||||
#[darling(default)]
|
||||
unstable_metadata: darling::util::Flag,
|
||||
#[cfg(feature = "runtime-path")]
|
||||
#[cfg(feature = "runtime-metadata-path")]
|
||||
#[darling(default)]
|
||||
runtime_path: Option<String>,
|
||||
}
|
||||
@@ -211,7 +206,7 @@ fn fetch_metadata(args: &RuntimeMetadataArgs) -> Result<subxt_codegen::Metadata,
|
||||
// Do we want to fetch unstable metadata? This only works if fetching from a URL.
|
||||
let unstable_metadata = args.unstable_metadata.is_present();
|
||||
|
||||
#[cfg(feature = "runtime-path")]
|
||||
#[cfg(feature = "runtime-metadata-path")]
|
||||
if let Some(path) = &args.runtime_path {
|
||||
if args.runtime_metadata_insecure_url.is_some() || args.runtime_metadata_path.is_some() {
|
||||
abort_call_site!(
|
||||
@@ -240,11 +235,14 @@ fn fetch_metadata(args: &RuntimeMetadataArgs) -> Result<subxt_codegen::Metadata,
|
||||
let root = std::env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into());
|
||||
let root_path = std::path::Path::new(&root);
|
||||
let path = root_path.join(rest_of_path);
|
||||
fetch_metadata_from_file_blocking(&path)
|
||||
subxt_utils_fetchmetadata::from_file_blocking(&path)
|
||||
.and_then(|b| subxt_codegen::Metadata::decode(&mut &*b).map_err(Into::into))
|
||||
.map_err(|e| CodegenError::from(e).into_compile_error())?
|
||||
.map_err(|e| CodegenError::Other(e.to_string()).into_compile_error())?
|
||||
}
|
||||
#[cfg(feature = "runtime-metadata-insecure-url")]
|
||||
(None, Some(url_string)) => {
|
||||
use subxt_utils_fetchmetadata::{from_url_blocking, MetadataVersion, Url};
|
||||
|
||||
let url = Url::parse(url_string).unwrap_or_else(|_| {
|
||||
abort_call_site!("Cannot download metadata; invalid url: {}", url_string)
|
||||
});
|
||||
@@ -254,30 +252,36 @@ fn fetch_metadata(args: &RuntimeMetadataArgs) -> Result<subxt_codegen::Metadata,
|
||||
false => MetadataVersion::Latest,
|
||||
};
|
||||
|
||||
fetch_metadata_from_url_blocking(url, version)
|
||||
.map_err(CodegenError::from)
|
||||
from_url_blocking(url, version)
|
||||
.map_err(|e| CodegenError::Other(e.to_string()))
|
||||
.and_then(|b| subxt_codegen::Metadata::decode(&mut &*b).map_err(Into::into))
|
||||
.map_err(|e| e.into_compile_error())?
|
||||
}
|
||||
#[cfg(feature = "runtime-path")]
|
||||
#[cfg(not(feature = "runtime-metadata-insecure-url"))]
|
||||
(None, Some(_)) => {
|
||||
abort_call_site!(
|
||||
"'runtime_metadata_insecure_url' requires the 'runtime-metadata-insecure-url' feature to be enabled"
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "runtime-metadata-path")]
|
||||
(None, None) => {
|
||||
abort_call_site!(
|
||||
"At least one of 'runtime_metadata_path', 'runtime_metadata_insecure_url' or 'runtime_path` can be provided"
|
||||
)
|
||||
}
|
||||
#[cfg(not(feature = "runtime-path"))]
|
||||
#[cfg(not(feature = "runtime-metadata-path"))]
|
||||
(None, None) => {
|
||||
abort_call_site!(
|
||||
"At least one of 'runtime_metadata_path', 'runtime_metadata_insecure_url' can be provided"
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "runtime-path")]
|
||||
#[cfg(feature = "runtime-metadata-path")]
|
||||
_ => {
|
||||
abort_call_site!(
|
||||
"Only one of 'runtime_metadata_path', 'runtime_metadata_insecure_url' or 'runtime_path` can be provided"
|
||||
)
|
||||
}
|
||||
#[cfg(not(feature = "runtime-path"))]
|
||||
#[cfg(not(feature = "runtime-metadata-path"))]
|
||||
_ => {
|
||||
abort_call_site!(
|
||||
"Only one of 'runtime_metadata_path' or 'runtime_metadata_insecure_url' can be provided"
|
||||
|
||||
@@ -12,15 +12,15 @@ use polkadot_sdk::{
|
||||
sp_maybe_compressed_blob::{self, CODE_BLOB_BOMB_LIMIT},
|
||||
sp_state_machine,
|
||||
};
|
||||
use subxt_codegen::{fetch_metadata::fetch_metadata_from_file_blocking, CodegenError, Metadata};
|
||||
use subxt_codegen::{CodegenError, Metadata};
|
||||
|
||||
/// Result type shorthand
|
||||
pub type WasmMetadataResult<A> = Result<A, CodegenError>;
|
||||
|
||||
/// Uses wasm artifact produced by compiling the runtime to generate metadata
|
||||
pub fn from_wasm_file(wasm_file_path: &Path) -> WasmMetadataResult<Metadata> {
|
||||
let wasm_file = fetch_metadata_from_file_blocking(wasm_file_path)
|
||||
.map_err(Into::<CodegenError>::into)
|
||||
let wasm_file = subxt_utils_fetchmetadata::from_file_blocking(wasm_file_path)
|
||||
.map_err(|e| CodegenError::Other(e.to_string()))
|
||||
.and_then(maybe_decompress)?;
|
||||
call_and_decode(wasm_file)
|
||||
}
|
||||
|
||||
+2
-2
@@ -60,7 +60,7 @@ reconnecting-rpc-client = ["dep:finito", "jsonrpsee"]
|
||||
# Enable this to use jsonrpsee (allowing for example `OnlineClient::from_url`).
|
||||
jsonrpsee = [
|
||||
"dep:jsonrpsee",
|
||||
"runtime",
|
||||
"runtime"
|
||||
]
|
||||
|
||||
# Enable this to pull in extra Substrate dependencies which make it possible to
|
||||
@@ -79,7 +79,7 @@ unstable-metadata = []
|
||||
unstable-light-client = ["subxt-lightclient"]
|
||||
|
||||
# Activate this to expose the ability to generate metadata from Wasm runtime files.
|
||||
runtime-path = ["subxt-macro/runtime-path"]
|
||||
runtime-metadata-path = ["subxt-macro/runtime-metadata-path"]
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
|
||||
@@ -14,6 +14,6 @@ hex = { workspace = true }
|
||||
scale-info = { workspace = true, features = ["bit-vec"] }
|
||||
frame-metadata = { workspace = true }
|
||||
codec = { package = "parity-scale-codec", workspace = true, features = ["derive", "bit-vec"] }
|
||||
subxt = { workspace = true, features = ["native", "jsonrpsee", "runtime-path"] }
|
||||
subxt = { workspace = true, features = ["native", "jsonrpsee", "runtime-metadata-path"] }
|
||||
subxt-metadata = { workspace = true }
|
||||
generate-custom-metadata = { path = "../generate-custom-metadata" }
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
[package]
|
||||
name = "subxt-utils-fetchmetadata"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
publish = true
|
||||
autotests = false
|
||||
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
documentation.workspace = true
|
||||
homepage.workspace = true
|
||||
description = "subxt utils fetch metadata"
|
||||
|
||||
[features]
|
||||
url = ["dep:jsonrpsee", "dep:tokio", "dep:url", "frame-metadata"]
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
codec = { package = "parity-scale-codec", workspace = true, features = ["derive", "std"] }
|
||||
hex = { workspace = true, features = ["std"] }
|
||||
|
||||
# Optional dependencies for the `url` feature.
|
||||
jsonrpsee = { workspace = true, features = ["ws-client", "http-client"], optional = true }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
|
||||
url = { workspace = true, optional = true }
|
||||
frame-metadata = { workspace = true, optional = true, features = ["std"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["url"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.playground]
|
||||
default-features = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
/// Error attempting to fetch metadata.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// Error decoding from a hex value.
|
||||
#[error("Cannot decode hex value: {0}")]
|
||||
DecodeError(#[from] hex::FromHexError),
|
||||
/// Some SCALE codec error.
|
||||
#[error("Cannot scale encode/decode value: {0}")]
|
||||
CodecError(#[from] codec::Error),
|
||||
/// JSON-RPC error fetching metadata.
|
||||
#[cfg(feature = "url")]
|
||||
#[error("Request error: {0}")]
|
||||
RequestError(#[from] jsonrpsee::core::ClientError),
|
||||
/// Failed IO when fetching from a file.
|
||||
#[error("Failed IO for {0}, make sure that you are providing the correct file path for metadata: {1}")]
|
||||
Io(String, std::io::Error),
|
||||
/// URL scheme is not http, https, ws or wss.
|
||||
#[error("'{0}' not supported, supported URI schemes are http, https, ws or wss.")]
|
||||
InvalidScheme(String),
|
||||
/// Some other error.
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
//! Subxt utils fetch metadata.
|
||||
|
||||
// Internal helper macros
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod error;
|
||||
|
||||
cfg_fetch_from_url! {
|
||||
mod url;
|
||||
pub use url::{from_url, from_url_blocking, MetadataVersion, Url};
|
||||
}
|
||||
|
||||
pub use error::Error;
|
||||
|
||||
/// Fetch metadata from a file in a blocking manner.
|
||||
pub fn from_file_blocking(path: &std::path::Path) -> Result<Vec<u8>, error::Error> {
|
||||
use std::io::Read;
|
||||
|
||||
let to_err = |err| error::Error::Io(path.to_string_lossy().into(), err);
|
||||
let mut file = std::fs::File::open(path).map_err(to_err)?;
|
||||
let mut bytes = Vec::new();
|
||||
file.read_to_end(&mut bytes).map_err(to_err)?;
|
||||
Ok(bytes)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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.
|
||||
|
||||
macro_rules! cfg_feature {
|
||||
($feature:literal, $($item:item)*) => {
|
||||
$(
|
||||
#[cfg(feature = $feature)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = $feature)))]
|
||||
$item
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! cfg_fetch_from_url {
|
||||
($($item:item)*) => {
|
||||
crate::macros::cfg_feature!("url", $($item)*);
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) use {cfg_feature, cfg_fetch_from_url};
|
||||
@@ -1,21 +1,16 @@
|
||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||
// 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.
|
||||
|
||||
//! Helper methods for fetching metadata from a file or URL.
|
||||
//! Fetch metadata from a URL.
|
||||
|
||||
use crate::error::FetchMetadataError;
|
||||
use crate::Error;
|
||||
use codec::{Decode, Encode};
|
||||
use jsonrpsee::{
|
||||
async_client::ClientBuilder,
|
||||
client_transport::ws::WsTransportClientBuilder,
|
||||
core::client::{ClientT, Error},
|
||||
http_client::HttpClientBuilder,
|
||||
rpc_params,
|
||||
core::client::ClientT, http_client::HttpClientBuilder, rpc_params, ws_client::WsClientBuilder,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
pub use jsonrpsee::client_transport::ws::Url;
|
||||
pub use url::Url;
|
||||
|
||||
/// The metadata version that is fetched from the node.
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
@@ -48,24 +43,20 @@ impl std::str::FromStr for MetadataVersion {
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch metadata from a file.
|
||||
pub fn fetch_metadata_from_file_blocking(
|
||||
path: &std::path::Path,
|
||||
) -> Result<Vec<u8>, FetchMetadataError> {
|
||||
use std::io::Read;
|
||||
let to_err = |err| FetchMetadataError::Io(path.to_string_lossy().into(), err);
|
||||
let mut file = std::fs::File::open(path).map_err(to_err)?;
|
||||
let mut bytes = Vec::new();
|
||||
file.read_to_end(&mut bytes).map_err(to_err)?;
|
||||
/// Returns the metadata bytes from the provided URL.
|
||||
pub async fn from_url(url: Url, version: MetadataVersion) -> Result<Vec<u8>, Error> {
|
||||
let bytes = match url.scheme() {
|
||||
"http" | "https" => fetch_metadata_http(url, version).await,
|
||||
"ws" | "wss" => fetch_metadata_ws(url, version).await,
|
||||
invalid_scheme => Err(Error::InvalidScheme(invalid_scheme.to_owned())),
|
||||
}?;
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
/// Returns the metadata bytes from the provided URL, blocking the current thread.
|
||||
pub fn fetch_metadata_from_url_blocking(
|
||||
url: Url,
|
||||
version: MetadataVersion,
|
||||
) -> Result<Vec<u8>, FetchMetadataError> {
|
||||
tokio_block_on(fetch_metadata_from_url(url, version))
|
||||
pub fn from_url_blocking(url: Url, version: MetadataVersion) -> Result<Vec<u8>, Error> {
|
||||
tokio_block_on(from_url(url, version))
|
||||
}
|
||||
|
||||
// Block on some tokio runtime for sync contexts
|
||||
@@ -77,60 +68,33 @@ fn tokio_block_on<T, Fut: std::future::Future<Output = T>>(fut: Fut) -> T {
|
||||
.block_on(fut)
|
||||
}
|
||||
|
||||
/// Returns the metadata bytes from the provided URL.
|
||||
pub async fn fetch_metadata_from_url(
|
||||
url: Url,
|
||||
version: MetadataVersion,
|
||||
) -> Result<Vec<u8>, FetchMetadataError> {
|
||||
let bytes = match url.scheme() {
|
||||
"http" | "https" => fetch_metadata_http(url, version).await,
|
||||
"ws" | "wss" => fetch_metadata_ws(url, version).await,
|
||||
invalid_scheme => Err(FetchMetadataError::InvalidScheme(invalid_scheme.to_owned())),
|
||||
}?;
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
async fn fetch_metadata_ws(
|
||||
url: Url,
|
||||
version: MetadataVersion,
|
||||
) -> Result<Vec<u8>, FetchMetadataError> {
|
||||
let (sender, receiver) = WsTransportClientBuilder::default()
|
||||
.build(url)
|
||||
.await
|
||||
.map_err(|e| Error::Transport(e.into()))?;
|
||||
|
||||
let client = ClientBuilder::default()
|
||||
.request_timeout(Duration::from_secs(180))
|
||||
async fn fetch_metadata_ws(url: Url, version: MetadataVersion) -> Result<Vec<u8>, Error> {
|
||||
let client = WsClientBuilder::default()
|
||||
.request_timeout(std::time::Duration::from_secs(180))
|
||||
.max_buffer_capacity_per_subscription(4096)
|
||||
.build_with_tokio(sender, receiver);
|
||||
.build(url)
|
||||
.await?;
|
||||
|
||||
fetch_metadata(client, version).await
|
||||
}
|
||||
|
||||
async fn fetch_metadata_http(
|
||||
url: Url,
|
||||
version: MetadataVersion,
|
||||
) -> Result<Vec<u8>, FetchMetadataError> {
|
||||
async fn fetch_metadata_http(url: Url, version: MetadataVersion) -> Result<Vec<u8>, Error> {
|
||||
let client = HttpClientBuilder::default()
|
||||
.request_timeout(Duration::from_secs(180))
|
||||
.request_timeout(std::time::Duration::from_secs(180))
|
||||
.build(url)?;
|
||||
|
||||
fetch_metadata(client, version).await
|
||||
}
|
||||
|
||||
/// The innermost call to fetch metadata:
|
||||
async fn fetch_metadata(
|
||||
client: impl ClientT,
|
||||
version: MetadataVersion,
|
||||
) -> Result<Vec<u8>, FetchMetadataError> {
|
||||
async fn fetch_metadata(client: impl ClientT, version: MetadataVersion) -> Result<Vec<u8>, Error> {
|
||||
const UNSTABLE_METADATA_VERSION: u32 = u32::MAX;
|
||||
|
||||
// Fetch metadata using the "new" state_call interface
|
||||
async fn fetch_inner(
|
||||
client: &impl ClientT,
|
||||
version: MetadataVersion,
|
||||
) -> Result<Vec<u8>, FetchMetadataError> {
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
// Look up supported versions:
|
||||
let supported_versions: Vec<u32> = {
|
||||
let res: String = client
|
||||
@@ -149,14 +113,12 @@ async fn fetch_metadata(
|
||||
.iter()
|
||||
.filter(|&&v| v != UNSTABLE_METADATA_VERSION)
|
||||
.max()
|
||||
.ok_or_else(|| {
|
||||
FetchMetadataError::Other("No valid metadata versions returned".to_string())
|
||||
})?,
|
||||
.ok_or_else(|| Error::Other("No valid metadata versions returned".to_string()))?,
|
||||
MetadataVersion::Unstable => {
|
||||
if supported_versions.contains(&UNSTABLE_METADATA_VERSION) {
|
||||
UNSTABLE_METADATA_VERSION
|
||||
} else {
|
||||
return Err(FetchMetadataError::Other(
|
||||
return Err(Error::Other(
|
||||
"The node does not have an unstable metadata version available".to_string(),
|
||||
));
|
||||
}
|
||||
@@ -165,7 +127,7 @@ async fn fetch_metadata(
|
||||
if supported_versions.contains(&version) {
|
||||
version
|
||||
} else {
|
||||
return Err(FetchMetadataError::Other(format!(
|
||||
return Err(Error::Other(format!(
|
||||
"The node does not have version {version} available"
|
||||
)));
|
||||
}
|
||||
@@ -187,7 +149,7 @@ async fn fetch_metadata(
|
||||
let metadata: Option<frame_metadata::OpaqueMetadata> =
|
||||
Decode::decode(&mut &metadata_bytes[..])?;
|
||||
let Some(metadata) = metadata else {
|
||||
return Err(FetchMetadataError::Other(format!(
|
||||
return Err(Error::Other(format!(
|
||||
"The node does not have version {version} available"
|
||||
)));
|
||||
};
|
||||
@@ -198,13 +160,13 @@ async fn fetch_metadata(
|
||||
async fn fetch_inner_legacy(
|
||||
client: &impl ClientT,
|
||||
version: MetadataVersion,
|
||||
) -> Result<Vec<u8>, FetchMetadataError> {
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
// If the user specifically asks for anything other than version 14 or "latest", error.
|
||||
if !matches!(
|
||||
version,
|
||||
MetadataVersion::Latest | MetadataVersion::Version(14)
|
||||
) {
|
||||
return Err(FetchMetadataError::Other(
|
||||
return Err(Error::Other(
|
||||
"The node can only return version 14 metadata using the legacy API but you've asked for something else"
|
||||
.to_string(),
|
||||
));
|
||||
Reference in New Issue
Block a user