diff --git a/Cargo.lock b/Cargo.lock index ce06462..2b36935 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -572,6 +572,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "anyhow" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" + [[package]] name = "ark-ff" version = "0.3.0" @@ -1068,6 +1074,7 @@ dependencies = [ "wasm-gen", "wasmer", "wasmparser 0.213.0", + "wasmprinter", ] [[package]] @@ -4862,6 +4869,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -5619,6 +5635,28 @@ dependencies = [ "indexmap 2.6.0", ] +[[package]] +name = "wasmparser" +version = "0.221.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083" +dependencies = [ + "bitflags 2.6.0", + "indexmap 2.6.0", + "semver 1.0.23", +] + +[[package]] +name = "wasmprinter" +version = "0.221.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a80742ff1b9e6d8c231ac7c7247782c6fc5bce503af760bca071811e5fc9ee56" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser 0.221.2", +] + [[package]] name = "wast" version = "220.0.0" diff --git a/main/Cargo.toml b/main/Cargo.toml index d09fc9b..3701d43 100644 --- a/main/Cargo.toml +++ b/main/Cargo.toml @@ -51,3 +51,4 @@ alloy-provider = "0.2.1" alloy-signer-local = { version = "0.2.1", features = ["keystore"] } alloy-signer = "0.2.1" alloy-transport = "0.2.1" +wasmprinter = "0.221.2" diff --git a/main/README.md b/main/README.md new file mode 120000 index 0000000..32d46ee --- /dev/null +++ b/main/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/main/src/check.rs b/main/src/check.rs index d9e99c1..9cbb534 100644 --- a/main/src/check.rs +++ b/main/src/check.rs @@ -62,12 +62,6 @@ pub async fn check(cfg: &CheckConfig) -> Result { greyln!("reading wasm file at {}", wasm.to_string_lossy().lavender()); } - // Next, we include the project's hash as a custom section - // in the user's WASM so it can be verified by Cargo stylus' - // reproducible verification. This hash is added as a section that is - // ignored by WASM runtimes, so it will only exist in the file - // for metadata purposes. - // add_project_hash_to_wasm_file(wasm, project_hash) let (wasm_file_bytes, code) = project::compress_wasm(&wasm, project_hash).wrap_err("failed to compress WASM")?; diff --git a/main/src/project.rs b/main/src/project.rs index e9b3fb5..95f34c8 100644 --- a/main/src/project.rs +++ b/main/src/project.rs @@ -66,6 +66,10 @@ pub fn build_dylib(cfg: BuildConfig) -> Result { let cargo_toml_version = extract_cargo_toml_version(&cargo_toml_path)?; greyln!("Building project with Cargo.toml version: {cargo_toml_version}"); + let project_name = extract_cargo_project_name(&cargo_toml_path)? + .replace("-", "_") + .replace("\"", ""); + cmd.arg("build"); cmd.arg("--lib"); cmd.arg("--locked"); @@ -101,7 +105,7 @@ pub fn build_dylib(cfg: BuildConfig) -> Result { // Gets the files in the release folder. let release_files: Vec = fs::read_dir(&release_path) - .map_err(|e| eyre!("could not read deps dir: {e}"))? + .map_err(|e| eyre!("could not read release deps dir: {e}"))? .filter_map(|r| r.ok()) .map(|r| r.path()) .filter(|r| r.is_file()) @@ -110,10 +114,14 @@ pub fn build_dylib(cfg: BuildConfig) -> Result { let wasm_file_path = release_files .into_iter() .find(|p| { - if let Some(ext) = p.file_name() { - return ext.to_string_lossy().contains(".wasm"); + if let Some(filename) = p.file_name() { + let mut expected_name = project_name.clone(); + expected_name.push_str(".wasm"); + + filename.to_string_lossy().ends_with(&expected_name) + } else { + false } - false }) .ok_or(BuildError::NoWasmFound { path: release_path })?; @@ -230,6 +238,22 @@ pub fn extract_cargo_toml_version(cargo_toml_path: &PathBuf) -> Result { Ok(version.to_string()) } +pub fn extract_cargo_project_name(cargo_toml_path: &PathBuf) -> Result { + let cargo_toml_contents = fs::read_to_string(cargo_toml_path) + .context("expected to find a Cargo.toml file in project directory")?; + + let cargo_toml: Value = + toml::from_str(&cargo_toml_contents).context("failed to parse Cargo.toml")?; + + let Some(pkg) = cargo_toml.get("package") else { + bail!("package section not found in Cargo.toml"); + }; + let Some(name) = pkg.get("name") else { + bail!("could not find name in project's Cargo.toml [package] section"); + }; + Ok(name.to_string()) +} + pub fn read_file_preimage(filename: &Path) -> Result> { let mut contents = Vec::with_capacity(1024); { @@ -326,6 +350,18 @@ pub fn compress_wasm(wasm: &PathBuf, project_hash: [u8; 32]) -> Result<(Vec, let wasm = fs::read(wasm).wrap_err_with(|| eyre!("failed to read Wasm {}", wasm.to_string_lossy()))?; + // We convert the WASM from binary to text and back to binary as this trick removes any dangling + // mentions of reference types in the wasm body, which are not yet supported by Arbitrum chain backends. + let wat_str = + wasmprinter::print_bytes(&wasm).map_err(|e| eyre!("failed to convert Wasm to Wat: {e}"))?; + let wasm = wasmer::wat2wasm(wat_str.as_bytes()) + .map_err(|e| eyre!("failed to convert Wat to Wasm: {e}"))?; + + // We include the project's hash as a custom section + // in the user's WASM so it can be verified by Cargo stylus' + // reproducible verification. This hash is added as a section that is + // ignored by WASM runtimes, so it will only exist in the file + // for metadata purposes. let wasm = add_project_hash_to_wasm_file(&wasm, project_hash) .wrap_err("failed to add project hash to wasm file as custom section")?;