Skip to content

Commit

Permalink
feat: parse files when the argument values are very big
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexD10S committed Dec 6, 2024
1 parent 28743bd commit 938d865
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 20 deletions.
78 changes: 62 additions & 16 deletions crates/pop-cli/src/commands/call/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use url::Url;

const DEFAULT_URL: &str = "ws://localhost:9944/";
const DEFAULT_URI: &str = "//Alice";
const ENCODED_CALL_DATA_MAX_LEN: usize = 1000; // Maximum length of encoded call data to display.

/// Command to execute extrinsics with configurable pallets, arguments, and signing options.
#[derive(Args, Clone)]
Expand Down Expand Up @@ -74,8 +75,9 @@ impl CallParachainCommand {
break;
}

if !prompt_to_repeat_call ||
!cli.confirm("Do you want to perform another call?")
if !prompt_to_repeat_call
|| !cli
.confirm("Do you want to perform another call?")
.initial_value(false)
.interact()?
{
Expand Down Expand Up @@ -138,8 +140,9 @@ impl CallParachainCommand {

// Resolve extrinsic.
let extrinsic = match self.extrinsic {
Some(ref extrinsic_name) =>
find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?,
Some(ref extrinsic_name) => {
find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?
},
None => {
let mut prompt_extrinsic = cli.select("Select the extrinsic to call:");
for extrinsic in &pallet.extrinsics {
Expand Down Expand Up @@ -176,8 +179,9 @@ impl CallParachainCommand {
// Resolve who is signing the extrinsic.
let suri = match self.suri.as_ref() {
Some(suri) => suri.clone(),
None =>
cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?,
None => {
cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?
},
};

return Ok(CallParachain {
Expand All @@ -199,11 +203,11 @@ impl CallParachainCommand {

// Function to check if all required fields are specified.
fn requires_user_input(&self) -> bool {
self.pallet.is_none() ||
self.extrinsic.is_none() ||
self.args.is_empty() ||
self.url.is_none() ||
self.suri.is_none()
self.pallet.is_none()
|| self.extrinsic.is_none()
|| self.args.is_empty()
|| self.url.is_none()
|| self.suri.is_none()
}
}

Expand Down Expand Up @@ -256,7 +260,11 @@ impl CallParachain {
return Err(anyhow!("Error: {}", e));
},
};
cli.info(format!("Encoded call data: {}", encode_call_data(client, &tx)?))?;
let encoded_data = encode_call_data(client, &tx)?;
// If the encoded call data is too long, don't display it all.
if encoded_data.len() < ENCODED_CALL_DATA_MAX_LEN {
cli.info(format!("Encoded call data: {}", encode_call_data(client, &tx)?))?;
}
Ok(tx)
}

Expand All @@ -267,8 +275,9 @@ impl CallParachain {
tx: DynamicPayload,
cli: &mut impl Cli,
) -> Result<()> {
if !self.skip_confirm &&
!cli.confirm("Do you want to submit the extrinsic?")
if !self.skip_confirm
&& !cli
.confirm("Do you want to submit the extrinsic?")
.initial_value(true)
.interact()?
{
Expand All @@ -293,7 +302,18 @@ impl CallParachain {
full_message.push_str(&format!(" --pallet {}", self.pallet));
full_message.push_str(&format!(" --extrinsic {}", self.extrinsic));
if !self.args.is_empty() {
let args: Vec<_> = self.args.iter().map(|a| format!("\"{a}\"")).collect();
let args: Vec<_> = self
.args
.iter()
.map(|a| {
// If the argument is too long, don't show it all, truncate it.
if a.len() > ENCODED_CALL_DATA_MAX_LEN {
format!("\"{}...{}\"", &a[..20], &a[a.len() - 20..])
} else {
format!("\"{a}\"")
}
})
.collect();
full_message.push_str(&format!(" --args {}", args.join(" ")));
}
full_message.push_str(&format!(" --url {} --suri {}", chain.url, self.suri));
Expand Down Expand Up @@ -349,7 +369,9 @@ fn prompt_for_param(cli: &mut impl Cli, param: &Param) -> Result<String> {

// Resolves the value of a parameter based on its type.
fn get_param_value(cli: &mut impl Cli, param: &Param) -> Result<String> {
if param.sub_params.is_empty() {
if param.is_sequence {
prompt_for_sequence_param(cli, param)
} else if param.sub_params.is_empty() {
prompt_for_primitive_param(cli, param)
} else if param.is_variant {
prompt_for_variant_param(cli, param)
Expand All @@ -360,6 +382,30 @@ fn get_param_value(cli: &mut impl Cli, param: &Param) -> Result<String> {
}
}

// Prompt for the value when it is a sequence.
fn prompt_for_sequence_param(cli: &mut impl Cli, param: &Param) -> Result<String> {
if cli
.confirm(format!(
"The value for `{}` might be too large to enter. Provide a file instead?",
param.name
))
.initial_value(true)
.interact()?
{
let file_path = cli
.input(format!("Enter the file path for the parameter `{}`:", param.name))
.placeholder("e.g., /path/to/your/file.json")
.interact()?;

let content = std::fs::read_to_string(&file_path)
.map_err(|err| anyhow!("Failed to read file {}", err.to_string()))?;

return Ok(content);
} else {
prompt_for_primitive_param(cli, param)
}
}

// Prompt for the value when it is a primitive.
fn prompt_for_primitive_param(cli: &mut impl Cli, param: &Param) -> Result<String> {
Ok(cli
Expand Down
1 change: 1 addition & 0 deletions crates/pop-parachains/src/call/metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ mod tests {
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);
Ok(())
}

Expand Down
22 changes: 18 additions & 4 deletions crates/pop-parachains/src/call/metadata/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub struct Param {
pub is_tuple: bool,
/// Indicates if the parameter is a Variant.
pub is_variant: bool,
/// Indicates if the parameter is a Sequence.
pub is_sequence: bool,
}

/// Transforms a metadata field into its `Param` representation.
Expand Down Expand Up @@ -69,6 +71,7 @@ fn type_to_param(name: String, registry: &PortableRegistry, type_id: u32) -> Res
is_optional: true,
is_tuple: false,
is_variant: false,
is_sequence: false,
})
} else {
Err(Error::MetadataParsingError(name))
Expand All @@ -77,16 +80,14 @@ fn type_to_param(name: String, registry: &PortableRegistry, type_id: u32) -> Res
// Determine the formatted type name.
let type_name = format_type(type_info, registry);
match &type_info.type_def {
TypeDef::Primitive(_) |
TypeDef::Array(_) |
TypeDef::Sequence(_) |
TypeDef::Compact(_) => Ok(Param {
TypeDef::Primitive(_) | TypeDef::Array(_) | TypeDef::Compact(_) => Ok(Param {
name,
type_name,
sub_params: Vec::new(),
is_optional: false,
is_tuple: false,
is_variant: false,
is_sequence: false,
}),
TypeDef::Composite(composite) => {
let sub_params = composite
Expand All @@ -109,6 +110,7 @@ fn type_to_param(name: String, registry: &PortableRegistry, type_id: u32) -> Res
is_optional: false,
is_tuple: false,
is_variant: false,
is_sequence: false,
})
},
TypeDef::Variant(variant) => {
Expand All @@ -135,6 +137,7 @@ fn type_to_param(name: String, registry: &PortableRegistry, type_id: u32) -> Res
is_optional: false,
is_tuple: false,
is_variant: true,
is_sequence: false,
})
})
.collect::<Result<Vec<Param>, Error>>()?;
Expand All @@ -146,8 +149,18 @@ fn type_to_param(name: String, registry: &PortableRegistry, type_id: u32) -> Res
is_optional: false,
is_tuple: false,
is_variant: true,
is_sequence: false,
})
},
TypeDef::Sequence(_) => Ok(Param {
name,
type_name,
sub_params: Vec::new(),
is_optional: false,
is_tuple: false,
is_variant: false,
is_sequence: true,
}),
TypeDef::Tuple(tuple) => {
let sub_params = tuple
.fields
Expand All @@ -169,6 +182,7 @@ fn type_to_param(name: String, registry: &PortableRegistry, type_id: u32) -> Res
is_optional: false,
is_tuple: true,
is_variant: false,
is_sequence: false,
})
},
_ => Err(Error::MetadataParsingError(name)),
Expand Down

0 comments on commit 938d865

Please sign in to comment.