# Next generation rust-optimizer Up until the 0.9 series, rust-optimizer was simple. It got exactly one simple cargo project and built it into a single `contract.wasm` and `hash.txt`. This contract is single crate that can be published to crates.io or any other package repository to allow reproducible builds. The build result was always exactly one file found in `target/wasm32-unknown-unknown/release/*.wasm`. With the rise of [workspace](https://doc.rust-lang.org/cargo/reference/workspaces.html) based repositories in cosmwasm-plus, we get a better development experience when working with multiple contracts and their dependencies. At the same time, the build and verification process gets more complicated. Some of the problems are 1. Cargo has not-that-great support for working with workspaces 2. Hard to find the contract dirs 3. Hard to find build results 4. No contract-spefific `Cargo.lock`s ## Cargo has not-that-great support for working with workspaces While Cargo's workspaces are nice to avoid re-compiling dependencies multiple times, its support for working with them is pretty much insufficient for our use case. While you can run simple things like `cargo fmt --all` and `cargo test --all` to perform an action in all workspace members, `cargo build` [leads to unexpected results](https://github.com/CosmWasm/rust-optimizer/issues/21) with respect to feature configuration. Running a command on all workspace members is [incomplete](https://github.com/rust-lang/cargo/issues/2878) and inconsistent (`cargo fmt --all` vs. `cargo build --workspace`). Cargo misses a way to iterate over workspace members and execute a command there, similar to `lerna exec -- custom_command_here "\$LERNA_PACKAGE_NAME"`. As a consequence, we need to re-implement workspace member detection if we want to do that. ## Hard to find the contract dirs A naive way to find all contract repositories is to look for `Cargo.toml`s, which in practice is not trivial since they can appear in unexpected locations, e.g.: ``` $ cd cosmwasm-examples $ find . -name Cargo.toml ./erc20/Cargo.toml ./voting/Cargo.toml ./nameservice/Cargo.toml ./nameservice/target/package/cw-nameservice-0.5.1/Cargo.toml ./nameservice/target/package/cw-nameservice-0.5.0/Cargo.toml ./nameservice/target/package/cw-nameservice-0.5.2/Cargo.toml ./nameservice/target/package/cw-nameservice-0.3.1/Cargo.toml ./nameservice/target/package/cw-nameservice-0.4.0/Cargo.toml ./mask/Cargo.toml ./mask/target/package/cw-mask-0.3.0/Cargo.toml ./mask/target/package/cw-mask-0.3.1/Cargo.toml ./mask/target/package/cw-mask-0.1.1/Cargo.toml ./mask/target/package/cw-mask-0.3.2/Cargo.toml ./mask/target/package/cw-mask-0.2.0/Cargo.toml ./escrow/Cargo.toml ./escrow/target/package/cw-escrow-0.5.0/Cargo.toml ./escrow/target/package/cw-escrow-0.5.1/Cargo.toml ./escrow/target/package/cw-escrow-0.3.1/Cargo.toml ./escrow/target/package/cw-escrow-0.5.2/Cargo.toml ``` Even when filtering out the package results, you cannot differentiate between contracts and other cargo packages: ``` $ cd cosmwasm-plus $ find . -name Cargo.toml ./Cargo.toml ./contracts/cw20-base/Cargo.toml ./contracts/cw20-escrow/Cargo.toml ./contracts/cw1-whitelist/Cargo.toml ./contracts/cw1-subkeys/Cargo.toml ./packages/cw1/Cargo.toml ./packages/cw20/Cargo.toml ./packages/cw2/Cargo.toml ``` A more reliable way would be to parse `workspace.members` from the root `Cargo.toml` and loop over them. However, this still does not tell you which package is a contract and which is not. Also if we start parsing tomls, we should move from bash to a proper scripting language with a rich standard library like Python. ## Hard to find build results With workspaces, the build results will be somewhere in the repo root's `target/wasm32-unknown-unknown/release`, which is different from simple projects where `./target` lives next to `Cargo.toml`. Supporting both targets folders at the same time is hard: ``` # find the target directories and build results, optimize and write to artifacts while IFS= read -r -d '' target_dir; do for wasm in "$target_dir"/release/*.wasm; do echo "Found build result $wasm" name=$(basename "$wasm") wasm-opt -Os "$wasm" -o "$artifacts_dir/$name" echo "Created artifact $name" done done < <(find . -name wasm32-unknown-unknown -type d -print0) ``` Also having multiple build results can be a problem, especially when caching comes in. Then you never know if all the `*.wasm` files found really belong to the current build. The problem is the _build and collect_ approach, where the build result is not connected to the execution of the build. This problem can probably be solved by using the (night-only) `--out-dir` flag: ``` $ cargo +nightly -Z unstable-options build --out-dir ./contract_artifacts $ ls ./contract_artifacts cw1_whitelist.wasm libcw1_whitelist.rlib ``` In this case you don't even need to care where the target folder is. ## No contract-spefific `Cargo.lock`s `Cargo.lock` is needed for reproducible builds. Without it, a rebuild of a contract can fetch a different version of a dependency and create a different result. When working with a workspace repo, it is unclear what a single contract's source code is. It turns out that is cannot be the sub-folder of a certain package if there is no `Cargo.lock` included. As a consequence, every single contract must consider the entire workspace as its source code. This makes source code large and harder to review.