Skip to content

Commit 8a7c172

Browse files
lexnvjsdw
andauthored
Metadata: Retain a subset of metadata pallets (paritytech#879)
* Update cargo.lock to use scale-info v2.4.0 Signed-off-by: Alexandru Vasile <[email protected]> * metadata: Retain only a subset of the metadata Signed-off-by: Alexandru Vasile <[email protected]> * codegen: Generate top level Event Signed-off-by: Alexandru Vasile <[email protected]> * metadata: Only retain DispatchError Signed-off-by: Alexandru Vasile <[email protected]> * metadata: Export just the retain method Signed-off-by: Alexandru Vasile <[email protected]> * cli: Retain pallets Signed-off-by: Alexandru Vasile <[email protected]> * metadata: Do not include extrinsic metadata Signed-off-by: Alexandru Vasile <[email protected]> * retain: Fix clippy Signed-off-by: Alexandru Vasile <[email protected]> * test-runtime: Generate per pallet metadata and rs file Signed-off-by: Alexandru Vasile <[email protected]> * ui-tests: Check per metadata generated files Signed-off-by: Alexandru Vasile <[email protected]> * Revert "test-runtime: Generate per pallet metadata and rs file" This reverts commit 725a2e5. Signed-off-by: Alexandru Vasile <[email protected]> * ui-tests: Adjust path to metadata file Signed-off-by: Alexandru Vasile <[email protected]> * ui-tests: Change drop order to keep `PalletMetadata` around Signed-off-by: Alexandru Vasile <[email protected]> * Update metadata/src/retain.rs Co-authored-by: James Wilson <[email protected]> * Address feedback Signed-off-by: Alexandru Vasile <[email protected]> * retain: Keep extrinsic type Signed-off-by: Alexandru Vasile <[email protected]> * cli: Introduce `MetadataSource` Signed-off-by: Alexandru Vasile <[email protected]> * cli: Use `MetadataSource` helper Signed-off-by: Alexandru Vasile <[email protected]> * cli: Use `FileOrUrl` flatten command argument Signed-off-by: Alexandru Vasile <[email protected]> * retain: Do not include generic type params in retained metadata Signed-off-by: Alexandru Vasile <[email protected]> * Adjust subxt to scale-info v2.5.0 Signed-off-by: Alexandru Vasile <[email protected]> * Update scaleinfo to v2.5.0 Signed-off-by: Alexandru Vasile <[email protected]> * Remove deprecated fn Signed-off-by: Alexandru Vasile <[email protected]> * testing: Fix clippy Signed-off-by: Alexandru Vasile <[email protected]> * benches: Use inner fields of scale info Signed-off-by: Alexandru Vasile <[email protected]> * address nits, and strip RuntimeCall type instead of trying to filter out use of it for better overall wins/clarity * fix UI test * move utils out of commands folder and fix clippy etc * address nits --------- Signed-off-by: Alexandru Vasile <[email protected]> Co-authored-by: James Wilson <[email protected]>
1 parent c08eb6c commit 8a7c172

File tree

14 files changed

+464
-72
lines changed

14 files changed

+464
-72
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/src/commands/codegen.rs

+4-25
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
33
// see LICENSE for license details.
44

5+
use crate::utils::FileOrUrl;
56
use clap::Parser as ClapParser;
67
use color_eyre::eyre;
7-
use jsonrpsee::client_transport::ws::Uri;
8-
use std::{fs, io::Read, path::PathBuf};
98
use subxt_codegen::{DerivesRegistry, TypeSubstitutes, TypeSubstitutionError};
109

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

6762
pub async fn run(opts: Opts) -> color_eyre::Result<()> {
68-
let bytes = if let Some(file) = opts.file.as_ref() {
69-
if opts.url.is_some() {
70-
eyre::bail!("specify one of `--url` or `--file` but not both")
71-
};
72-
73-
let mut file = fs::File::open(file)?;
74-
let mut bytes = Vec::new();
75-
file.read_to_end(&mut bytes)?;
76-
bytes
77-
} else {
78-
let url = opts.url.unwrap_or_else(|| {
79-
"http://localhost:9933"
80-
.parse::<Uri>()
81-
.expect("default url is valid")
82-
});
83-
subxt_codegen::utils::fetch_metadata_bytes(&url).await?
84-
};
63+
let bytes = opts.file_or_url.fetch().await?;
8564

8665
codegen(
8766
&bytes,

cli/src/commands/metadata.rs

+30-16
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,61 @@
22
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
33
// see LICENSE for license details.
44

5+
use crate::utils::FileOrUrl;
56
use clap::Parser as ClapParser;
67
use color_eyre::eyre;
7-
use frame_metadata::RuntimeMetadataPrefixed;
8-
use jsonrpsee::client_transport::ws::Uri;
9-
use scale::Decode;
8+
use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed};
9+
use scale::{Decode, Encode};
1010
use std::io::{self, Write};
11-
use subxt_codegen::utils::fetch_metadata_hex;
11+
use subxt_metadata::retain_metadata_pallets;
1212

1313
/// Download metadata from a substrate node, for use with `subxt` codegen.
1414
#[derive(Debug, ClapParser)]
1515
pub struct Opts {
16-
/// The url of the substrate node to query for metadata.
17-
#[clap(
18-
name = "url",
19-
long,
20-
value_parser,
21-
default_value = "http://localhost:9933"
22-
)]
23-
url: Uri,
16+
#[command(flatten)]
17+
file_or_url: FileOrUrl,
2418
/// The format of the metadata to display: `json`, `hex` or `bytes`.
2519
#[clap(long, short, default_value = "bytes")]
2620
format: String,
21+
/// Generate a subset of the metadata that contains only the
22+
/// types needed to represent the provided pallets.
23+
#[clap(long, use_value_delimiter = true, value_parser)]
24+
pallets: Option<Vec<String>>,
2725
}
2826

