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 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
Cargo.lock
sWhile 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 with respect to feature configuration. Running a command on all workspace members is incomplete 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.
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.:
Even when filtering out the package results, you cannot differentiate between contracts and other cargo packages:
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.
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:
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:
In this case you don't even need to care where the target folder is.
Cargo.lock
sCargo.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.