Skip to content
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

Metadata: Retain a subset of metadata pallets #879

Merged
merged 32 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4dbbd16
Update cargo.lock to use scale-info v2.4.0
lexnv Mar 23, 2023
99934de
metadata: Retain only a subset of the metadata
lexnv Mar 23, 2023
3f0f55f
codegen: Generate top level Event
lexnv Mar 24, 2023
704c512
metadata: Only retain DispatchError
lexnv Mar 24, 2023
d49c801
metadata: Export just the retain method
lexnv Mar 24, 2023
5ebab47
cli: Retain pallets
lexnv Mar 24, 2023
47e9163
metadata: Do not include extrinsic metadata
lexnv Mar 24, 2023
19eec1f
retain: Fix clippy
lexnv Mar 24, 2023
725a2e5
test-runtime: Generate per pallet metadata and rs file
lexnv Mar 27, 2023
8515b1e
ui-tests: Check per metadata generated files
lexnv Mar 27, 2023
a8d368b
Revert "test-runtime: Generate per pallet metadata and rs file"
lexnv Mar 27, 2023
64c316b
Merge remote-tracking branch 'origin/master' into lexnv/stirp_metadata
lexnv Mar 27, 2023
36bfe9e
ui-tests: Adjust path to metadata file
lexnv Mar 27, 2023
e90920c
ui-tests: Change drop order to keep `PalletMetadata` around
lexnv Mar 27, 2023
396cc7c
Update metadata/src/retain.rs
lexnv Mar 28, 2023
cc1809f
Address feedback
lexnv Mar 28, 2023
5a3c81d
retain: Keep extrinsic type
lexnv Mar 27, 2023
4a71546
cli: Introduce `MetadataSource`
lexnv Mar 28, 2023
a663236
cli: Use `MetadataSource` helper
lexnv Mar 28, 2023
d8b9824
cli: Use `FileOrUrl` flatten command argument
lexnv Mar 29, 2023
01ff1b5
retain: Do not include generic type params in retained metadata
lexnv Mar 29, 2023
e28bb8a
Adjust subxt to scale-info v2.5.0
lexnv Mar 29, 2023
2dee176
Update scaleinfo to v2.5.0
lexnv Mar 29, 2023
13cbbd6
Remove deprecated fn
lexnv Mar 29, 2023
115fbfb
testing: Fix clippy
lexnv Mar 29, 2023
6284f4a
benches: Use inner fields of scale info
lexnv Mar 29, 2023
314cb7b
Merge branch 'master' into lexnv/stirp_metadata
jsdw Apr 3, 2023
c62309f
Merge branch 'master' into lexnv/stirp_metadata
jsdw Apr 4, 2023
72e828d
address nits, and strip RuntimeCall type instead of trying to filter …
jsdw Apr 4, 2023
17d1976
fix UI test
jsdw Apr 4, 2023
e6e3016
move utils out of commands folder and fix clippy etc
jsdw Apr 4, 2023
98e3684
address nits
jsdw Apr 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 4 additions & 25 deletions cli/src/commands/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.

use crate::utils::FileOrUrl;
use clap::Parser as ClapParser;
use color_eyre::eyre;
use jsonrpsee::client_transport::ws::Uri;
use std::{fs, io::Read, path::PathBuf};
use subxt_codegen::{DerivesRegistry, TypeSubstitutes, TypeSubstitutionError};

