diff --git a/Cargo.lock b/Cargo.lock
index 0c20d3890a37ffd8ce2e3cb5d42a02864816245e..49d4321a723ec5e7b425e92d879c1ce4ff2607d2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -269,6 +269,7 @@ dependencies = [
"assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"async-std 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -284,6 +285,7 @@ dependencies = [
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"zip 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -346,6 +348,16 @@ dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "colored"
+version = "1.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "const-random"
version = "0.1.8"
@@ -2952,6 +2964,15 @@ dependencies = [
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "which"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "winapi"
version = "0.2.8"
@@ -3074,6 +3095,7 @@ dependencies = [
"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62"
+"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d"
"checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a"
"checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a"
"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
@@ -3350,6 +3372,7 @@ dependencies = [
"checksum webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e664e770ac0110e2384769bcc59ed19e329d81f555916a6e072714957b81b4"
"checksum webpki-roots 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a262ae37dd9d60f60dd473d1158f9fbebf110ba7b6a5051c8160460f6043718b"
"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
+"checksum which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
diff --git a/Cargo.toml b/Cargo.toml
index 3cee7d4349b3b0abdb420b560bb4992dd6ea6e75..b858e4be8582e859fba35d37e6c97cf7b1ed29cd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,6 +25,8 @@ pwasm-utils = "0.12"
parity-wasm = "0.41"
cargo_metadata = "0.9"
codec = { package = "parity-scale-codec", version = "1.1" }
+which = "3.1.0"
+colored = "1.9"
# dependencies for optional extrinsics feature
async-std = { version = "1.2.0", optional = true }
diff --git a/src/cmd/build.rs b/src/cmd/build.rs
index b7deddfb73bf4d1108f60579e8cb7557e6a59bcd..c054f591ccb9040882a2d3e56aa0c25bc61e404a 100644
--- a/src/cmd/build.rs
+++ b/src/cmd/build.rs
@@ -14,10 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with ink!. If not, see .
-use std::path::PathBuf;
+use std::{
+ fs::metadata,
+ io::{self, Write},
+ path::PathBuf,
+ process::Command,
+};
use anyhow::{Context, Result};
use cargo_metadata::MetadataCommand;
+use colored::Colorize;
use parity_wasm::elements::{External, MemoryType, Module, Section};
/// This is the maximum number of pages available for a contract to allocate.
@@ -25,6 +31,7 @@ const MAX_MEMORY_PAGES: u32 = 16;
/// Relevant metadata obtained from Cargo.toml.
pub struct CrateMetadata {
+ package_name: String,
original_wasm: PathBuf,
pub dest_wasm: PathBuf,
}
@@ -62,10 +69,11 @@ pub fn collect_crate_metadata(working_dir: Option<&PathBuf>) -> Result Result<()> {
Ok(())
}
+/// Attempts to perform optional wasm optimization using `wasm-opt`.
+///
+/// The intention is to reduce the size of bloated wasm binaries as a result of missing
+/// optimizations (or bugs?) between Rust and Wasm.
+///
+/// This step depends on the `wasm-opt` tool being installed. If it is not the build will still
+/// succeed, and the user will be encouraged to install it for further optimizations.
+fn optimize_wasm(crate_metadata: &CrateMetadata) -> Result<()> {
+ // check `wasm-opt` installed
+ if which::which("wasm-opt").is_err() {
+ println!(
+ "{}",
+ "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()
+ );
+ return Ok(());
+ }
+
+ let mut optimized = crate_metadata.dest_wasm.clone();
+ optimized.set_file_name(format!("{}-opt.wasm", crate_metadata.package_name));
+
+ 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");
+ }
+
+ let original_size = metadata(&crate_metadata.dest_wasm)?.len() / 1000;
+ let optimized_size = metadata(&optimized)?.len() / 1000;
+ println!(
+ " Original wasm size: {}K, Optimized: {}K",
+ original_size, optimized_size
+ );
+
+ // overwrite existing destination wasm file with the optimised version
+ std::fs::rename(&optimized, &crate_metadata.dest_wasm)?;
+ Ok(())
+}
+
/// Executes build of the smart-contract which produces a wasm binary that is ready for deploying.
///
/// It does so by invoking build by cargo and then post processing the final binary.
pub(crate) fn execute_build(working_dir: Option<&PathBuf>) -> Result {
- println!(" [1/3] Collecting crate metadata");
+ println!(
+ " {} {}",
+ "[1/4]".bold(),
+ "Collecting crate metadata".bright_green().bold()
+ );
let crate_metadata = collect_crate_metadata(working_dir)?;
- println!(" [2/3] Building cargo project");
+ println!(
+ " {} {}",
+ "[2/4]".bold(),
+ "Building cargo project".bright_green().bold()
+ );
build_cargo_project(working_dir)?;
- println!(" [3/3] Post processing wasm file");
+ println!(
+ " {} {}",
+ "[3/4]".bold(),
+ "Post processing wasm file".bright_green().bold()
+ );
post_process_wasm(&crate_metadata)?;
+ println!(
+ " {} {}",
+ "[4/4]".bold(),
+ "Optimizing wasm file".bright_green().bold()
+ );
+ optimize_wasm(&crate_metadata)?;
Ok(format!(
- "Your contract is ready.\nYou can find it here:\n{}",
- crate_metadata.dest_wasm.display()
+ "\nYour contract is ready. You can find it here:\n{}",
+ crate_metadata.dest_wasm.display().to_string().bold()
))
}