Skip to content

Commit

Permalink
feat: Add salt flag to forc deploy, maturity flag to deploy and `…
Browse files Browse the repository at this point in the history
…run` (FuelLabs#4116)

## Description

This allows for specifying a `--salt` for the top-level contract member
when running `forc deploy`. Right now, we only enable this for
*packages*, and not for workspaces with more than one package due to
some ambiguities that arise (see comment note in code). I'll open an
issue to track relaxing this constraint a little. Edit: opened
FuelLabs#4117.

I noticed we also had no way of specifying maturity, so have added a
`--maturity` flag for this as well.

These flags are shared with the `forc-tx` crate in order to try and
provide some consistency (in help output and flag representation) across
our CLI tooling.

Ideally we'd like to ship this feature in the Sway release that ends up
in the fuelup beta-3 toolchain - otherwise users following the
quick-start guide will be unable to re-deploy the same contract to the
network as it will already exist - they'll need to be able to provide a
salt.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
mitchmindtree authored Feb 17, 2023
1 parent 7031e60 commit 8fdc452
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions forc-plugins/forc-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fuels-signers = { workspace = true }
fuels-types = { workspace = true }
futures = "0.3"
hex = "0.4.3"
rand = "0.8"
serde = "1.0"
serde_json = "1"
sway-core = { version = "0.35.1", path = "../../sway-core" }
Expand Down
10 changes: 9 additions & 1 deletion forc-plugins/forc-client/src/cmd/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use clap::Parser;
use fuel_crypto::SecretKey;

pub use forc::cli::shared::{BuildOutput, BuildProfile, Minify, Pkg, Print};
pub use forc_tx::Gas;
pub use forc_tx::{Gas, Maturity, Salt};

#[derive(Debug, Default, Parser)]
#[clap(bin_name = "forc deploy", version)]
Expand All @@ -16,6 +16,14 @@ pub struct Command {
#[clap(flatten)]
pub gas: Gas,
#[clap(flatten)]
pub maturity: Maturity,
#[clap(flatten)]
pub salt: Salt,
/// Generate a random salt for the contract.
/// Useful for testing or deploying examples to a shared network.
#[clap(long)]
pub random_salt: bool,
#[clap(flatten)]
pub build_output: BuildOutput,
#[clap(flatten)]
pub build_profile: BuildProfile,
Expand Down
4 changes: 3 additions & 1 deletion forc-plugins/forc-client/src/cmd/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use fuel_crypto::SecretKey;

pub use super::submit::Network;
pub use forc::cli::shared::{BuildOutput, BuildProfile, Minify, Pkg, Print};
pub use forc_tx::Gas;
pub use forc_tx::{Gas, Maturity};

/// Run script project.
/// Crafts a script transaction then sends it to a running node.
Expand All @@ -19,6 +19,8 @@ pub struct Command {
#[clap(flatten)]
pub gas: Gas,
#[clap(flatten)]
pub maturity: Maturity,
#[clap(flatten)]
pub build_output: BuildOutput,
#[clap(flatten)]
pub build_profile: BuildProfile,
Expand Down
33 changes: 31 additions & 2 deletions forc-plugins/forc-client/src/op/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use anyhow::{bail, Context, Result};
use forc_pkg::{self as pkg, PackageManifestFile};
use fuel_core_client::client::types::TransactionStatus;
use fuel_core_client::client::FuelClient;
use fuel_tx::{Output, Salt, TransactionBuilder};
use fuel_tx::{Output, TransactionBuilder};
use fuel_vm::prelude::*;
use futures::FutureExt;
use pkg::BuiltPackage;
Expand All @@ -36,8 +36,28 @@ pub async fn deploy(command: cmd::Deploy) -> Result<Vec<DeployedContract>> {
} else {
std::env::current_dir()?
};

let build_opts = build_opts_from_cmd(&command);
let built_pkgs_with_manifest = built_pkgs_with_manifest(&curr_dir, build_opts)?;

// If a salt was specified but we have more than one member to build, there
// may be ambiguity in how the salt should be applied, especially if the
// workspace contains multiple contracts, and especially if one contract
// member is the dependency of another (in which case salt should be
// specified under `[contract- dependencies]`). Considering this, we have a
// simple check to ensure that we only accept salt when deploying a single
// package. In the future, we can consider relaxing this to allow for
// specifying a salt for workspace deployment, as long as there is only one
// root contract member in the package graph.
if command.salt.salt.is_some() && built_pkgs_with_manifest.len() > 1 {
bail!(
"A salt was specified when attempting to deploy a workspace with more than one member.
If you wish to deploy a contract member with salt, deploy the member individually.
If you wish to specify the salt for a contract dependency, \
please do so within the `[contract-dependencies]` table."
)
}

for (member_manifest, built_pkg) in built_pkgs_with_manifest {
if member_manifest
.check_program_type(vec![TreeType::Contract])
Expand All @@ -64,7 +84,14 @@ pub async fn deploy_pkg(
let client = FuelClient::new(node_url)?;

let bytecode = compiled.bytecode.clone().into();
let salt = Salt::new([0; 32]);
let salt = match (command.salt.salt, command.random_salt) {
(Some(salt), false) => salt,
(None, true) => rand::random(),
(None, false) => Default::default(),
(Some(_), true) => {
bail!("Both `--salt` and `--random-salt` were specified: must choose one")
}
};
let mut storage_slots = compiled.storage_slots.clone();
storage_slots.sort();

Expand All @@ -77,6 +104,8 @@ pub async fn deploy_pkg(
let tx = TransactionBuilder::create(bytecode, salt, storage_slots.clone())
.gas_limit(command.gas.limit)
.gas_price(command.gas.price)
// TODO: Spec says maturity should be u32, but fuel-tx wants u64.
.maturity(u64::from(command.maturity.maturity))
.add_output(Output::contract_created(contract_id, state_root))
.finalize_signed(client.clone(), command.unsigned, command.signing_key)
.await?;
Expand Down
2 changes: 2 additions & 0 deletions forc-plugins/forc-client/src/op/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ pub async fn run_pkg(
let tx = TransactionBuilder::script(compiled.bytecode.clone(), script_data)
.gas_limit(command.gas.limit)
.gas_price(command.gas.price)
// TODO: Spec says maturity should be u32, but fuel-tx expects u64.
.maturity(u64::from(command.maturity.maturity))
.add_contracts(contract_ids)
.finalize_signed(client.clone(), command.unsigned, command.signing_key)
.await?;
Expand Down
41 changes: 28 additions & 13 deletions forc-plugins/forc-tx/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! A simple tool for constructing transactions from the command line.
use clap::Parser;
use clap::{Args, Parser};
use devault::Devault;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
Expand Down Expand Up @@ -30,12 +30,10 @@ pub enum Transaction {
pub struct Create {
#[clap(flatten)]
pub gas: Gas,
/// Block until which tx cannot be included.
#[clap(long)]
pub maturity: u32,
/// Added salt used to derive the contract ID.
#[clap(long)]
pub salt: Option<fuel_tx::Salt>,
#[clap(flatten)]
pub maturity: Maturity,
#[clap(flatten)]
pub salt: Salt,
/// Path to the contract bytecode.
#[clap(long)]
pub bytecode: PathBuf,
Expand Down Expand Up @@ -74,9 +72,8 @@ pub struct Mint {
pub struct Script {
#[clap(flatten)]
pub gas: Gas,
/// Block until which tx cannot be included.
#[clap(long)]
pub maturity: u32,
#[clap(flatten)]
pub maturity: Maturity,
/// Script to execute.
#[clap(long)]
pub bytecode: PathBuf,
Expand Down Expand Up @@ -112,6 +109,24 @@ pub struct Gas {
pub limit: u64,
}

/// Block until which tx cannot be included.
#[derive(Debug, Args, Default, Deserialize, Serialize)]
pub struct Maturity {
/// Block height until which tx cannot be included.
#[clap(long = "maturity", default_value_t = 0)]
pub maturity: u32,
}

/// Added salt used to derive the contract ID.
#[derive(Debug, Args, Default, Deserialize, Serialize)]
pub struct Salt {
/// Added salt used to derive the contract ID.
///
/// By default, this is `0x0000000000000000000000000000000000000000000000000000000000000000`.
#[clap(long = "salt")]
pub salt: Option<fuel_tx::Salt>,
}

/// Transaction input.
#[derive(Debug, Parser, Deserialize, Serialize)]
#[clap(name = "input")]
Expand Down Expand Up @@ -633,9 +648,9 @@ impl TryFrom<Create> for fuel_tx::Create {
create.gas.price,
create.gas.limit,
// TODO: `fuel_tx` create shouldn't accept `Word`: spec says `u32`.
create.maturity as fuel_tx::Word,
fuel_tx::Word::from(create.maturity.maturity),
create.bytecode_witness_index,
create.salt.unwrap_or_default(),
create.salt.salt.unwrap_or_default(),
storage_slots,
inputs,
outputs,
Expand Down Expand Up @@ -678,7 +693,7 @@ impl TryFrom<Script> for fuel_tx::Script {
script.gas.price,
script.gas.limit,
// TODO: `fuel_tx` create shouldn't accept `Word`: spec says `u32`.
script.maturity as fuel_tx::Word,
fuel_tx::Word::from(script.maturity.maturity),
script_bytecode,
script_data,
inputs,
Expand Down

0 comments on commit 8fdc452

Please sign in to comment.