Skip to content

Commit

Permalink
minor ux improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
kayagokalp committed Aug 8, 2024
1 parent 11e3097 commit 45a0358
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 11 deletions.
93 changes: 89 additions & 4 deletions forc-plugins/forc-client/src/op/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use crate::{
constants::TX_SUBMIT_TIMEOUT_MS,
util::{
node_url::get_node_url,
pkg::{built_pkgs, create_proxy_contract, update_proxy_address_in_manifest},
pkg::{
build_loader_contract, built_pkgs, create_proxy_contract, split_into_chunks,
update_proxy_address_in_manifest,
},
target::Target,
tx::{
bech32_from_secret, prompt_forc_wallet_password, select_secret_key,
Expand Down Expand Up @@ -42,7 +45,7 @@ use sway_core::BuildTarget;
/// contract size is bigger than this amount, forc-deploy will automatically
/// starts dividing the contract and deploy them in chunks automatically.
/// The value is in bytes.
const MAX_CONTRACT_SIZE: usize = 100_000;
const MAX_CONTRACT_SIZE: usize = 1_000;

#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
pub struct DeployedContract {
Expand Down Expand Up @@ -129,6 +132,70 @@ fn validate_and_parse_salts<'a>(
Ok(contract_salt_map)
}

async fn deploy_chunked(
command: &cmd::Deploy,
compiled: &BuiltPackage,
salt: Salt,
signing_key: &SecretKey,
provider: &Provider,
pkg_name: &str,
) -> anyhow::Result<(ContractId, Vec<ContractId>)> {
println_action_green("Splitting", &format!("{pkg_name} into chunks"));
let contract_chunks = split_into_chunks(compiled.bytecode.bytes.clone(), MAX_CONTRACT_SIZE)?;
let mut deployed_contracts = vec![];
println_action_green("Deploying", &format!("{pkg_name} chunks"));
let chain_info = provider.chain_info().await?;
let target = Target::from_str(&chain_info.name).unwrap_or(Target::testnet());
let contract_url = match target.explorer_url() {
Some(explorer_url) => format!("{explorer_url}/contract/0x"),
None => "".to_string(),
};
for contract_chunk in contract_chunks {
let chunk_id = contract_chunk.id();
let deployed_chunk = contract_chunk.deploy(provider, &salt, signing_key).await?;
let chunk_contract_id = deployed_chunk.contract_id();
println_action_green(
"Finished",
&format!("deploying chunk {chunk_id} for {pkg_name}: {chunk_contract_id}"),
);
deployed_contracts.push(deployed_chunk);
}
println_action_green("Deployed", &format!("{pkg_name} chunks"));
let deployed_contract_ids: Vec<String> = deployed_contracts
.iter()
.map(|deployed_contract| format!("0x{}", deployed_contract.contract_id()))
.collect();

let deployed_contracts: Vec<_> = deployed_contracts
.iter()
.map(|deployed_contract| *deployed_contract.contract_id())
.collect();

let program_abi = match &compiled.program_abi {
sway_core::asm_generation::ProgramABI::Fuel(abi) => abi,
_ => bail!("contract chunking is only supported with fuelVM"),
};

println_action_green("Building", &format!("loader contract for {pkg_name}"));
let loader_contract = build_loader_contract(
program_abi,
&deployed_contract_ids,
deployed_contracts.len(),
pkg_name,
&build_opts_from_cmd(command),
)?;

println_action_green("Deploying", &format!("loader contract for {pkg_name}"));
let deployed_id = deploy_pkg(command, &loader_contract, salt, provider, signing_key).await?;

println_action_green(
"Finished",
&format!("deploying loader contract for {pkg_name} {contract_url}{deployed_id}"),
);

Ok((deployed_id, deployed_contracts))
}

/// Deploys a new proxy contract for the given package.
async fn deploy_new_proxy(
pkg_name: &str,
Expand Down Expand Up @@ -284,7 +351,25 @@ pub async fn deploy(command: cmd::Deploy) -> Result<Vec<DeployedContract>> {
bail!("Both `--salt` and `--default-salt` were specified: must choose one")
}
};
let deployed_contract_id = deploy_pkg(&command, pkg, salt, &provider, &signing_key).await?;
let bytecode_size = pkg.bytecode.bytes.len();
let (deployed_contract_id, chunk_ids) = if bytecode_size > MAX_CONTRACT_SIZE {
// Deploy chunked
let node_url = get_node_url(&command.node, &pkg.descriptor.manifest_file.network)?;
let provider = Provider::connect(node_url).await?;
deploy_chunked(
&command,
pkg,
salt,
&signing_key,
&provider,
&pkg.descriptor.name,
)
.await?
} else {
let deployed_contract_id =
deploy_pkg(&command, pkg, salt, &provider, &signing_key).await?;
(deployed_contract_id, vec![])
};

let proxy_id = match &pkg.descriptor.manifest_file.proxy {
Some(forc_pkg::manifest::Proxy {
Expand Down Expand Up @@ -331,7 +416,7 @@ pub async fn deploy(command: cmd::Deploy) -> Result<Vec<DeployedContract>> {
let deployed_contract = DeployedContract {
id: deployed_contract_id,
proxy: proxy_id,
chunks: vec![],
chunks: chunk_ids,
};
deployed_contracts.push(deployed_contract);
}
Expand Down
34 changes: 27 additions & 7 deletions forc-plugins/forc-client/src/util/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub const LOADER_CONTRACT_FORC_TOML: &str = r#"
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "main.sw"
license = "Apache-2.0"
name = "proxy_contract"
name = "loader_contract"
[dependencies]
"#;
Expand Down Expand Up @@ -103,7 +103,7 @@ pub(crate) fn built_pkgs(path: &Path, build_opts: &BuildOpts) -> Result<Vec<Arc<
Ok(built_pkgs)
}

pub fn generate_proxy_contract_with_chunking_src(
pub fn generate_chunk_loader_contract_src(
abi: &ProgramABI,
num_chunks: usize,
chunk_contract_ids: &[String],
Expand Down Expand Up @@ -309,8 +309,7 @@ pub(crate) fn create_chunk_loader_contract(
.truncate(true)
.open(proxy_contract_dir.join(SRC_DIR).join(MAIN_ENTRY))?;

let contract_str =
generate_proxy_contract_with_chunking_src(abi, num_chunks, chunk_contract_ids);
let contract_str = generate_chunk_loader_contract_src(abi, num_chunks, chunk_contract_ids);
write!(f, "{}", contract_str)?;
Ok(proxy_contract_dir)
}
Expand Down Expand Up @@ -338,6 +337,10 @@ impl ContractChunk {
Self { id, size, bytecode }
}

pub fn id(&self) -> usize {
self.id
}

pub async fn deploy(
self,
provider: &Provider,
Expand Down Expand Up @@ -388,12 +391,29 @@ pub fn split_into_chunks(bytecode: Vec<u8>, chunk_size: usize) -> Result<Vec<Con
Ok(chunks)
}

pub fn build_loader_contract(
abi: &ProgramABI,
chunk_contract_ids: &[String],
num_chunks: usize,
pkg_name: &str,
build_opts: &BuildOpts,
) -> Result<Arc<BuiltPackage>> {
let loader_contract =
create_chunk_loader_contract(abi, chunk_contract_ids, num_chunks, pkg_name)?;
let mut build_opts = build_opts.clone();
let proxy_contract_dir_str = format!("{}", loader_contract.clone().display());
build_opts.pkg.path = Some(proxy_contract_dir_str);
let built_pkgs = built_pkgs(&loader_contract, &build_opts)?;
let built_pkg = built_pkgs
.first()
.cloned()
.ok_or_else(|| anyhow::anyhow!("could not get proxy contract"))?;
Ok(built_pkg)
}

#[cfg(test)]
mod tests {
use super::*;
use forc_pkg::BuildOpts;
use forc_util::user_forc_directory;
use std::path::PathBuf;

#[test]
fn test_split_into_chunks_exact_division() {
Expand Down

0 comments on commit 45a0358

Please sign in to comment.