/// Generate runtime API client code from metadata.
Expand All @@ -15,12 +14,8 @@ use subxt_codegen::{DerivesRegistry, TypeSubstitutes, TypeSubstitutionError};
/// `subxt codegen | rustfmt --edition=2018 --emit=stdout`
#[derive(Debug, ClapParser)]
pub struct Opts {
/// The url of the substrate node to query for metadata for codegen.
#[clap(name = "url", long, value_parser)]
url: Option<Uri>,
/// The path to the encoded metadata file.
#[clap(short, long, value_parser)]
file: Option<PathBuf>,
#[command(flatten)]
file_or_url: FileOrUrl,
/// Additional derives
#[clap(long = "derive")]
derives: Vec<String>,
Expand Down Expand Up @@ -65,23 +60,7 @@ fn substitute_type_parser(src: &str) -> Result<(String, String), String> {
}

pub async fn run(opts: Opts) -> color_eyre::Result<()> {
let bytes = if let Some(file) = opts.file.as_ref() {
if opts.url.is_some() {
eyre::bail!("specify one of `--url` or `--file` but not both")
};

let mut file = fs::File::open(file)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)?;
bytes
} else {
let url = opts.url.unwrap_or_else(|| {
"http://localhost:9933"
.parse::<Uri>()
.expect("default url is valid")
});
subxt_codegen::utils::fetch_metadata_bytes(&url).await?
};
let bytes = opts.file_or_url.fetch().await?;

codegen(
&bytes,
Expand Down
46 changes: 30 additions & 16 deletions cli/src/commands/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,61 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.

use crate::utils::FileOrUrl;
use clap::Parser as ClapParser;
use color_eyre::eyre;
use frame_metadata::RuntimeMetadataPrefixed;
use jsonrpsee::client_transport::ws::Uri;
use scale::Decode;
use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed};
use scale::{Decode, Encode};
use std::io::{self, Write};
use subxt_codegen::utils::fetch_metadata_hex;
use subxt_metadata::retain_metadata_pallets;

/// Download metadata from a substrate node, for use with `subxt` codegen.
#[derive(Debug, ClapParser)]
pub struct Opts {
/// The url of the substrate node to query for metadata.
#[clap(
name = "url",
long,
value_parser,
default_value = "http://localhost:9933"
)]
url: Uri,
#[command(flatten)]
file_or_url: FileOrUrl,
/// The format of the metadata to display: `json`, `hex` or `bytes`.
#[clap(long, short, default_value = "bytes")]
format: String,
/// Generate a subset of the metadata that contains only the
/// types needed to represent the provided pallets.
#[clap(long, use_value_delimiter = true, value_parser)]
pallets: Option<Vec<String>>,
}

