diff --git a/Cargo.lock b/Cargo.lock index e5c48a6fb91649e034fd37f7fc6593efc8e2331e..18ea419be5dca25b082efa761b48288c54bd0a18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "Inflector" version = "0.11.4" @@ -489,6 +491,7 @@ dependencies = [ "colored", "contract-metadata", "env_logger", + "funty", "futures", "heck", "hex", diff --git a/Cargo.toml b/Cargo.toml index 420a9ba9c10b7a17a99cb1a3b2dccbbe24e0b980..7883206cee8a6360bab45ddcfea61b42c68c813c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,9 @@ subxt = { version = "0.14.0", package = "substrate-subxt", optional = true } futures = { version = "0.3.12", optional = true } hex = { version = "0.4.2", optional = true } +# Should be removed once bitvecto-rs/bitvec#105 is resolved +funty = "=1.1.0" + [build-dependencies] anyhow = "1.0.38" zip = { version = "0.5.10", default-features = false } diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 98060919e27331224f27a1d93d8225f7cd3d7e3e..2a03e774da649f1a11ecd7ed9fc27f689f378858 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -14,23 +14,24 @@ // You should have received a copy of the GNU General Public License // along with cargo-contract. If not, see . +use std::{convert::TryFrom, ffi::OsStr, fs::metadata, path::PathBuf}; + +#[cfg(feature = "binaryen-as-dependency")] use std::{ - convert::TryFrom, - fs::{metadata, File}, + fs::File, io::{Read, Write}, - path::{Path, PathBuf}, }; #[cfg(not(feature = "binaryen-as-dependency"))] -use std::{io, process::Command}; +use std::process::Command; use crate::{ crate_metadata::CrateMetadata, maybe_println, util, validate_wasm, workspace::{ManifestPath, Profile, Workspace}, - BuildArtifacts, BuildResult, UnstableFlags, UnstableOptions, VerbosityFlags, + BuildArtifacts, BuildResult, OptimizationResult, UnstableFlags, UnstableOptions, Verbosity, + VerbosityFlags, }; -use crate::{OptimizationResult, Verbosity}; use anyhow::{Context, Result}; use colored::Colorize; use parity_wasm::elements::{External, MemoryType, Module, Section}; @@ -254,6 +255,11 @@ fn post_process_wasm(crate_metadata: &CrateMetadata) -> Result<()> { validate_wasm::validate_import_section(&module)?; + debug_assert!( + !module.clone().to_bytes().unwrap().is_empty(), + "resulting wasm size of post processing must be > 0" + ); + parity_wasm::serialize_to_file(&crate_metadata.dest_wasm, module)?; Ok(()) } @@ -263,23 +269,20 @@ fn post_process_wasm(crate_metadata: &CrateMetadata) -> Result<()> { /// The intention is to reduce the size of bloated wasm binaries as a result of missing /// optimizations (or bugs?) between Rust and Wasm. fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result { - let mut optimized = crate_metadata.dest_wasm.clone(); - optimized.set_file_name(format!("{}-opt.wasm", crate_metadata.package_name)); + let mut dest_optimized = crate_metadata.dest_wasm.clone(); + dest_optimized.set_file_name(format!("{}-opt.wasm", crate_metadata.package_name)); - let mut dest_wasm_file = File::open(crate_metadata.dest_wasm.as_os_str())?; - let mut dest_wasm_file_content = Vec::new(); - dest_wasm_file.read_to_end(&mut dest_wasm_file_content)?; - - let optimized_wasm = do_optimization(crate_metadata, &optimized, &dest_wasm_file_content, 3)?; - - let mut optimized_wasm_file = File::create(optimized.as_os_str())?; - optimized_wasm_file.write_all(&optimized_wasm)?; + let _ = do_optimization( + crate_metadata.dest_wasm.as_os_str(), + &dest_optimized.as_os_str(), + 3, + )?; let original_size = metadata(&crate_metadata.dest_wasm)?.len() as f64 / 1000.0; - let optimized_size = metadata(&optimized)?.len() as f64 / 1000.0; + let optimized_size = metadata(&dest_optimized)?.len() as f64 / 1000.0; // overwrite existing destination wasm file with the optimised version - std::fs::rename(&optimized, &crate_metadata.dest_wasm)?; + std::fs::rename(&dest_optimized, &crate_metadata.dest_wasm)?; Ok(OptimizationResult { original_size, optimized_size, @@ -291,14 +294,17 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result { /// The supplied `optimization_level` denotes the number of optimization passes, /// resulting in potentially a lot of time spent optimizing. /// -/// If successful, the optimized Wasm is returned as a `Vec`. +/// If successful, the optimized wasm is written to `dest_optimized`. #[cfg(feature = "binaryen-as-dependency")] fn do_optimization( - _: &CrateMetadata, - _: &Path, - wasm: &[u8], + dest_wasm: &OsStr, + dest_optimized: &OsStr, optimization_level: u32, -) -> Result> { +) -> Result<()> { + let mut dest_wasm_file = File::open(dest_wasm)?; + let mut dest_wasm_file_content = Vec::new(); + dest_wasm_file.read_to_end(&mut dest_wasm_file_content)?; + let codegen_config = binaryen::CodegenConfig { // number of optimization passes (spends potentially a lot of time optimizing) optimization_level, @@ -307,10 +313,14 @@ fn do_optimization( // the default debug_info: false, }; - let mut module = binaryen::Module::read(&wasm) + let mut module = binaryen::Module::read(&dest_wasm_file_content) .map_err(|_| anyhow::anyhow!("binaryen failed to read file content"))?; module.optimize(&codegen_config); - Ok(module.write()) + + let mut optimized_wasm_file = File::create(dest_optimized)?; + optimized_wasm_file.write_all(&module.write())?; + + Ok(()) } /// Optimizes the Wasm supplied as `crate_metadata.dest_wasm` using @@ -319,15 +329,13 @@ fn do_optimization( /// The supplied `optimization_level` denotes the number of optimization passes, /// resulting in potentially a lot of time spent optimizing. /// -/// If successful, the optimized Wasm file is created under `optimized` -/// and returned as a `Vec`. +/// If successful, the optimized wasm is written to `dest_optimized`. #[cfg(not(feature = "binaryen-as-dependency"))] fn do_optimization( - crate_metadata: &CrateMetadata, - optimized_dest: &Path, - _: &[u8], + dest_wasm: &OsStr, + dest_optimized: &OsStr, optimization_level: u32, -) -> Result> { +) -> Result<()> { // check `wasm-opt` is installed if which::which("wasm-opt").is_err() { anyhow::bail!( @@ -340,19 +348,17 @@ fn do_optimization( } let output = Command::new("wasm-opt") - .arg(crate_metadata.dest_wasm.as_os_str()) + .arg(dest_wasm) .arg(format!("-O{}", optimization_level)) .arg("-o") - .arg(optimized_dest.as_os_str()) + .arg(dest_optimized) .output()?; if !output.status.success() { // Dump the output streams produced by `wasm-opt` into the stdout/stderr. - io::stdout().write_all(&output.stdout)?; - io::stderr().write_all(&output.stderr)?; anyhow::bail!("wasm-opt optimization failed"); } - Ok(output.stdout) + Ok(()) } /// Executes build of the smart-contract which produces a wasm binary that is ready for deploying. @@ -462,6 +468,7 @@ mod tests_ci_only { // the path can never be e.g. `foo_target/ink` -- the assert // would fail for that. assert!(res.target_directory.ends_with("target/ink")); + assert!(res.optimization_result.unwrap().optimized_size > 0.0); Ok(()) }) } diff --git a/src/cmd/metadata.rs b/src/cmd/metadata.rs index 0197c2f1f2a136f242f76b81e5ee738a46df4c38..4a20bb3154a5d992569870b5d7760e5fd47a5859 100644 --- a/src/cmd/metadata.rs +++ b/src/cmd/metadata.rs @@ -390,7 +390,8 @@ mod tests { assert!( dest_bundle.exists(), - format!("Missing metadata file '{}'", dest_bundle.display()) + "Missing metadata file '{}'", + dest_bundle.display() ); let source = metadata_json.get("source").expect("source not found"); diff --git a/src/main.rs b/src/main.rs index 0d4c63e58c38caeed981d0dcab58e6fd5150618c..445d488645686d6f695f010d6fc21746dc43c33d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -238,6 +238,10 @@ impl BuildResult { format!("{:.1}K", optimization.0).bold(), format!("{:.1}K", optimization.1).bold(), ); + debug_assert!( + optimization.1 > 0.0, + "optimized file size must be greater 0" + ); if self.build_artifact == BuildArtifacts::CodeOnly { let out = format!(