Skip to content

Commit

Permalink
Moved all CLI commands to automatically infer gas budget.
Browse files Browse the repository at this point in the history
  • Loading branch information
stefan-mysten committed Mar 2, 2024
1 parent 417671d commit 1cfb13f
Show file tree
Hide file tree
Showing 6 changed files with 350 additions and 85 deletions.
219 changes: 206 additions & 13 deletions crates/sui/src/client_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ macro_rules! serialize_or_execute {
}};
}

/// Only to be used within CLI
pub const MAX_GAS_BUDGET: u64 = 50_000_000_000;

#[derive(Parser)]
#[clap(rename_all = "kebab-case")]
pub enum SuiClientCommands {
Expand Down Expand Up @@ -181,7 +184,7 @@ pub enum SuiClientCommands {
gas: Option<ObjectID>,
/// Gas budget for this call
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data
/// (TransactionData) using base64 encoding, and print out the string <TX_BYTES>. The string can
Expand Down Expand Up @@ -271,7 +274,7 @@ pub enum SuiClientCommands {
gas: Option<ObjectID>,
/// Gas budget for this call
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data
/// (TransactionData) using base64 encoding, and print out the string <TX_BYTES>. The string can
Expand Down Expand Up @@ -354,7 +357,7 @@ pub enum SuiClientCommands {

/// Gas budget for this transaction
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data
/// (TransactionData) using base64 encoding, and print out the string <TX_BYTES>. The string can
Expand Down Expand Up @@ -383,7 +386,7 @@ pub enum SuiClientCommands {

/// Gas budget for this transaction
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data
/// (TransactionData) using base64 encoding, and print out the string <TX_BYTES>. The string can
Expand Down Expand Up @@ -416,9 +419,9 @@ pub enum SuiClientCommands {
#[clap(long, num_args(1..))]
amounts: Vec<u64>,

/// Gas budget for this transaction
/// Gas budget for this transaction.
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data
/// (TransactionData) using base64 encoding, and print out the string <TX_BYTES>. The string can
Expand Down Expand Up @@ -456,7 +459,7 @@ pub enum SuiClientCommands {

/// Gas budget for running module initializers
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Publish the package without checking whether compiling dependencies from source results
/// in bytecode matching the dependencies found on-chain.
Expand Down Expand Up @@ -499,7 +502,7 @@ pub enum SuiClientCommands {
gas: Option<ObjectID>,
/// Gas budget for this call
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data
/// (TransactionData) using base64 encoding, and print out the string <TX_BYTES>. The string can
Expand Down Expand Up @@ -554,7 +557,7 @@ pub enum SuiClientCommands {

/// Gas budget for this transfer
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data
/// (TransactionData) using base64 encoding, and print out the string <TX_BYTES>. The string can
Expand Down Expand Up @@ -585,7 +588,7 @@ pub enum SuiClientCommands {

/// Gas budget for this transfer
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// The amount to transfer, if not specified, the entire coin object will be transferred.
#[clap(long)]
Expand Down Expand Up @@ -627,7 +630,7 @@ pub enum SuiClientCommands {

/// Gas budget for running module initializers
#[clap(long)]
gas_budget: u64,
gas_budget: Option<u64>,

/// Publish the package without checking whether compiling dependencies from source results
/// in bytecode matching the dependencies found on-chain.
Expand Down Expand Up @@ -971,7 +974,25 @@ impl SuiClientCommands {
skip_dependency_verification,
)
.await?;

let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let tx = client
.transaction_builder()
.upgrade(
sender,
package_id,
compiled_modules.clone(),
dependencies.published.clone().into_values().collect(),
upgrade_capability,
upgrade_policy,
package_digest.to_vec(),
gas,
max_gas_budget(context).await?,
)
.await?;
dry_run(context, tx).await?
};
let data = client
.transaction_builder()
.upgrade(
Expand Down Expand Up @@ -1031,7 +1052,21 @@ impl SuiClientCommands {
skip_dependency_verification,
)
.await?;

let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let tx = client
.transaction_builder()
.publish(
sender,
compiled_modules.clone(),
dependencies.published.clone().into_values().collect(),
gas,
max_gas_budget(context).await?,
)
.await?;
dry_run(context, tx).await?
};
let data = client
.transaction_builder()
.publish(
Expand Down Expand Up @@ -1132,6 +1167,22 @@ impl SuiClientCommands {
serialize_unsigned_transaction,
serialize_signed_transaction,
} => {
let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let tx = construct_move_call_transaction(
package,
&module,
&function,
type_args.clone(),
gas,
max_gas_budget(context).await?,
args.clone(),
context,
)
.await?;
dry_run(context, tx).await?
};
let tx_data = construct_move_call_transaction(
package, &module, &function, type_args, gas, gas_budget, args, context,
)
Expand All @@ -1156,6 +1207,15 @@ impl SuiClientCommands {
let from = context.get_object_owner(&object_id).await?;
let to = get_identity_address(Some(to), context)?;
let client = context.get_client().await?;
let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let tx = client
.transaction_builder()
.transfer_object(from, object_id, gas, max_gas_budget(context).await?, to)
.await?;
dry_run(context, tx).await?
};
let data = client
.transaction_builder()
.transfer_object(from, object_id, gas, gas_budget, to)
Expand All @@ -1180,6 +1240,15 @@ impl SuiClientCommands {
let from = context.get_object_owner(&object_id).await?;
let to = get_identity_address(Some(to), context)?;
let client = context.get_client().await?;
let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let tx = client
.transaction_builder()
.transfer_sui(from, object_id, max_gas_budget(context).await?, to, amount)
.await?;
dry_run(context, tx).await?
};
let data = client
.transaction_builder()
.transfer_sui(from, object_id, gas_budget, to, amount)
Expand Down Expand Up @@ -1225,6 +1294,22 @@ impl SuiClientCommands {
.map_err(|e| anyhow!("{e}"))?;
let from = context.get_object_owner(&input_coins[0]).await?;
let client = context.get_client().await?;
let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let data = client
.transaction_builder()
.pay(
from,
input_coins.clone(),
recipients.clone(),
amounts.clone(),
gas,
max_gas_budget(context).await?,
)
.await?;
dry_run(context, data).await?
};
let data = client
.transaction_builder()
.pay(from, input_coins, recipients, amounts, gas, gas_budget)
Expand Down Expand Up @@ -1269,6 +1354,21 @@ impl SuiClientCommands {
.map_err(|e| anyhow!("{e}"))?;
let signer = context.get_object_owner(&input_coins[0]).await?;
let client = context.get_client().await?;
let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let data = client
.transaction_builder()
.pay_sui(
signer,
input_coins.clone(),
recipients.clone(),
amounts.clone(),
max_gas_budget(context).await?,
)
.await?;
dry_run(context, data).await?
};
let data = client
.transaction_builder()
.pay_sui(signer, input_coins, recipients, amounts, gas_budget)
Expand Down Expand Up @@ -1296,6 +1396,20 @@ impl SuiClientCommands {
let recipient = get_identity_address(Some(recipient), context)?;
let signer = context.get_object_owner(&input_coins[0]).await?;
let client = context.get_client().await?;
let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let tx = client
.transaction_builder()
.pay_all_sui(
signer,
input_coins.clone(),
recipient,
max_gas_budget(context).await?,
)
.await?;
dry_run(context, tx).await?
};
let data = client
.transaction_builder()
.pay_all_sui(signer, input_coins, recipient, gas_budget)
Expand Down Expand Up @@ -1417,6 +1531,43 @@ impl SuiClientCommands {
} => {
let signer = context.get_object_owner(&coin_id).await?;
let client = context.get_client().await?;
let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let tx = match (amounts.clone(), count) {
(Some(amounts), None) => {
client
.transaction_builder()
.split_coin(
signer,
coin_id,
amounts,
gas,
max_gas_budget(context).await?,
)
.await?
}
(None, Some(count)) => {
if count == 0 {
return Err(anyhow!("Coin split count must be greater than 0"));
}
client
.transaction_builder()
.split_coin_equal(
signer,
coin_id,
count,
gas,
max_gas_budget(context).await?,
)
.await?
}
_ => {
return Err(anyhow!("Exactly one of `count` and `amounts` must be present for split-coin command."));
}
};
dry_run(context, tx).await?
};
let data = match (amounts, count) {
(Some(amounts), None) => {
client
Expand Down Expand Up @@ -1455,6 +1606,21 @@ impl SuiClientCommands {
} => {
let client = context.get_client().await?;
let signer = context.get_object_owner(&primary_coin).await?;
let gas_budget = if let Some(gas_budget) = gas_budget {
gas_budget
} else {
let tx = client
.transaction_builder()
.merge_coins(
signer,
primary_coin,
coin_to_merge,
gas,
max_gas_budget(context).await?,
)
.await?;
dry_run(context, tx).await?
};
let data = client
.transaction_builder()
.merge_coins(signer, primary_coin, coin_to_merge, gas, gas_budget)
Expand Down Expand Up @@ -2432,3 +2598,30 @@ fn pretty_print_balance(
.with(TableStyle::blank())
.to_string()]);
}

pub(crate) async fn dry_run(
context: &mut WalletContext,
tx: TransactionData,
) -> Result<u64, anyhow::Error> {
let client = context.get_client().await?;
let dry_run = client.read_api().dry_run_transaction_block(tx).await?;
Ok(dry_run.effects.gas_cost_summary().gas_used())
}

pub async fn max_gas_budget(context: &mut WalletContext) -> Result<u64, anyhow::Error> {
let cfg = context
.get_client()
.await?
.read_api()
.get_protocol_config(None)
.await?;
let x = match cfg.attributes.get("max_tx_gas") {
Some(x) => match x {
Some(sui_json_rpc_types::SuiProtocolConfigValue::U64(y)) => *y,
// TODO should we fail instead, if the protocol config does not have the max-budget, and ask the user to provide with a budget?
_ => MAX_GAS_BUDGET,
},
None => MAX_GAS_BUDGET,
};
Ok(x)
}
2 changes: 1 addition & 1 deletion crates/sui/src/client_ptb/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub struct ProgramMetadata {
pub summary_set: bool,
pub gas_object_id: Option<Spanned<ObjectID>>,
pub json_set: bool,
pub gas_budget: Spanned<u64>,
pub gas_budget: Option<Spanned<u64>>,
}

/// A parsed module access consisting of the address, module name, and function name.
Expand Down
7 changes: 3 additions & 4 deletions crates/sui/src/client_ptb/displays/ptb_preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ impl<'a> Display for PTBPreview<'a> {
}
// index of horizontal line to draw after commands
let line_index = builder.count_rows();
builder.push_record([
GAS_BUDGET,
self.program_metadata.gas_budget.value.to_string().as_str(),
]);
if let Some(gas_budget) = self.program_metadata.gas_budget {
builder.push_record([GAS_BUDGET, gas_budget.value.to_string().as_str()]);
}
if let Some(gas_coin_id) = self.program_metadata.gas_object_id {
builder.push_record([GAS_COIN, gas_coin_id.value.to_string().as_str()]);
}
Expand Down
Loading

0 comments on commit 1cfb13f

Please sign in to comment.