Skip to content

Commit

Permalink
refactor: terminology (#368)
Browse files Browse the repository at this point in the history
* refactor: terminology

* refactor: simply pallet/function relationship

* fix: amend call_data conflicts after refactor
  • Loading branch information
evilrobot-01 authored Dec 9, 2024
1 parent 9903944 commit b19ece8
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 241 deletions.
216 changes: 105 additions & 111 deletions crates/pop-cli/src/commands/call/parachain.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions crates/pop-cli/tests/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ name = "collator-01"
// Wait for the networks to initialize. Increased timeout to accommodate CI environment delays.
sleep(Duration::from_secs(50)).await;

// `pop call parachain --pallet System --extrinsic remark --args "0x11" --url
// `pop call parachain --pallet System --function remark --args "0x11" --url
// ws://127.0.0.1:random_port --suri //Alice --skip-confirm`
Command::cargo_bin("pop")
.unwrap()
Expand All @@ -142,7 +142,7 @@ name = "collator-01"
"parachain",
"--pallet",
"System",
"--extrinsic",
"--function",
"remark",
"--args",
"0x11",
Expand Down
13 changes: 7 additions & 6 deletions crates/pop-parachains/src/call/metadata/action.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0

use super::{find_extrinsic_by_name, Pallet};
use super::{find_dispatchable_by_name, Pallet};
use strum::{EnumMessage as _, EnumProperty as _, VariantArray as _};
use strum_macros::{AsRefStr, Display, EnumMessage, EnumProperty, EnumString, VariantArray};

Expand Down Expand Up @@ -91,8 +91,8 @@ impl Action {
self.get_detailed_message().unwrap_or_default()
}

/// Get the extrinsic name corresponding to the action.
pub fn extrinsic_name(&self) -> &str {
/// Get the dispatchable function name corresponding to the action.
pub fn function_name(&self) -> &str {
self.get_message().unwrap_or_default()
}

Expand All @@ -109,7 +109,8 @@ impl Action {
pub fn supported_actions(pallets: &[Pallet]) -> Vec<Action> {
let mut actions = Vec::new();
for action in Action::VARIANTS.iter() {
if find_extrinsic_by_name(pallets, action.pallet_name(), action.extrinsic_name()).is_ok() {
if find_dispatchable_by_name(pallets, action.pallet_name(), action.function_name()).is_ok()
{
actions.push(action.clone());
}
}
Expand Down Expand Up @@ -162,7 +163,7 @@ mod tests {
}

#[test]
fn extrinsic_names_are_correct() {
fn function_names_are_correct() {
let pallets = HashMap::from([
(Action::CreateAsset, "create"),
(Action::MintAsset, "mint"),
Expand All @@ -175,7 +176,7 @@ mod tests {
]);

for action in Action::VARIANTS.iter() {
assert_eq!(&action.extrinsic_name(), pallets.get(action).unwrap(),);
assert_eq!(&action.function_name(), pallets.get(action).unwrap(),);
}
}

Expand Down
123 changes: 64 additions & 59 deletions crates/pop-parachains/src/call/metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use subxt::{dynamic::Value, Metadata, OnlineClient, SubstrateConfig};
pub mod action;
pub mod params;

/// Represents a pallet in the blockchain, including its extrinsics.
/// Represents a pallet in the blockchain, including its dispatchable functions.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Pallet {
/// The name of the pallet.
Expand All @@ -18,8 +18,8 @@ pub struct Pallet {
pub index: u8,
/// The documentation of the pallet.
pub docs: String,
/// The extrinsics of the pallet.
pub extrinsics: Vec<Extrinsic>,
/// The dispatchable functions of the pallet.
pub functions: Vec<Function>,
}

impl Display for Pallet {
Expand All @@ -28,29 +28,30 @@ impl Display for Pallet {
}
}

/// Represents an extrinsic.
/// Represents a dispatchable function.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Extrinsic {
/// The name of the extrinsic.
pub struct Function {
/// The pallet containing the dispatchable function.
pub pallet: String,
/// The name of the function.
pub name: String,
/// The index of the extrinsic within the pallet.
/// The index of the function within the pallet.
pub index: u8,
/// The documentation of the extrinsic.
/// The documentation of the function.
pub docs: String,
/// The parameters of the extrinsic.
/// The parameters of the function.
pub params: Vec<Param>,
/// Whether this extrinsic is supported (no recursive or unsupported types like `RuntimeCall`).
/// Whether this function is supported (no recursive or unsupported types like `RuntimeCall`).
pub is_supported: bool,
}

impl Display for Extrinsic {
impl Display for Function {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}

/// Parses the chain metadata to extract information about pallets and their extrinsics with its
/// parameters.
/// Parses the chain metadata to extract information about pallets and their dispatchable functions.
///
/// # Arguments
/// * `client`: The client to interact with the chain.
Expand All @@ -62,23 +63,24 @@ pub fn parse_chain_metadata(client: &OnlineClient<SubstrateConfig>) -> Result<Ve
let pallets = metadata
.pallets()
.map(|pallet| {
let extrinsics = pallet
let functions = pallet
.call_variants()
.map(|variants| {
variants
.iter()
.map(|variant| {
let mut is_supported = true;

// Parse parameters for the extrinsic
// Parse parameters for the dispatchable function.
let params = {
let mut parsed_params = Vec::new();
for field in &variant.fields {
match params::field_to_param(client, field) {
Ok(param) => parsed_params.push(param),
Err(_) => {
// If an error occurs while parsing the values, mark the
// extrinsic as unsupported rather than error.
// dispatchable function as unsupported rather than
// error.
is_supported = false;
parsed_params.clear();
break;
Expand All @@ -88,7 +90,8 @@ pub fn parse_chain_metadata(client: &OnlineClient<SubstrateConfig>) -> Result<Ve
parsed_params
};

Ok(Extrinsic {
Ok(Function {
pallet: pallet.name().to_string(),
name: variant.name.clone(),
index: variant.index,
docs: if is_supported {
Expand All @@ -102,21 +105,21 @@ pub fn parse_chain_metadata(client: &OnlineClient<SubstrateConfig>) -> Result<Ve
.join(" ")
} else {
// To display the message in the UI
"Extrinsic Not Supported".to_string()
"Function Not Supported".to_string()
},
params,
is_supported,
})
})
.collect::<Result<Vec<Extrinsic>, Error>>()
.collect::<Result<Vec<Function>, Error>>()
})
.unwrap_or_else(|| Ok(vec![]))?;

Ok(Pallet {
name: pallet.name().to_string(),
index: pallet.index(),
docs: pallet.docs().join(" "),
extrinsics,
functions,
})
})
.collect::<Result<Vec<Pallet>, Error>>()?;
Expand All @@ -140,31 +143,33 @@ pub fn find_pallet_by_name<'a>(
}
}

/// Finds a specific extrinsic by name and retrieves its details from metadata.
/// Finds a specific dispatchable function by name and retrieves its details from metadata.
///
/// # Arguments
/// * `pallets`: List of pallets available in the chain.
/// * `pallet_name`: The name of the pallet to find.
/// * `extrinsic_name`: Name of the extrinsic to locate.
pub fn find_extrinsic_by_name<'a>(
/// * `pallet_name`: The name of the pallet.
/// * `function_name`: Name of the dispatchable function to locate.
pub fn find_dispatchable_by_name<'a>(
pallets: &'a [Pallet],
pallet_name: &str,
extrinsic_name: &str,
) -> Result<&'a Extrinsic, Error> {
function_name: &str,
) -> Result<&'a Function, Error> {
let pallet = find_pallet_by_name(pallets, pallet_name)?;
if let Some(extrinsic) = pallet.extrinsics.iter().find(|&e| e.name == extrinsic_name) {
Ok(extrinsic)
if let Some(function) = pallet.functions.iter().find(|&e| e.name == function_name) {
Ok(function)
} else {
Err(Error::ExtrinsicNotSupported)
Err(Error::FunctionNotSupported)
}
}

/// Parses and processes raw string parameters for an extrinsic, mapping them to `Value` types.
/// Parses and processes raw string parameter values for a dispatchable function, mapping them to
/// `Value` types.
///
/// # Arguments
/// * `params`: The metadata definition for each parameter of the extrinsic.
/// * `raw_params`: A vector of raw string arguments for the extrinsic.
pub fn parse_extrinsic_arguments(
/// * `params`: The metadata definition for each parameter of the corresponding dispatchable
/// function.
/// * `raw_params`: A vector of raw string arguments for the dispatchable function.
pub fn parse_dispatchable_arguments(
params: &[Param],
raw_params: Vec<String>,
) -> Result<Vec<Value>, Error> {
Expand Down Expand Up @@ -205,22 +210,22 @@ mod tests {
assert_eq!(first_pallet.name, "System");
assert_eq!(first_pallet.index, 0);
assert_eq!(first_pallet.docs, "");
assert_eq!(first_pallet.extrinsics.len(), 11);
let first_extrinsic = first_pallet.extrinsics.first().unwrap();
assert_eq!(first_extrinsic.name, "remark");
assert_eq!(first_extrinsic.index, 0);
assert_eq!(first_pallet.functions.len(), 11);
let first_function = first_pallet.functions.first().unwrap();
assert_eq!(first_function.name, "remark");
assert_eq!(first_function.index, 0);
assert_eq!(
first_extrinsic.docs,
first_function.docs,
"Make some on-chain remark. Can be executed by every `origin`."
);
assert!(first_extrinsic.is_supported);
assert_eq!(first_extrinsic.params.first().unwrap().name, "remark");
assert_eq!(first_extrinsic.params.first().unwrap().type_name, "[u8]");
assert_eq!(first_extrinsic.params.first().unwrap().sub_params.len(), 0);
assert!(!first_extrinsic.params.first().unwrap().is_optional);
assert!(!first_extrinsic.params.first().unwrap().is_tuple);
assert!(!first_extrinsic.params.first().unwrap().is_variant);
assert!(first_extrinsic.params.first().unwrap().is_sequence);
assert!(first_function.is_supported);
assert_eq!(first_function.params.first().unwrap().name, "remark");
assert_eq!(first_function.params.first().unwrap().type_name, "[u8]");
assert_eq!(first_function.params.first().unwrap().sub_params.len(), 0);
assert!(!first_function.params.first().unwrap().is_optional);
assert!(!first_function.params.first().unwrap().is_tuple);
assert!(!first_function.params.first().unwrap().is_variant);
assert!(first_function.params.first().unwrap().is_sequence);
Ok(())
}

Expand All @@ -233,31 +238,31 @@ mod tests {
Err(Error::PalletNotFound(pallet)) if pallet == "WrongName".to_string()));
let pallet = find_pallet_by_name(&pallets, "Balances")?;
assert_eq!(pallet.name, "Balances");
assert_eq!(pallet.extrinsics.len(), 9);
assert_eq!(pallet.functions.len(), 9);
Ok(())
}

#[tokio::test]
async fn find_extrinsic_by_name_works() -> Result<()> {
async fn find_dispatchable_by_name_works() -> Result<()> {
let client = set_up_client(POP_NETWORK_TESTNET_URL).await?;
let pallets = parse_chain_metadata(&client)?;
assert!(matches!(
find_extrinsic_by_name(&pallets, "WrongName", "wrong_extrinsic"),
find_dispatchable_by_name(&pallets, "WrongName", "wrong_name"),
Err(Error::PalletNotFound(pallet)) if pallet == "WrongName".to_string()));
assert!(matches!(
find_extrinsic_by_name(&pallets, "Balances", "wrong_extrinsic"),
Err(Error::ExtrinsicNotSupported)
find_dispatchable_by_name(&pallets, "Balances", "wrong_name"),
Err(Error::FunctionNotSupported)
));
let extrinsic = find_extrinsic_by_name(&pallets, "Balances", "force_transfer")?;
assert_eq!(extrinsic.name, "force_transfer");
assert_eq!(extrinsic.docs, "Exactly as `transfer_allow_death`, except the origin must be root and the source account may be specified.");
assert_eq!(extrinsic.is_supported, true);
assert_eq!(extrinsic.params.len(), 3);
let function = find_dispatchable_by_name(&pallets, "Balances", "force_transfer")?;
assert_eq!(function.name, "force_transfer");
assert_eq!(function.docs, "Exactly as `transfer_allow_death`, except the origin must be root and the source account may be specified.");
assert_eq!(function.is_supported, true);
assert_eq!(function.params.len(), 3);
Ok(())
}

#[test]
fn parse_extrinsic_arguments_works() -> Result<()> {
fn parse_dispatchable_arguments_works() -> Result<()> {
// Values for testing from: https://docs.rs/scale-value/0.18.0/scale_value/stringify/fn.from_str.html
// and https://docs.rs/scale-value/0.18.0/scale_value/stringify/fn.from_str_custom.html
let args = [
Expand All @@ -283,7 +288,7 @@ mod tests {
.into_iter()
.map(|b| Value::u128(b as u128))
.collect();
// Define mock extrinsic parameters for testing.
// Define mock dispatchable function parameters for testing.
let params = vec![
Param { type_name: "u128".to_string(), ..Default::default() },
Param { type_name: "i128".to_string(), ..Default::default() },
Expand All @@ -297,7 +302,7 @@ mod tests {
Param { type_name: "composite".to_string(), ..Default::default() },
];
assert_eq!(
parse_extrinsic_arguments(&params, args)?,
parse_dispatchable_arguments(&params, args)?,
[
Value::u128(1),
Value::i128(-1),
Expand Down
Loading

0 comments on commit b19ece8

Please sign in to comment.