Skip to content

Commit

Permalink
fix: sequence arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexD10S committed Dec 8, 2024
1 parent be1d1b6 commit 3f79680
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 24 deletions.
2 changes: 1 addition & 1 deletion crates/pop-cli/src/commands/call/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl CallParachain {
) -> Result<DynamicPayload> {
let tx = match construct_extrinsic(
self.pallet.name.as_str(),
self.extrinsic.name.as_str(),
&self.extrinsic,
self.args.clone(),
)
.await
Expand Down
74 changes: 61 additions & 13 deletions crates/pop-parachains/src/call/metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,31 @@ pub async fn find_extrinsic_by_name(
/// Parses and processes raw string parameters for an extrinsic, mapping them to `Value` types.
///
/// # Arguments
/// * `extrinsic`: The definition of the extrinsic, containing parameter metadata.
/// * `raw_params`: A vector of raw string arguments for the extrinsic.
pub async fn parse_extrinsic_arguments(raw_params: Vec<String>) -> Result<Vec<Value>, Error> {
let mut parsed_params: Vec<Value> = Vec::new();
for raw_param in raw_params {
let parsed_value: Value = scale_value::stringify::from_str_custom()
.add_custom_parser(custom_parsers::parse_hex)
.add_custom_parser(custom_parsers::parse_ss58)
.parse(&raw_param)
.0
.map_err(|_| Error::ParamProcessingError)?;
parsed_params.push(parsed_value);
}
Ok(parsed_params)
pub async fn parse_extrinsic_arguments(
extrinsic: &Extrinsic,
raw_params: Vec<String>,
) -> Result<Vec<Value>, Error> {
extrinsic
.params
.iter()
.zip(raw_params)
.map(|(param, raw_param)| {
// Convert sequence parameters to hex if is_sequence
let processed_param = if param.is_sequence && !raw_param.starts_with("0x") {
format!("0x{}", hex::encode(raw_param))
} else {
raw_param
};
scale_value::stringify::from_str_custom()
.add_custom_parser(custom_parsers::parse_hex)
.add_custom_parser(custom_parsers::parse_ss58)
.parse(&processed_param)
.0
.map_err(|_| Error::ParamProcessingError)
})
.collect()
}

#[cfg(test)]
Expand Down Expand Up @@ -229,6 +241,24 @@ mod tests {

#[tokio::test]
async fn parse_extrinsic_arguments_works() -> Result<()> {
/// Helper function to create a `Param` with default values.
fn create_param(
name: &str,
type_name: &str,
is_sequence: bool,
is_variant: bool,
is_tuple: bool,
) -> Param {
Param {
name: name.to_string(),
type_name: type_name.to_string(),
sub_params: vec![],
is_optional: false,
is_sequence,
is_variant,
is_tuple,
}
}
// 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 @@ -254,8 +284,26 @@ mod tests {
.into_iter()
.map(|b| Value::u128(b as u128))
.collect();
// Define mock extrinsic with parameters for testing.
let extrinsic = Extrinsic {
name: "test_extrinsic".to_string(),
docs: "Test extrinsic documentation".to_string(),
params: vec![
create_param("param_1", "u128", false, false, false),
create_param("param_2", "i128", false, false, false),
create_param("param_3", "bool", false, false, false),
create_param("param_4", "char", false, false, false),
create_param("param_5", "string", false, false, false),
create_param("param_6", "composite", false, false, false),
create_param("param_7", "variant", false, true, false),
create_param("param_8", "bit_sequence", false, false, false),
create_param("param_9", "tuple", false, false, true),
create_param("param_10", "composite", false, false, false),
],
is_supported: true,
};
assert_eq!(
parse_extrinsic_arguments(args).await?,
parse_extrinsic_arguments(&extrinsic, args).await?,
[
Value::u128(1),
Value::i128(-1),
Expand Down
36 changes: 26 additions & 10 deletions crates/pop-parachains/src/call/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0

use crate::errors::Error;
use crate::{errors::Error, Extrinsic};
use pop_common::create_signer;
use subxt::{
dynamic::Value,
Expand Down Expand Up @@ -28,11 +28,11 @@ pub async fn set_up_client(url: &str) -> Result<OnlineClient<SubstrateConfig>, E
/// * `args` - A vector of string arguments to be passed to the extrinsic.
pub async fn construct_extrinsic(
pallet_name: &str,
extrinsic_name: &str,
extrinsic: &Extrinsic,
args: Vec<String>,
) -> Result<DynamicPayload, Error> {
let parsed_args: Vec<Value> = metadata::parse_extrinsic_arguments(args).await?;
Ok(subxt::dynamic::tx(pallet_name, extrinsic_name, parsed_args))
let parsed_args: Vec<Value> = metadata::parse_extrinsic_arguments(&extrinsic, args).await?;

Check warning on line 34 in crates/pop-parachains/src/call/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> crates/pop-parachains/src/call/mod.rs:34:68 | 34 | let parsed_args: Vec<Value> = metadata::parse_extrinsic_arguments(&extrinsic, args).await?; | ^^^^^^^^^^ help: change this to: `extrinsic` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `#[warn(clippy::needless_borrow)]` on by default
Ok(subxt::dynamic::tx(pallet_name, extrinsic.name.clone(), parsed_args))
}

/// Signs and submits a given extrinsic.
Expand Down Expand Up @@ -77,7 +77,7 @@ pub fn encode_call_data(
mod tests {
use super::*;

use crate::set_up_client;
use crate::{find_extrinsic_by_name, parse_chain_metadata, set_up_client};
use anyhow::Result;

#[tokio::test]
Expand All @@ -92,11 +92,16 @@ mod tests {

#[tokio::test]
async fn construct_extrinsic_works() -> Result<()> {
let client = set_up_client("wss://rpc1.paseo.popnetwork.xyz").await?;
let pallets = parse_chain_metadata(&client).await?;
let transfer_allow_death =
find_extrinsic_by_name(&pallets, "Balances", "transfer_allow_death").await?;

// Wrong parameters
assert!(matches!(
construct_extrinsic(
"Balances",
"transfer_allow_death",
&transfer_allow_death,
vec!["Bob".to_string(), "100".to_string()],
)
.await,
Expand All @@ -105,7 +110,7 @@ mod tests {
// Valid parameters
let extrinsic = construct_extrinsic(
"Balances",
"transfer_allow_death",
&transfer_allow_death,
vec![
"Id(5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty)".to_string(),
"100".to_string(),
Expand All @@ -120,16 +125,27 @@ mod tests {
#[tokio::test]
async fn encode_call_data_works() -> Result<()> {
let client = set_up_client("wss://rpc1.paseo.popnetwork.xyz").await?;
let extrinsic = construct_extrinsic("System", "remark", vec!["0x11".to_string()]).await?;
let pallets = parse_chain_metadata(&client).await?;
let remark = find_extrinsic_by_name(&pallets, "Balances", "remark").await?;
let extrinsic = construct_extrinsic("System", &remark, vec!["0x11".to_string()]).await?;
assert_eq!(encode_call_data(&client, &extrinsic)?, "0x00000411");
let extrinsic = construct_extrinsic("System", &remark, vec!["123".to_string()]).await?;
assert_eq!(encode_call_data(&client, &extrinsic)?, "0x00000c313233");
let extrinsic = construct_extrinsic("System", &remark, vec!["test".to_string()]).await?;
assert_eq!(encode_call_data(&client, &extrinsic)?, "0x00001074657374");
Ok(())
}

#[tokio::test]
async fn sign_and_submit_wrong_extrinsic_fails() -> Result<()> {
let client = set_up_client("wss://rpc1.paseo.popnetwork.xyz").await?;
let tx =
construct_extrinsic("WrongPallet", "wrongExtrinsic", vec!["0x11".to_string()]).await?;
let extrinsic = Extrinsic {
name: "wrong_extrinsic".to_string(),
docs: "documentation".to_string(),
params: vec![],
is_supported: true,
};
let tx = construct_extrinsic("WrongPallet", &extrinsic, vec!["0x11".to_string()]).await?;
assert!(matches!(
sign_and_submit_extrinsic(client, tx, "//Alice").await,
Err(Error::ExtrinsicSubmissionError(message)) if message.contains("PalletNameNotFound(\"WrongPallet\"))")
Expand Down

0 comments on commit 3f79680

Please sign in to comment.