2927
pub async fn run(opts: Opts) -> color_eyre::Result<()> {
30-
let hex_data = fetch_metadata_hex(&opts.url).await?;
28+
let bytes = opts.file_or_url.fetch().await?;
29+
let mut metadata = <RuntimeMetadataPrefixed as Decode>::decode(&mut &bytes[..])?;
30+
31+
if let Some(pallets) = opts.pallets {
32+
let metadata_v14 = match &mut metadata.1 {
33+
RuntimeMetadata::V14(metadata_v14) => metadata_v14,
34+
_ => {
35+
return Err(eyre::eyre!(
36+
"Unsupported metadata version {:?}, expected V14.",
37+
metadata.1
38+
))
39+
}
40+
};
41+
42+
retain_metadata_pallets(metadata_v14, |pallet_name| {
43+
pallets.iter().any(|p| &**p == pallet_name)
44+
});
45+
}
3146

3247
match opts.format.as_str() {
3348
"json" => {
34-
let bytes = hex::decode(hex_data.trim_start_matches("0x"))?;
35-
let metadata = <RuntimeMetadataPrefixed as Decode>::decode(&mut &bytes[..])?;
3649
let json = serde_json::to_string_pretty(&metadata)?;
3750
println!("{json}");
3851
Ok(())
3952
}
4053
"hex" => {
54+
let hex_data = format!("0x{:?}", hex::encode(metadata.encode()));
4155
println!("{hex_data}");
4256
Ok(())
4357
}
4458
"bytes" => {
45-
let bytes = hex::decode(hex_data.trim_start_matches("0x"))?;
59+
let bytes = metadata.encode();
4660
Ok(io::stdout().write_all(&bytes)?)
4761
}
4862
_ => Err(eyre::eyre!(

cli/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![deny(unused_crate_dependencies)]
66

77
mod commands;
8+
mod utils;
89
use clap::Parser as ClapParser;
910

1011
/// Subxt utilities for interacting with Substrate based nodes.

cli/src/utils.rs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
2+
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3+
// see LICENSE for license details.
4+
5+
use clap::Args;
6+
use color_eyre::eyre;
7+
use std::{fs, io::Read, path::PathBuf};
8+
use subxt_codegen::utils::Uri;
9+
10+
/// The source of the metadata.
11+
#[derive(Debug, Args)]
12+
pub struct FileOrUrl {
13+
/// The url of the substrate node to query for metadata for codegen.
14+
#[clap(long, value_parser)]
15+
url: Option<Uri>,
16+
/// The path to the encoded metadata file.
17+
#[clap(long, value_parser)]
18+
file: Option<PathBuf>,
19+
}
20+
21+
impl FileOrUrl {
22+
/// Fetch the metadata bytes.
23+
pub async fn fetch(&self) -> color_eyre::Result<Vec<u8>> {
24+
match (&self.file, &self.url) {
25+
// Can't provide both --file and --url
26+
(Some(_), Some(_)) => {
27+
eyre::bail!("specify one of `--url` or `--file` but not both")
28+
}
29+
// Load from --file path
30+
(Some(path), None) => {
31+
let mut file = fs::File::open(path)?;
32+
let mut bytes = Vec::new();
33+
file.read_to_end(&mut bytes)?;
34+
Ok(bytes)
35+
}
36+
// Fetch from --url
37+
(None, Some(uri)) => Ok(subxt_codegen::utils::fetch_metadata_bytes(uri).await?),
38+
// Default if neither is provided; fetch from local url
39+
(None, None) => {
40+
let uri = Uri::from_static("http://localhost:9933");
41+
Ok(subxt_codegen::utils::fetch_metadata_bytes(&uri).await?)
42+
}
43+
}
44+
}
45+
}

codegen/src/api/mod.rs

+23-28
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,13 @@ impl RuntimeGenerator {
235235
) -> Result<TokenStream2, CodegenError> {
236236
let item_mod_attrs = item_mod.attrs.clone();
237237
let item_mod_ir = ir::ItemMod::try_from(item_mod)?;
238+
let default_derives = derives.default_derives();
238239

239240
let type_gen = TypeGenerator::new(
240241
&self.metadata.types,
241242
"runtime_types",
242243
type_substitutes,
243-
derives,
244+
derives.clone(),
244245
crate_path.clone(),
245246
should_gen_docs,
246247
);
@@ -258,28 +259,6 @@ impl RuntimeGenerator {
258259
})
259260
.collect::<Vec<_>>();
260261

261-
// Get the path to the `Runtime` struct. We assume that the same path contains
262-
// RuntimeCall and RuntimeEvent.
263-
let runtime_type_id = self.metadata.ty.id;
264-
let runtime_path_segments = self
265-
.metadata
266-
.types
267-
.resolve(runtime_type_id)
268-
.ok_or(CodegenError::TypeNotFound(runtime_type_id))?
269-
.path
270-
.namespace()
271-
.iter()
272-
.map(|part| syn::PathSegment::from(format_ident!("{}", part)));
273-
let runtime_path_suffix = syn::Path {
274-
leading_colon: None,
275-
segments: syn::punctuated::Punctuated::from_iter(runtime_path_segments),
276-
};
277-
let runtime_path = if runtime_path_suffix.segments.is_empty() {
278-
quote!(#types_mod_ident)
279-
} else {
280-
quote!(#types_mod_ident::#runtime_path_suffix)
281-
};
282-
283262
// Pallet names and their length are used to create PALLETS array.
284263
// The array is used to identify the pallets composing the metadata for
285264
// validation of just those pallets.
@@ -344,6 +323,26 @@ impl RuntimeGenerator {
344323
})
345324
.collect::<Result<Vec<_>, CodegenError>>()?;
346325

326+
let outer_event_variants = self.metadata.pallets.iter().filter_map(|p| {
327+
let variant_name = format_ident!("{}", p.name);
328+
let mod_name = format_ident!("{}", p.name.to_string().to_snake_case());
329+
let index = proc_macro2::Literal::u8_unsuffixed(p.index);
330+
331+
p.event.as_ref().map(|_| {
332+
quote! {
333+
#[codec(index = #index)]
334+
#variant_name(#mod_name::Event),
335+
}
336+
})
337+
});
338+
339+
let outer_event = quote! {
340+
#default_derives
341+
pub enum Event {
342+
#( #outer_event_variants )*
343+
}
344+
};
345+
347346
let root_event_if_arms = self.metadata.pallets.iter().filter_map(|p| {
348347
let variant_name_str = &p.name;
349348
let variant_name = format_ident!("{}", variant_name_str);
@@ -402,14 +401,10 @@ impl RuntimeGenerator {
402401
// Identify the pallets composing the static metadata by name.
403402
pub static PALLETS: [&str; #pallet_names_len] = [ #(#pallet_names,)* ];
404403

405-
/// The statically generated runtime call type.
406-
pub type Call = #runtime_path::RuntimeCall;
407-
408404
/// The error type returned when there is a runtime issue.
409405
pub type DispatchError = #types_mod_ident::sp_runtime::DispatchError;
410406

411-
// Make the runtime event type easily accessible, and impl RootEvent to help decode into it.
412-
pub type Event = #runtime_path::RuntimeEvent;
407+
#outer_event
413408

414409
impl #crate_path::events::RootEvent for Event {
415410
fn root_event(pallet_bytes: &[u8], pallet_name: &str, pallet_ty: u32, metadata: &#crate_path::Metadata) -> Result<Self, #crate_path::Error> {

metadata/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
33
// see LICENSE for license details.
44

5+
mod retain;
6+
57
use frame_metadata::{
68
ExtrinsicMetadata, RuntimeMetadataV14, StorageEntryMetadata, StorageEntryType,
79
};
10+
pub use retain::retain_metadata_pallets;
811
use scale_info::{form::PortableForm, Field, PortableRegistry, TypeDef, Variant};
912
use std::collections::HashSet;
1013

0 commit comments

Comments
 (0)