diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84e325d..0602cab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,3 +115,11 @@ jobs: cache-on-failure: true - name: cargo check --target wasm32v1-none (contracts) run: cargo check ${{ env.CONTRACTS }} --target wasm32v1-none + - name: cargo build --release (milestonex-campaign) + # cargo check above only type-checks; it does not run codegen/linking + # and so never actually produces (or validates) the deployable + # milestonex_campaign.wasm binary. Build it for real here so the size + # check below is checking a real artifact, not assuming one exists. + run: cargo build -p milestonex-campaign --target wasm32v1-none --release + - name: Verify campaign WASM artifact exists and is under the 64 KiB Soroban ceiling (issue #43) + run: bash scripts/check-wasm-artifact.sh diff --git a/Makefile b/Makefile index 4b2410e..8030953 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ .PHONY: build build-wasm build-tools test fmt fmt-tools lint lint-tools lint-schema all-lint \ clean optimize help setup deploy-testnet deploy-sandbox sandbox-start \ - audit deny wire-test + audit deny wire-test check-wasm-size # Default target build: build-wasm build-tools @@ -22,6 +22,12 @@ build: build-wasm build-tools build-wasm: @echo "🔨 Building Soroban contract..." cargo build -p milestonex-core -p milestonex-campaign -p milestonex-token-bridge -p milestonex-common --target wasm32v1-none --release + @test -f target/wasm32v1-none/release/milestonex_campaign.wasm || { \ + echo "❌ milestonex_campaign.wasm was not produced by the build above."; \ + echo " Check that milestonex-campaign is still listed on the cargo build line"; \ + echo " and that its [lib] crate-type still includes \"cdylib\" (see issue #43)."; \ + exit 1; \ + } @echo "✅ WASM contracts built successfully" # Build CLI tools @@ -164,8 +170,15 @@ optimize: build after=$$(wc -c < "$$wasm"); \ echo " $$(basename $$wasm): $${before}B -> $${after}B"; \ done + @$(MAKE) check-wasm-size @echo "✅ Optimization complete" +# Regression check (issue #43): verify milestonex_campaign.wasm — the binary +# deploy tooling ships — exists and is under the Soroban 64 KiB hosted-contract +# ceiling. +check-wasm-size: + @bash scripts/check-wasm-artifact.sh + # Show help help: @echo "Available commands:" @@ -185,6 +198,7 @@ help: @echo " make deploy-sandbox - Deploy contract to local sandbox" @echo " make deploy-testnet - Deploy contract to Stellar testnet" @echo " make optimize - Optimize WASM with wasm-opt -Oz" + @echo " make check-wasm-size - Verify milestonex_campaign.wasm exists and is < 64 KiB (issue #43)" @echo " make audit - Run cargo-audit for vulnerability scanning" @echo " make deny - Check license compliance with cargo-deny" @echo " make help - Show this help message" diff --git a/scripts/check-wasm-artifact.sh b/scripts/check-wasm-artifact.sh new file mode 100644 index 0000000..cdb09b0 --- /dev/null +++ b/scripts/check-wasm-artifact.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# scripts/check-wasm-artifact.sh — Regression check for issue #43. +# +# Verifies that the canonical milestonex_campaign.wasm binary is actually +# produced by `make build-wasm` and stays under the 64 KiB Soroban ceiling +# for hosted contracts. Guards against `cargo build` silently succeeding +# while only producing the legacy milestonex_core.wasm (e.g. if a future +# change drops `-p milestonex-campaign` from the Makefile's build-wasm +# target). +# +# Usage: +# bash scripts/check-wasm-artifact.sh +# +# Run after `make build-wasm` (raw build) or `make optimize` (wasm-opt'd +# build — the artifact deploy tooling actually ships). + +set -euo pipefail + +WASM_PATH="target/wasm32v1-none/release/milestonex_campaign.wasm" +SIZE_CAP_BYTES=65536 + +if [ ! -f "$WASM_PATH" ]; then + echo "❌ $WASM_PATH not found." + echo " Expected the canonical campaign contract to be produced by 'make build-wasm'." + echo " Run 'make build-wasm' first, or check that milestonex-campaign is still" + echo " listed in the Makefile's build-wasm target and its crate-type includes cdylib." + exit 1 +fi + +SIZE_BYTES=$(wc -c < "$WASM_PATH") + +if [ "$SIZE_BYTES" -ge "$SIZE_CAP_BYTES" ]; then + echo "❌ $WASM_PATH is ${SIZE_BYTES}B, which is >= the ${SIZE_CAP_BYTES}B (64 KiB)" + echo " Soroban ceiling for hosted contracts. Run 'make optimize' (wasm-opt -Oz)" + echo " before deploying, or investigate the size regression." + exit 1 +fi + +echo "✅ $WASM_PATH exists and is ${SIZE_BYTES}B (< ${SIZE_CAP_BYTES}B / 64 KiB)" diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 6e2911d..ba3caff 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash -# scripts/deploy.sh — Deploy MilestoneX core contract to a Soroban network. +# scripts/deploy.sh — Deploy the MilestoneX campaign contract to a Soroban +# network. milestonex-campaign is the canonical, actively-developed contract; +# milestonex-core is the legacy reference implementation and is not deployed +# by this script (see issue #43). # # Usage: # bash scripts/deploy.sh [testnet|sandbox|mainnet] @@ -44,8 +47,8 @@ case "$NETWORK" in esac # ── Paths ───────────────────────────────────────────────────────────────────── -WASM_PATH="target/wasm32v1-none/release/milestonex_core.wasm" -OPTIMIZED_WASM_PATH="target/wasm32v1-none/release/milestonex_core.wasm" +WASM_PATH="target/wasm32v1-none/release/milestonex_campaign.wasm" +OPTIMIZED_WASM_PATH="target/wasm32v1-none/release/milestonex_campaign.wasm" DEPLOYMENTS_DIR="deployments" DEPLOYMENT_FILE="${DEPLOYMENTS_DIR}/${NETWORK}.json"