pub async fn run(opts: Opts) -> color_eyre::Result<()> {
let hex_data = fetch_metadata_hex(&opts.url).await?;
let bytes = opts.file_or_url.fetch().await?;
let mut metadata = <RuntimeMetadataPrefixed as Decode>::decode(&mut &bytes[..])?;

if let Some(pallets) = opts.pallets {
let metadata_v14 = match &mut metadata.1 {
RuntimeMetadata::V14(metadata_v14) => metadata_v14,
_ => {
return Err(eyre::eyre!(
"Unsupported metadata version {:?}, expected V14.",
metadata.1
))
}
};

retain_metadata_pallets(metadata_v14, |pallet_name| {
pallets.iter().any(|p| &**p == pallet_name)
});
}

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}");
Ok(())
}
"hex" => {
let hex_data = format!("0x{:?}", hex::encode(metadata.encode()));
println!("{hex_data}");
Ok(())
}
"bytes" => {
let bytes = hex::decode(hex_data.trim_start_matches("0x"))?;
let bytes = metadata.encode();
Ok(io::stdout().write_all(&bytes)?)
}
_ => Err(eyre::eyre!(
Expand Down
1 change: 1 addition & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#![deny(unused_crate_dependencies)]

mod commands;
mod utils;
use clap::Parser as ClapParser;

/// Subxt utilities for interacting with Substrate based nodes.
Expand Down
45 changes: 45 additions & 0 deletions cli/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.

use clap::Args;
use color_eyre::eyre;
use std::{fs, io::Read, path::PathBuf};
use subxt_codegen::utils::Uri;

/// The source of the metadata.
#[derive(Debug, Args)]
pub struct FileOrUrl {
/// The url of the substrate node to query for metadata for codegen.
#[clap(long, value_parser)]
url: Option<Uri>,
/// The path to the encoded metadata file.
#[clap(long, value_parser)]
file: Option<PathBuf>,
}

impl FileOrUrl {
/// Fetch the metadata bytes.
pub async fn fetch(&self) -> color_eyre::Result<Vec<u8>> {
match (&self.file, &self.url) {
// Can't provide both --file and --url
(Some(_), Some(_)) => {
eyre::bail!("specify one of `--url` or `--file` but not both")
}
// Load from --file path
(Some(path), None) => {
let mut file = fs::File::open(path)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)?;
Ok(bytes)
}
// Fetch from --url
(None, Some(uri)) => Ok(subxt_codegen::utils::fetch_metadata_bytes(uri).await?),
// Default if neither is provided; fetch from local url
(None, None) => {
let uri = Uri::from_static("http://localhost:9933");
Ok(subxt_codegen::utils::fetch_metadata_bytes(&uri).await?)
}
}
}
}
51 changes: 23 additions & 28 deletions codegen/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,13 @@ impl RuntimeGenerator {
) -> Result<TokenStream2, CodegenError> {
let item_mod_attrs = item_mod.attrs.clone();
let item_mod_ir = ir::ItemMod::try_from(item_mod)?;
let default_derives = derives.default_derives();

let type_gen = TypeGenerator::new(
&self.metadata.types,
"runtime_types",
type_substitutes,
derives,
derives.clone(),
crate_path.clone(),
should_gen_docs,
);
Expand All @@ -258,28 +259,6 @@ impl RuntimeGenerator {
})
.collect::<Vec<_>>();

// Get the path to the `Runtime` struct. We assume that the same path contains
// RuntimeCall and RuntimeEvent.
let runtime_type_id = self.metadata.ty.id;
let runtime_path_segments = self
.metadata
.types
.resolve(runtime_type_id)
.ok_or(CodegenError::TypeNotFound(runtime_type_id))?
.path
.namespace()
.iter()
.map(|part| syn::PathSegment::from(format_ident!("{}", part)));
let runtime_path_suffix = syn::Path {
leading_colon: None,
segments: syn::punctuated::Punctuated::from_iter(runtime_path_segments),
};
let runtime_path = if runtime_path_suffix.segments.is_empty() {
quote!(#types_mod_ident)
} else {
quote!(#types_mod_ident::#runtime_path_suffix)
};

// 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.
Expand Down Expand Up @@ -344,6 +323,26 @@ impl RuntimeGenerator {
})
.collect::<Result<Vec<_>, CodegenError>>()?;

let outer_event_variants = self.metadata.pallets.iter().filter_map(|p| {
let variant_name = format_ident!("{}", p.name);
let mod_name = format_ident!("{}", p.name.to_string().to_snake_case());
let index = proc_macro2::Literal::u8_unsuffixed(p.index);

p.event.as_ref().map(|_| {
quote! {
#[codec(index = #index)]
#variant_name(#mod_name::Event),
}
})
});

let outer_event = quote! {
#default_derives
pub enum Event {
#( #outer_event_variants )*
}
};

let root_event_if_arms = self.metadata.pallets.iter().filter_map(|p| {
let variant_name_str = &p.name;
let variant_name = format_ident!("{}", variant_name_str);
Expand Down Expand Up @@ -402,14 +401,10 @@ impl RuntimeGenerator {
// Identify the pallets composing the static metadata by name.
pub static PALLETS: [&str; #pallet_names_len] = [ #(#pallet_names,)* ];

/// The statically generated runtime call type.
pub type Call = #runtime_path::RuntimeCall;

/// The error type returned when there is a runtime issue.
pub type DispatchError = #types_mod_ident::sp_runtime::DispatchError;

// Make the runtime event type easily accessible, and impl RootEvent to help decode into it.
pub type Event = #runtime_path::RuntimeEvent;
#outer_event
lexnv marked this conversation as resolved.
Show resolved Hide resolved
jsdw marked this conversation as resolved.
Show resolved Hide resolved

impl #crate_path::events::RootEvent for Event {
fn root_event(pallet_bytes: &[u8], pallet_name: &str, pallet_ty: u32, metadata: &#crate_path::Metadata) -> Result<Self, #crate_path::Error> {
Expand Down
3 changes: 3 additions & 0 deletions metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.

mod retain;

use frame_metadata::{
ExtrinsicMetadata, RuntimeMetadataV14, StorageEntryMetadata, StorageEntryType,
};
pub use retain::retain_metadata_pallets;
use scale_info::{form::PortableForm, Field, PortableRegistry, TypeDef, Variant};
use std::collections::HashSet;

Expand Down
Loading