Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dry run gas limit estimation #484

Merged
merged 35 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
55fb1e6
Dry run instantiate gas estimation
ascjones Mar 31, 2022
55512ad
Merge branch 'master' into aj/dry-run-gas-limit
ascjones Apr 6, 2022
ca5b0ed
Merge branch 'master' into aj/dry-run-gas-limit
ascjones Apr 12, 2022
4348cc5
Fmt
ascjones Apr 12, 2022
c901432
Merge branch 'master' into aj/dry-run-gas-limit
ascjones Jun 1, 2022
c654df8
Merge branch 'master' into aj/dry-run-gas-limit
ascjones Jul 1, 2022
2f88768
Prompt instantiate dry run estimate
ascjones Jul 1, 2022
64d4014
Fix gas estimation and fmt
ascjones Jul 1, 2022
0763eb5
Dry run gas estimation for instantiate with code
ascjones Jul 5, 2022
45695e1
Dry run gas estimation for call
ascjones Jul 5, 2022
1e163b3
Fmt
ascjones Jul 5, 2022
add77cd
Clippy
ascjones Jul 5, 2022
a04a829
Fmt
ascjones Jul 5, 2022
ad1b74e
Remove deprecated rustfmt configuration options
ascjones Jul 5, 2022
ce2e2f1
Merge branch 'master' into aj/dry-run-gas-limit
ascjones Jul 5, 2022
c00001e
Merge branch 'master' into aj/dry-run-gas-limit
ascjones Aug 1, 2022
3562628
Merge branch 'master' into aj/dry-run-gas-limit
ascjones Aug 2, 2022
9d974e6
If else instead of early return
ascjones Aug 3, 2022
cebe60c
WIP tx confirm
ascjones Aug 3, 2022
2fdff82
Prompt instantiate with code hash
ascjones Aug 3, 2022
b79348b
Dry run status
ascjones Aug 3, 2022
01b1b8b
Dry run call pre dispatch
ascjones Aug 3, 2022
f0adec6
Align and prettify dry run gas estimate
ascjones Aug 3, 2022
3aeae66
Factor out success print fns
ascjones Aug 3, 2022
3c16c23
Remove unused imports
ascjones Aug 3, 2022
7d07c52
Clippy
ascjones Aug 4, 2022
3b97603
Fmt
ascjones Aug 4, 2022
b957482
Update comment
ascjones Aug 4, 2022
cb2a754
Use --gas argument override if specified
ascjones Aug 4, 2022
ac875ff
Merge branch 'master' into aj/dry-run-gas-limit
ascjones Aug 9, 2022
587a3df
Fix dry run result formatting
ascjones Aug 9, 2022
e5a0069
Print pre-submission dry run details
ascjones Aug 9, 2022
574f93f
Fmt
ascjones Aug 9, 2022
193c66e
Make confirm prompt case sensitive and default Y
ascjones Aug 11, 2022
533da22
Fmt
ascjones Aug 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 100 additions & 41 deletions src/cmd/extrinsics/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,24 @@ use super::{
dry_run_error_details,
load_metadata,
parse_balance,
prompt_confirm_tx,
wait_for_success_and_handle_error,
Balance,
ContractMessageTranscoder,
ExtrinsicOpts,
PairSigner,
RuntimeApi,
RuntimeDispatchError,
EXEC_RESULT_MAX_KEY_COL_WIDTH,
MAX_KEY_COL_WIDTH,
};
use crate::{
name_value_println,
DEFAULT_KEY_COL_WIDTH,
};
use anyhow::{
anyhow,
Result,
};
use crate::name_value_println;
use anyhow::Result;
use jsonrpsee::{
core::client::ClientT,
rpc_params,
Expand Down Expand Up @@ -71,8 +78,9 @@ pub struct CallCommand {
#[clap(flatten)]
extrinsic_opts: ExtrinsicOpts,
/// Maximum amount of gas to be used for this command.
#[clap(name = "gas", long, default_value = "50000000000")]
gas_limit: u64,
/// If not specified will perform a dry-run to estimate the gas consumed for the instantiation.
#[clap(name = "gas", long)]
gas_limit: Option<u64>,
/// The value to be transferred as part of the call.
#[clap(name = "value", long, parse(try_from_str = parse_balance), default_value = "0")]
value: Balance,
Expand All @@ -97,22 +105,49 @@ impl CallCommand {
.to_runtime_api::<RuntimeApi>();

if self.extrinsic_opts.dry_run {
self.call_rpc(&api, call_data, &signer, &transcoder).await
let result = self.call_dry_run(call_data, &signer).await?;

match result.result {
Ok(ref ret_val) => {
let value = transcoder
.decode_return(&self.message, &mut &ret_val.data.0[..])?;
name_value_println!(
"Result",
String::from("Success!"),
DEFAULT_KEY_COL_WIDTH
);
name_value_println!(
"Reverted",
format!("{:?}", ret_val.did_revert()),
DEFAULT_KEY_COL_WIDTH
);
name_value_println!(
"Data",
format!("{}", value),
DEFAULT_KEY_COL_WIDTH
);
display_contract_exec_result::<_, DEFAULT_KEY_COL_WIDTH>(&result)
}
Err(ref err) => {
let err = dry_run_error_details(&api, err).await?;
name_value_println!("Result", err, MAX_KEY_COL_WIDTH);
display_contract_exec_result::<_, MAX_KEY_COL_WIDTH>(&result)
}
}
} else {
self.call(&api, call_data, &signer, &transcoder).await
}
})
}

