From 54454927c0ed745a074539a07baf668311ac22cd Mon Sep 17 00:00:00 2001 From: Collins Ikechukwu Date: Tue, 18 Aug 2026 01:16:50 +0100 Subject: [PATCH] fix(ci): assert the built version instead of pinning it to a fixture hash The SDK 27 compatibility gate has been red on testnet since 30 July. With VERIFY_SDK27_BUILD=1 it asserted that a freshly built boundless_events.wasm hashes to the pinned events-1.5.0-sdk27.wasm fixture. contractmeta! is embedded in the wasm, so that assertion stopped being satisfiable the moment the runtime version moved to 1.6.0, and would break again on every bump after. Re-pinning the hash would only defer it to the next release. What the pin was really guarding is that a shipped artifact declares the version its source claims, and contractmeta! and INITIAL_VERSION are independent declarations that have drifted before: fixtures/events-1.3.0-sdk23.wasm reports contractmeta 1.2.0 against a 1.3.0 runtime, which the manifest records as a known defect. The gate now compares the built wasm's contractmeta against INITIAL_VERSION for both contracts, which catches that class and survives version bumps. Verified by reverting events contractmeta to 1.5.0 against a 1.6.0 source: the gate fails with both values named. Fixture integrity, snapshot provenance and the compatibility suite itself are unchanged, and the fixture hashes stay pinned byte-for-byte. --- .../compatibility/fixtures/manifest.json | 3 +- scripts/test-sdk27-compat.sh | 48 +++++++++++++++---- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/contracts/compatibility/fixtures/manifest.json b/contracts/compatibility/fixtures/manifest.json index 0c36476..67ac592 100644 --- a/contracts/compatibility/fixtures/manifest.json +++ b/contracts/compatibility/fixtures/manifest.json @@ -47,7 +47,8 @@ "soroban_sdk": "27.0.0", "protocol": 27, "runtime_version": "1.5.0", - "contractmeta_version": "1.5.0" + "contractmeta_version": "1.5.0", + "note": "Historical SDK 27 fixture, kept byte-for-byte as the 'new' side of the storage-compatibility tests. It is not expected to match a current build: contractmeta is embedded in the wasm, so every runtime version bump changes the hash. The build gate asserts contractmeta matches INITIAL_VERSION instead." }, { "file": "profile-1.2.0-sdk27.wasm", diff --git a/scripts/test-sdk27-compat.sh b/scripts/test-sdk27-compat.sh index 4f2194a..1a1d00f 100755 --- a/scripts/test-sdk27-compat.sh +++ b/scripts/test-sdk27-compat.sh @@ -24,6 +24,33 @@ check_hash() { fi } +meta_version() { + stellar -q contract info meta --wasm "$1" --output json \ + | jq -er '.[] | select(.sc_meta_v0.key == "version") | .sc_meta_v0.val' +} + +# The version the source claims, from `pub const INITIAL_VERSION`. +source_version() { + local file="$1" version + version="$(sed -n 's/^pub const INITIAL_VERSION: &str = "\(.*\)";$/\1/p' "$file")" + if [ -z "$version" ]; then + echo "no INITIAL_VERSION found in $file" >&2 + exit 1 + fi + printf '%s\n' "$version" +} + +check_declared_version() { + local wasm="$1" expected="$2" actual + actual="$(meta_version "$wasm")" + if [ "$actual" != "$expected" ]; then + echo "declared version mismatch for $wasm" >&2 + echo " contractmeta: $actual" >&2 + echo " INITIAL_VERSION in source: $expected" >&2 + exit 1 + fi +} + rustc --version | grep -q '^rustc 1\.93\.0 ' || { echo "Rust 1.93.0 is required" >&2 exit 1 @@ -38,10 +65,7 @@ while IFS=$'\t' read -r file expected; do done < <(jq -r '.wasm[] | [.file, .sha256] | @tsv' "$MANIFEST") while IFS=$'\t' read -r file expected; do - actual="$( - stellar -q contract info meta --wasm "$FIXTURES/$file" --output json \ - | jq -er '.[] | select(.sc_meta_v0.key == "version") | .sc_meta_v0.val' - )" + actual="$(meta_version "$FIXTURES/$file")" if [ "$actual" != "$expected" ]; then echo "contractmeta version mismatch for $file" >&2 echo "expected: $expected" >&2 @@ -101,10 +125,18 @@ case "$verify_build" in exit 1 } - events_hash="$(jq -r '.wasm[] | select(.file == "events-1.5.0-sdk27.wasm") | .sha256' "$MANIFEST")" - profile_hash="$(jq -r '.wasm[] | select(.file == "profile-1.2.0-sdk27.wasm") | .sha256' "$MANIFEST")" - check_hash "$EVENTS_WASM" "$events_hash" - check_hash "$PROFILE_WASM" "$profile_hash" + # Assert the built artifact declares the version its source claims, + # rather than pinning it to a fixture hash. contractmeta! is embedded + # in the wasm, so a fixture pin is unsatisfiable the moment the runtime + # version moves past that fixture's — it went red on the 1.6.0 bump and + # would go red on every bump after. + # + # This catches the failure the pin was really guarding against. The two + # version declarations are independent and have drifted before: + # fixtures/events-1.3.0-sdk23.wasm reports contractmeta 1.2.0 against a + # 1.3.0 runtime, recorded in the manifest note for that entry. + check_declared_version "$EVENTS_WASM" "$(source_version "$ROOT/contracts/events/src/admin.rs")" + check_declared_version "$PROFILE_WASM" "$(source_version "$ROOT/contracts/profile/src/admin.rs")" ;; *) echo "VERIFY_SDK27_BUILD must be 0 or 1" >&2