From 98b89ca70ba9b6fdf9134d02b2ce93f05a5375ce Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 3 Feb 2021 15:21:15 +0100 Subject: [PATCH 1/8] Fix `#[warn(clippy::ptr_arg)]` --- build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 3dd69103..232f0976 100644 --- a/build.rs +++ b/build.rs @@ -20,7 +20,7 @@ use std::{ fs::File, io::{prelude::*, Write}, iter::Iterator, - path::PathBuf, + path::{Path, PathBuf}, }; use anyhow::Result; @@ -64,7 +64,7 @@ fn main() { ); } -fn zip_dir(src_dir: &PathBuf, dst_file: &PathBuf, method: CompressionMethod) -> Result<()> { +fn zip_dir(src_dir: &Path, dst_file: &Path, method: CompressionMethod) -> Result<()> { if !src_dir.exists() { anyhow::bail!("src_dir '{}' does not exist", src_dir.display()); } -- GitLab From 10a9afb58d0e812b06f7ec0492c848817c689afc Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 3 Feb 2021 13:10:16 +0100 Subject: [PATCH 2/8] Use either `binaryen-rs` dep or `wasm-opt` binary --- Cargo.toml | 3 +- src/cmd/build.rs | 76 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fed702dd..2be41587 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ serde = { version = "1.0.123", default-features = false, features = ["derive"] } serde_json = "1.0.61" tempfile = "3.2.0" url = { version = "2.2.0", features = ["serde"] } -binaryen = "0.12.0" +binaryen = { version = "0.12.0", optional = true } # dependencies for optional extrinsics feature async-std = { version = "1.9.0", optional = true } @@ -61,6 +61,7 @@ wabt = "0.10.0" [features] default = [] +wasm-opt-unavailable = ["binaryen"] # Enable this for (experimental) commands to deploy, instantiate and call contracts. # diff --git a/src/cmd/build.rs b/src/cmd/build.rs index adf88e90..4785dc4e 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -18,9 +18,12 @@ use std::{ convert::TryFrom, fs::{metadata, File}, io::{Read, Write}, - path::PathBuf, + path::{Path, PathBuf}, }; +#[cfg(not(feature = "wasm-opt-unavailable"))] +use std::{io, process::Command}; + use crate::{ crate_metadata::CrateMetadata, maybe_println, util, @@ -261,23 +264,11 @@ 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 codegen_config = binaryen::CodegenConfig { - // execute -O3 optimization passes (spends potentially a lot of time optimizing) - optimization_level: 3, - // the default - shrink_level: 1, - // the default - debug_info: false, - }; - 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 mut module = binaryen::Module::read(&dest_wasm_file_content) - .map_err(|_| anyhow::anyhow!("binaryen failed to read file content"))?; - module.optimize(&codegen_config); - let optimized_wasm = module.write(); + let optimized_wasm = get_optimized_wasm(crate_metadata, &optimized, &dest_wasm_file_content)?; let mut optimized_wasm_file = File::create(optimized.as_os_str())?; optimized_wasm_file.write_all(&optimized_wasm)?; @@ -293,6 +284,63 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result { }) } +/// Optimizes the Wasm supplied as `wasm` using the `binaryen-rs` dependency. +/// +/// If successful, the optimized Wasm is returned as a `Vec`. +#[cfg(feature = "wasm-opt-unavailable")] +fn get_optimized_wasm(_: &CrateMetadata, _: &Path, wasm: &[u8]) -> Result> { + let codegen_config = binaryen::CodegenConfig { + // execute -O3 optimization passes (spends potentially a lot of time optimizing) + optimization_level: 3, + // the default + shrink_level: 1, + // the default + debug_info: false, + }; + let mut module = binaryen::Module::read(&wasm) + .map_err(|_| anyhow::anyhow!("binaryen failed to read file content"))?; + module.optimize(&codegen_config); + Ok(module.write()) +} + +/// Optimizes the Wasm supplied as `crate_metadata.dest_wasm` using +/// the `wasm-opt` binary. +/// +/// If successful, the optimized Wasm file is created under `optimized` +/// and returned as a `Vec`. +#[cfg(not(feature = "wasm-opt-unavailable"))] +fn get_optimized_wasm( + crate_metadata: &CrateMetadata, + optimized: &Path, + _: &[u8], +) -> Result> { + // check `wasm-opt` is installed + if which::which("wasm-opt").is_err() { + anyhow::bail!( + "{}", + "wasm-opt is not installed. Install this tool on your system in order to \n\ + reduce the size of your contract's Wasm binary. \n\ + See https://github.com/WebAssembly/binaryen#tools" + .bright_yellow() + ); + } + + let output = Command::new("wasm-opt") + .arg(crate_metadata.dest_wasm.as_os_str()) + .arg("-O3") // execute -O3 optimization passes (spends potentially a lot of time optimizing) + .arg("-o") + .arg(optimized.as_os_str()) + .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) +} + /// Executes build of the smart-contract which produces a wasm binary that is ready for deploying. /// /// It does so by invoking `cargo build` and then post processing the final binary. -- GitLab From e3b6dca1660a3f3313da11d89bb51657601b4bd0 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 4 Feb 2021 07:29:42 +0100 Subject: [PATCH 3/8] Implement reviewers suggestions --- Cargo.toml | 2 +- src/cmd/build.rs | 34 +++++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2be41587..28282bbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ wabt = "0.10.0" [features] default = [] -wasm-opt-unavailable = ["binaryen"] +binaryen-as-dependency = ["binaryen"] # Enable this for (experimental) commands to deploy, instantiate and call contracts. # diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 4785dc4e..4104a372 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -21,7 +21,7 @@ use std::{ path::{Path, PathBuf}, }; -#[cfg(not(feature = "wasm-opt-unavailable"))] +#[cfg(not(feature = "binaryen-as-dependency"))] use std::{io, process::Command}; use crate::{ @@ -268,7 +268,7 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result { let mut dest_wasm_file_content = Vec::new(); dest_wasm_file.read_to_end(&mut dest_wasm_file_content)?; - let optimized_wasm = get_optimized_wasm(crate_metadata, &optimized, &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)?; @@ -286,12 +286,20 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result { /// Optimizes the Wasm supplied as `wasm` using the `binaryen-rs` dependency. /// +/// 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`. -#[cfg(feature = "wasm-opt-unavailable")] -fn get_optimized_wasm(_: &CrateMetadata, _: &Path, wasm: &[u8]) -> Result> { +#[cfg(feature = "binaryen-as-dependency")] +fn do_optimization( + _: &CrateMetadata, + _: &Path, + wasm: &[u8], + optimization_level: u32, +) -> Result> { let codegen_config = binaryen::CodegenConfig { - // execute -O3 optimization passes (spends potentially a lot of time optimizing) - optimization_level: 3, + // number of optimization passes (spends potentially a lot of time optimizing) + optimization_level, // the default shrink_level: 1, // the default @@ -306,13 +314,17 @@ fn get_optimized_wasm(_: &CrateMetadata, _: &Path, wasm: &[u8]) -> Result`. -#[cfg(not(feature = "wasm-opt-unavailable"))] -fn get_optimized_wasm( +#[cfg(not(feature = "binaryen-as-dependency"))] +fn do_optimization( crate_metadata: &CrateMetadata, - optimized: &Path, + optimized_dest: &Path, _: &[u8], + optimization_level: u32, ) -> Result> { // check `wasm-opt` is installed if which::which("wasm-opt").is_err() { @@ -327,9 +339,9 @@ fn get_optimized_wasm( let output = Command::new("wasm-opt") .arg(crate_metadata.dest_wasm.as_os_str()) - .arg("-O3") // execute -O3 optimization passes (spends potentially a lot of time optimizing) + .arg(format!("-O{}", optimization_level)) .arg("-o") - .arg(optimized.as_os_str()) + .arg(optimized_dest.as_os_str()) .output()?; if !output.status.success() { -- GitLab From 1fd35bcdc1893b6908af9eb9cf4d130ac41a5af8 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 4 Feb 2021 07:38:28 +0100 Subject: [PATCH 4/8] Rename `optimization_level` to `optimization_passes` --- src/cmd/build.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 4104a372..d5a0cffd 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -286,7 +286,7 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result { /// Optimizes the Wasm supplied as `wasm` using the `binaryen-rs` dependency. /// -/// The supplied `optimization_level` denotes the number of optimization passes, +/// The supplied `optimization_passes` 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`. @@ -295,11 +295,11 @@ fn do_optimization( _: &CrateMetadata, _: &Path, wasm: &[u8], - optimization_level: u32, + optimization_passes: u32, ) -> Result> { let codegen_config = binaryen::CodegenConfig { // number of optimization passes (spends potentially a lot of time optimizing) - optimization_level, + optimization_passes, // the default shrink_level: 1, // the default @@ -314,7 +314,7 @@ fn do_optimization( /// Optimizes the Wasm supplied as `crate_metadata.dest_wasm` using /// the `wasm-opt` binary. /// -/// The supplied `optimization_level` denotes the number of optimization passes, +/// The supplied `optimization_passes` 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` @@ -324,7 +324,7 @@ fn do_optimization( crate_metadata: &CrateMetadata, optimized_dest: &Path, _: &[u8], - optimization_level: u32, + optimization_passes: u32, ) -> Result> { // check `wasm-opt` is installed if which::which("wasm-opt").is_err() { @@ -339,7 +339,7 @@ fn do_optimization( let output = Command::new("wasm-opt") .arg(crate_metadata.dest_wasm.as_os_str()) - .arg(format!("-O{}", optimization_level)) + .arg(format!("-O{}", optimization_passes)) .arg("-o") .arg(optimized_dest.as_os_str()) .output()?; -- GitLab From c06ab6edbaf18708f7cc733ec1ddbc041231a36c Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 4 Feb 2021 07:39:41 +0100 Subject: [PATCH 5/8] Revert "Rename `optimization_level` to `optimization_passes`" This reverts commit 1fd35bcdc1893b6908af9eb9cf4d130ac41a5af8. --- src/cmd/build.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cmd/build.rs b/src/cmd/build.rs index d5a0cffd..4104a372 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -286,7 +286,7 @@ fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result { /// Optimizes the Wasm supplied as `wasm` using the `binaryen-rs` dependency. /// -/// The supplied `optimization_passes` denotes the number of optimization passes, +/// 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`. @@ -295,11 +295,11 @@ fn do_optimization( _: &CrateMetadata, _: &Path, wasm: &[u8], - optimization_passes: u32, + optimization_level: u32, ) -> Result> { let codegen_config = binaryen::CodegenConfig { // number of optimization passes (spends potentially a lot of time optimizing) - optimization_passes, + optimization_level, // the default shrink_level: 1, // the default @@ -314,7 +314,7 @@ fn do_optimization( /// Optimizes the Wasm supplied as `crate_metadata.dest_wasm` using /// the `wasm-opt` binary. /// -/// The supplied `optimization_passes` denotes the number of optimization passes, +/// 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` @@ -324,7 +324,7 @@ fn do_optimization( crate_metadata: &CrateMetadata, optimized_dest: &Path, _: &[u8], - optimization_passes: u32, + optimization_level: u32, ) -> Result> { // check `wasm-opt` is installed if which::which("wasm-opt").is_err() { @@ -339,7 +339,7 @@ fn do_optimization( let output = Command::new("wasm-opt") .arg(crate_metadata.dest_wasm.as_os_str()) - .arg(format!("-O{}", optimization_passes)) + .arg(format!("-O{}", optimization_level)) .arg("-o") .arg(optimized_dest.as_os_str()) .output()?; -- GitLab From 3fea2599594b2753a5cfef2f523be2fe6b6ba90b Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 4 Feb 2021 08:09:14 +0100 Subject: [PATCH 6/8] Update installation instructions --- README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d765607c..3eebf48c 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,19 @@ A CLI tool for helping setting up and managing WebAssembly smart contracts writt ## Installation -- **Prerequisites** +`rust-src` is a prerequisite: `rustup component add rust-src`. - - **rust-src**: `rustup component add rust-src` - - A C++14 compiler and python >= 3.5 is required for building the - [binaryen](https://github.com/WebAssembly/binaryen) dependency. - `binaryen` is built automatically during the `cargo-contract` build process. +We optimize the resulting contract Wasm using `binaryen`. You have two options of how +to invoke `binaryen`: -- **Install latest version from [crates.io](https://crates.io/crates/cargo-contract)** - - `cargo install cargo-contract` + - The preferred way: + Install [`binaryen`](https://github.com/WebAssembly/binaryen#tools). Many package managers + have it available nowadays (it's a package for e.g. Debian/Ubuntu, Homebrew, Arch Linux, etc.). + After you've installed `wasm-opt` execute `cargo install --force cargo-contract`. + + - Build `binaryen` as a dependency when installing `cargo-contract`: + A C++14 compiler and python >= 3.5 is required. + Execute `cargo install --force --features wasm-opt-unavailable cargo-contract`. ## Usage -- GitLab From 9e8bc19ab233db316a381f0ea3b4535c934af43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Thu, 4 Feb 2021 08:11:32 +0100 Subject: [PATCH 7/8] Update readme --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3eebf48c..dd95e2d9 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,14 @@ A CLI tool for helping setting up and managing WebAssembly smart contracts writt `rust-src` is a prerequisite: `rustup component add rust-src`. -We optimize the resulting contract Wasm using `binaryen`. You have two options of how -to invoke `binaryen`: +We optimize the resulting contract Wasm using `binaryen`. You have two options for installing it: - - The preferred way: + - _The preferred way:_ Install [`binaryen`](https://github.com/WebAssembly/binaryen#tools). Many package managers have it available nowadays (it's a package for e.g. Debian/Ubuntu, Homebrew, Arch Linux, etc.). - After you've installed `wasm-opt` execute `cargo install --force cargo-contract`. + After you've installed the package execute `cargo install --force cargo-contract`. - - Build `binaryen` as a dependency when installing `cargo-contract`: + - _Build `binaryen` as a dependency when installing `cargo-contract`:_ A C++14 compiler and python >= 3.5 is required. Execute `cargo install --force --features wasm-opt-unavailable cargo-contract`. -- GitLab From 3047713517887e794f7ead54406bc49f46f7d67e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Thu, 4 Feb 2021 08:16:06 +0100 Subject: [PATCH 8/8] Add package manager links --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dd95e2d9..600d4be4 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ We optimize the resulting contract Wasm using `binaryen`. You have two options f - _The preferred way:_ Install [`binaryen`](https://github.com/WebAssembly/binaryen#tools). Many package managers - have it available nowadays (it's a package for e.g. Debian/Ubuntu, Homebrew, Arch Linux, etc.). + have it available nowadays ‒ e.g. it's a package for [Debian/Ubuntu](https://tracker.debian.org/pkg/binaryen), + [Homebrew](https://formulae.brew.sh/formula/binaryen) and [Arch Linux](https://archlinux.org/packages/community/x86_64/binaryen/). After you've installed the package execute `cargo install --force cargo-contract`. - _Build `binaryen` as a dependency when installing `cargo-contract`:_ -- GitLab