mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-25 02:27:58 +00:00
CLI subxt explore commands (#950)
* add cli command to explore metadata * fmt and clippy * Bump serde from 1.0.160 to 1.0.162 (#948) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.160 to 1.0.162. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.160...1.0.162) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * extrinsics: Decode extrinsics from blocks (#929) * Update polkadot.scale Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics: Add extrinsics client Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics: Decode extrinsics Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Add extrinsic error Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * blocks: Expose extrinsics Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * examples: Fetch and decode block extrinsics Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Fix clippy Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics: Fetch pallet and variant index Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Move extrinsics on the subxt::blocks Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * example: Adjust example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Collect ExtrinsicMetadata Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Implement StaticExtrinsic for the calls Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust examples Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Add root level Call enum Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust testing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Add new decode interface Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Merge ExtrinsicError with BlockError Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * examples: Find first extrinsic Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Move code to extrinsic_types Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add Extrinsic struct Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust examples Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * test: Decode extinsics Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics/test: Add fake metadata for static decoding Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics/test: Decode from insufficient bytes Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics/test: Check unsupported versions Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics/test: Statically decode to root and pallet enums Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics/tests: Remove clones Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * blocks: Fetch block body inline Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * blocks: Rename ExtrinsicIds to ExtrinsicPartTypeIds Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics/test: Check decode as_extrinsic Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * blocks: Remove InsufficientData error Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * blocks: Return error from extrinsic_metadata Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * extrinsics: Postpone decoding of call bytes Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata_type: Rename variables Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust calls path for example and tests Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * examples: Remove traces Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * book: Add extrinsics documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * book: Improve extrinsics docs Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> Co-authored-by: James Wilson <james@jsdw.me> * change doc comments * add constants exploration * add storage access interface but not done yet * add storage exploration * formatting * remove dbg * some small tweaks * fix formatting and scale value for storage * split up files, sort entries, change formatting * fmt and clippy fix * fix minor formatting issue * implement suggestions * implement other suggestion, fix bug --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: James Wilson <james@jsdw.me>
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
use crate::utils::{print_docs_with_indent, FileOrUrl};
|
||||
use clap::{Parser as ClapParser, Subcommand};
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use std::write;
|
||||
|
||||
use codec::Decode;
|
||||
use color_eyre::eyre::eyre;
|
||||
use frame_metadata::v15::RuntimeMetadataV15;
|
||||
use frame_metadata::RuntimeMetadataPrefixed;
|
||||
|
||||
use syn::__private::str;
|
||||
|
||||
use crate::commands::explore::calls::{explore_calls, CallsSubcommand};
|
||||
use crate::commands::explore::constants::{explore_constants, ConstantsSubcommand};
|
||||
use crate::commands::explore::storage::{explore_storage, StorageSubcommand};
|
||||
|
||||
use subxt::Metadata;
|
||||
|
||||
mod calls;
|
||||
mod constants;
|
||||
mod storage;
|
||||
|
||||
/// Explore pallets, calls, call parameters, storage entries and constants. Also allows for creating (unsigned) extrinsics.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ## Pallets
|
||||
///
|
||||
/// Show the pallets that are available:
|
||||
/// ```
|
||||
/// subxt explore --file=polkadot_metadata.scale
|
||||
/// ```
|
||||
///
|
||||
/// ## Calls
|
||||
///
|
||||
/// Show the calls in a pallet:
|
||||
/// ```
|
||||
/// subxt explore Balances calls
|
||||
/// ```
|
||||
/// Show the call parameters a call expects:
|
||||
/// ```
|
||||
/// subxt explore Balances calls transfer
|
||||
/// ```
|
||||
/// Create an unsigned extrinsic from a scale value, validate it and output its hex representation
|
||||
/// ```
|
||||
/// subxt explore Grandpa calls note_stalled { "delay": 5, "best_finalized_block_number": 5 }
|
||||
/// # Encoded call data:
|
||||
/// # 0x2c0411020500000005000000
|
||||
/// subxt explore Balances calls transfer "{ \"dest\": v\"Raw\"((255, 255, 255)), \"value\": 0 }"
|
||||
/// # Encoded call data:
|
||||
/// # 0x24040607020cffffff00
|
||||
/// ```
|
||||
/// ## Constants
|
||||
///
|
||||
/// Show the constants in a pallet:
|
||||
/// ```
|
||||
/// subxt explore Balances constants
|
||||
/// ```
|
||||
/// ## Storage
|
||||
///
|
||||
/// Show the storage entries in a pallet
|
||||
/// ```
|
||||
/// subxt explore Alliance storage
|
||||
/// ```
|
||||
/// Show the types and value of a specific storage entry
|
||||
/// ```
|
||||
/// subxt explore Alliance storage Announcements [KEY_SCALE_VALUE]
|
||||
/// ```
|
||||
///
|
||||
#[derive(Debug, ClapParser)]
|
||||
pub struct Opts {
|
||||
#[command(flatten)]
|
||||
file_or_url: FileOrUrl,
|
||||
pallet: Option<String>,
|
||||
#[command(subcommand)]
|
||||
pallet_subcommand: Option<PalletSubcommand>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum PalletSubcommand {
|
||||
Calls(CallsSubcommand),
|
||||
Constants(ConstantsSubcommand),
|
||||
Storage(StorageSubcommand),
|
||||
}
|
||||
|
||||
/// cargo run -- explore --file=../artifacts/polkadot_metadata.scale
|
||||
pub async fn run(opts: Opts) -> color_eyre::Result<()> {
|
||||
// get the metadata
|
||||
let bytes = opts.file_or_url.fetch().await?;
|
||||
let metadata_prefixed = <RuntimeMetadataPrefixed as Decode>::decode(&mut &bytes[..])?;
|
||||
let metadata = Metadata::try_from(metadata_prefixed)?;
|
||||
|
||||
// if no pallet specified, show user the pallets to choose from:
|
||||
let Some(pallet_name) = opts.pallet else {
|
||||
let available_pallets = print_available_pallets(metadata.runtime_metadata());
|
||||
println!("Usage:\n subxt explore <PALLET>\n explore a specific pallet\n\n{available_pallets}", );
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// if specified pallet is wrong, show user the pallets to choose from (but this time as an error):
|
||||
let Some(pallet_metadata) = metadata.runtime_metadata().pallets.iter().find(|pallet| pallet.name.to_lowercase() == pallet_name.to_lowercase())else {
|
||||
return Err(eyre!("pallet \"{}\" not found in metadata!\n{}", pallet_name, print_available_pallets(metadata.runtime_metadata())));
|
||||
};
|
||||
|
||||
// if correct pallet was specified but no subcommand, instruct the user how to proceed:
|
||||
let Some(pallet_subcomand) = opts.pallet_subcommand else {
|
||||
let docs_string = print_docs_with_indent(&pallet_metadata.docs, 4);
|
||||
let mut output = String::new();
|
||||
if !docs_string.is_empty() {
|
||||
write!(output, "Description:\n{docs_string}")?;
|
||||
}
|
||||
write!(output, "Usage:")?;
|
||||
write!(output, "\n subxt explore {pallet_name} calls\n explore the calls that can be made into this pallet")?;
|
||||
write!(output, "\n subxt explore {pallet_name} constants\n explore the constants held in this pallet")?;
|
||||
write!(output, "\n subxt explore {pallet_name} storage\n explore the storage values held in this pallet")?;
|
||||
println!("{output}");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
match pallet_subcomand {
|
||||
PalletSubcommand::Calls(command) => explore_calls(command, &metadata, pallet_metadata),
|
||||
PalletSubcommand::Constants(command) => {
|
||||
explore_constants(command, &metadata, pallet_metadata)
|
||||
}
|
||||
PalletSubcommand::Storage(command) => {
|
||||
// if the metadata came from some url, we use that same url to make storage calls against.
|
||||
let node_url = opts.file_or_url.url.map(|url| url.to_string());
|
||||
explore_storage(command, &metadata, pallet_metadata, node_url).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_available_pallets(metadata_v15: &RuntimeMetadataV15) -> String {
|
||||
if metadata_v15.pallets.is_empty() {
|
||||
"There are no <PALLET> values available.".to_string()
|
||||
} else {
|
||||
let mut output = "Available <PALLET> values are:".to_string();
|
||||
let mut strings: Vec<_> = metadata_v15.pallets.iter().map(|p| &p.name).collect();
|
||||
strings.sort();
|
||||
for pallet in strings {
|
||||
write!(output, "\n {}", pallet).unwrap();
|
||||
}
|
||||
output
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user