ci: wai-quantum's byte-pinning tests on nine more instruction sets #248

Merged
dcharlot merged 3 commits from wai/quantum-processors-ci into main 2026-10-14 11:50:38 -04:00

View file

@ -0,0 +1,141 @@
name: wai-quantum on every processor
# The crate promises the same bits on every processor. Native legs run elsewhere
# (x86_64 Linux, aarch64 macOS, the arm64 Linux VM, wasm32, wasip2); this
# workflow runs the crate's byte-pinning tests under user-mode QEMU on the
# instruction sets no runner has, the big-endian ones among them:
#
# bit_identity 23 digests across every numeric layer, taken natively and
# confirmed under wasip2;
# frame_reference the noisy-Clifford fixtures written by an independent tool;
# the library the modules that pin exact bytes: the core and its corpora,
# the fabric and its certificates, the strict JSON reader,
# receipts, energy labels and the bill of materials.
#
# These are emulator results: they prove what each target's binary computes
# under QEMU, not what that silicon does. i686 is the exception: it runs
# directly on the x86_64 host in 32-bit mode, so that leg is silicon.
#
# Each leg's job container is that target's cross image (linker, sysroot and
# QEMU, the runner preset in its environment), pinned by digest, capped at
# 6 GiB: an uncapped emulated run once took the 15 GiB host down. The job
# installs the pinned Rust into the runner's persistent cache, builds in a
# target directory of its own there (a build script compiled in one image fails
# in another with an older glibc), and holds a host-wide lock, so one leg runs
# at a time across every run of this workflow.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches: [main]
paths:
- 'wai/wai-quantum/**'
- 'rust-toolchain.toml'
- '.github/workflows/wai-quantum-processors.yml'
pull_request:
paths:
- 'wai/wai-quantum/**'
- 'rust-toolchain.toml'
- '.github/workflows/wai-quantum-processors.yml'
jobs:
emulated:
name: emulated · ${{ matrix.target }}
runs-on: linux
timeout-minutes: 120
container:
image: ${{ matrix.image }}
options: --memory=6g --memory-swap=6g ${{ matrix.options }}
strategy:
fail-fast: false
max-parallel: 1
matrix:
include:
- target: s390x-unknown-linux-gnu
image: ghcr.io/cross-rs/s390x-unknown-linux-gnu@sha256:0d8edc92c39158abe211fddfc9617bf5b7865c2ae0f58873f9cf0c58bb315271
how: emulated, qemu-user
- target: sparc64-unknown-linux-gnu
image: ghcr.io/cross-rs/sparc64-unknown-linux-gnu@sha256:2d04e507ee8bbb1ba61d483d22cf5839a0f138678f71facb40a08a9dffecf316
how: emulated, qemu-user
- target: powerpc64-unknown-linux-gnu
image: ghcr.io/cross-rs/powerpc64-unknown-linux-gnu@sha256:db02ecb2429912a6e939cc3d5cfe00aa20d7423ff484980f1fbfee4a3f2683cf
how: emulated, qemu-user
- target: powerpc64le-unknown-linux-gnu
image: ghcr.io/cross-rs/powerpc64le-unknown-linux-gnu@sha256:de5114adcd786f6a41eb07379459aaae94de73670303e202ea3603d250c19091
how: emulated, qemu-user
- target: riscv64gc-unknown-linux-gnu
image: ghcr.io/cross-rs/riscv64gc-unknown-linux-gnu@sha256:67ee97dd4719390d299edfcf39f226360ccfb1539e08b078ec187d4848415794
how: emulated, qemu-user
# QEMU 5.1's 32-bit ARM guest grows the emulator's own memory with the
# guest's thread count: with all 20 host CPUs, bit_identity's threaded
# state-vector run took qemu-arm past 6 GiB (a 32-bit guest addresses at
# most 4 GiB, so the excess is the emulator's). Four CPUs keep it under
# 1 GiB and still take the threaded paths.
- target: armv7-unknown-linux-gnueabihf
image: ghcr.io/cross-rs/armv7-unknown-linux-gnueabihf@sha256:4a08bebb60f08d52c1885b643a768f163c7318c05f91cf119f6c02855ea52699
options: --cpuset-cpus=0-3
how: emulated, qemu-user
# Runs directly on the x86_64 host in 32-bit mode.
- target: i686-unknown-linux-gnu
image: ghcr.io/cross-rs/i686-unknown-linux-gnu@sha256:2647400f884dd399a3ce6f6d918fec0776d43e73f471f52e310cbe664ac1671f
how: silicon, x86_64 host in 32-bit mode
- target: aarch64-unknown-linux-gnu
image: ghcr.io/cross-rs/aarch64-unknown-linux-gnu@sha256:7f8308a8734d9fcd2ebbe9a3e4bdea74af293f0799d80c3cc341e340cda49a4c
how: emulated, qemu-user
# cross 0.2.5 has no LoongArch image; this is cross's development image.
- target: loongarch64-unknown-linux-gnu
image: ghcr.io/cross-rs/loongarch64-unknown-linux-gnu@sha256:8968bd3b2c3b7b6d73c48e10faa605e14b40ce0080579a06402ea9fdfbc2a5c0
how: emulated, qemu-user
steps:
- name: Fetch the source
shell: bash
run: |
set -euo pipefail
want="${{ github.event.pull_request.head.sha || github.sha }}"
# The commit itself, not the ref: a later commit on the ref that this
# workflow's paths do not match would otherwise be tested instead. The
# archive carries its commit id, checked before anything is built.
rm -rf src src.tar.gz src.tar && mkdir src
curl -sSf -o src.tar.gz "http://100.64.224.0:3400/Transaction-Science/open-standards/archive/$want.tar.gz"
# Decompressed to a file, not a pipe: get-tar-commit-id stops reading at the
# header, and the writer's broken pipe would fail the step under pipefail.
gzip -dc src.tar.gz > src.tar
got="$(git get-tar-commit-id < src.tar)"
[ "$got" = "$want" ] || { echo "::error::the archive is of $got, not $want"; exit 1; }
tar -xf src.tar -C src --strip-components=1
rm src.tar.gz src.tar
- name: The byte-pinning tests
shell: bash
working-directory: src/wai/wai-quantum
run: |
set -euo pipefail
t="${{ matrix.target }}"
cache=/ci-cache/wai-quantum-processors
mkdir -p "$cache"
# One leg at a time on this host, across every run of this workflow: the
# emulated tests are heavy, and the toolchain cache is shared.
exec 9>"$cache/.lock"
flock 9
export RUSTUP_HOME="$cache/rustup" CARGO_HOME="$cache/cargo"
export PATH="$CARGO_HOME/bin:$PATH"
if ! command -v rustup >/dev/null; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal --default-toolchain none
fi
rustup toolchain install
rustup target add "$t"
export CARGO_TARGET_DIR="$cache/target/$t"
logs="$(mktemp -d)"
run() {
local name="$1"; shift
timeout 2700 cargo test --locked --release -j 6 --target "$t" --features full "$@" 2>&1 | tee "$logs/$name.log"
}
run bit_identity --test bit_identity
grep -qE '^test result: ok\. 23 passed; 0 failed' "$logs/bit_identity.log" || { echo "::error::$t: the 23 bit-identity digests did not all pass"; exit 1; }
run frame --test frame_reference
grep -qE '^test result: ok\. 2 passed; 0 failed' "$logs/frame.log" || { echo "::error::$t: the fixtures did not pass"; exit 1; }
run lib --lib -- quantum:: quantum_fabric:: ijson:: quantum_receipt quantum_energy quantum_qbom merkle
grep -qE '^test result: ok\. [1-9][0-9]+ passed; 0 failed' "$logs/lib.log" || { echo "::error::$t: the byte-pinning library tests did not pass"; exit 1; }
echo "processor: $t (${{ matrix.how }}) bit_identity 23/23, fixtures 2/2, $(grep -E '^test result' "$logs/lib.log" | tail -1)"