async fn call_rpc(
async fn call_dry_run(
&self,
api: &RuntimeApi,
data: Vec<u8>,
signer: &PairSigner,
transcoder: &ContractMessageTranscoder<'_>,
) -> Result<()> {
) -> Result<ContractExecResult> {
let url = self.extrinsic_opts.url_to_string();
let cli = WsClientBuilder::default().build(&url).await?;
let gas_limit = self.gas_limit.as_ref().unwrap_or(&5_000_000_000_000);
let storage_deposit_limit = self
.extrinsic_opts
.storage_deposit_limit
Expand All @@ -122,40 +157,13 @@ impl CallCommand {
origin: signer.account_id().clone(),
dest: self.contract.clone(),
value: NumberOrHex::Hex(self.value.into()),
gas_limit: NumberOrHex::Number(self.gas_limit),
gas_limit: NumberOrHex::Number(*gas_limit),
storage_deposit_limit,
input_data: Bytes(data),
};
let params = rpc_params![call_request];
let result: ContractExecResult = cli.request("contracts_call", params).await?;

match result.result {
Ok(ref ret_val) => {
let value =
transcoder.decode_return(&self.message, &mut &ret_val.data.0[..])?;
name_value_println!(
"Result",
String::from("Success!"),
EXEC_RESULT_MAX_KEY_COL_WIDTH
);
name_value_println!(
"Reverted",
format!("{:?}", ret_val.did_revert()),
EXEC_RESULT_MAX_KEY_COL_WIDTH
);
name_value_println!(
"Data",
format!("{}", value),
EXEC_RESULT_MAX_KEY_COL_WIDTH
);
}
Err(ref err) => {
let err = dry_run_error_details(api, err).await?;
name_value_println!("Result", err, EXEC_RESULT_MAX_KEY_COL_WIDTH);
}
}
display_contract_exec_result(&result)?;
Ok(())
let result = cli.request("contracts_call", params).await?;
Ok(result)
}

async fn call(
Expand All @@ -166,13 +174,30 @@ impl CallCommand {
transcoder: &ContractMessageTranscoder<'_>,
) -> Result<()> {
log::debug!("calling contract {:?}", self.contract);

let gas_limit = self
.pre_submit_dry_run_gas_estimate(api, data.clone(), signer)
.await?;

if !self.extrinsic_opts.skip_confirm {
prompt_confirm_tx(|| {
name_value_println!("Message", self.message, DEFAULT_KEY_COL_WIDTH);
name_value_println!("Args", self.args.join(" "), DEFAULT_KEY_COL_WIDTH);
name_value_println!(
"Gas limit",
gas_limit.to_string(),
DEFAULT_KEY_COL_WIDTH
);
})?;
}

let tx_progress = api
.tx()
.contracts()
.call(
self.contract.clone().into(),
self.value,
self.gas_limit,
gas_limit,
self.extrinsic_opts.storage_deposit_limit,
data,
)?
Expand All @@ -188,6 +213,40 @@ impl CallCommand {
&self.extrinsic_opts.verbosity()?,
)
}

/// Dry run the call before tx submission. Returns the gas required estimate.
async fn pre_submit_dry_run_gas_estimate(
&self,
api: &RuntimeApi,
data: Vec<u8>,
signer: &PairSigner,
) -> Result<u64> {
if self.extrinsic_opts.skip_dry_run {
return match self.gas_limit {
Some(gas) => Ok(gas),
None => {
Err(anyhow!(
"Gas limit `--gas` argument required if `--skip-dry-run` specified"
))
}
}
}
super::print_dry_running_status(&self.message);
let call_result = self.call_dry_run(data, signer).await?;
match call_result.result {
Ok(_) => {
super::print_gas_required_success(call_result.gas_required);
let gas_limit = self.gas_limit.unwrap_or(call_result.gas_required);
Ok(gas_limit)
}
Err(ref err) => {
let err = dry_run_error_details(api, err).await?;
name_value_println!("Result", err, MAX_KEY_COL_WIDTH);
display_contract_exec_result::<_, MAX_KEY_COL_WIDTH>(&call_result)?;
Err(anyhow!("Pre-submission dry-run failed. Use --skip-dry-run to skip this step."))
}
}
}
}

/// A struct that encodes RPC parameters required for a call to a smart contract.
Expand Down
2 changes: 2 additions & 0 deletions src/cmd/extrinsics/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub fn display_events(
return Ok(())
}

println!();

if matches!(verbosity, Verbosity::Verbose) {
println!("VERBOSE")
}
Expand Down
Loading