Skip to content

refactor(testing): collapse the two placeholder-proof branches (#1160) #788

refactor(testing): collapse the two placeholder-proof branches (#1160)

refactor(testing): collapse the two placeholder-proof branches (#1160) #788

Workflow file for this run

name: Production Test Vectors
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: write
concurrency:
group: prod-vectors-latest
cancel-in-progress: true
jobs:
check:
name: Check key availability
runs-on: ubuntu-latest
outputs:
scheme-changed: ${{ steps.scheme-diff.outputs.changed }}
cache-hit: ${{ steps.key-cache.outputs.cache-hit }}
steps:
- name: Checkout leanSpec
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check if scheme changed
id: scheme-diff
run: |
if git diff HEAD~1 --name-only | grep -qE '^src/lean_spec/subspecs/(xmss|poseidon1)/'; then
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Check prod key cache
id: key-cache
uses: actions/cache/restore@v4
with:
path: /tmp/prod-keys-probe
key: prod-keys-${{ hashFiles('src/lean_spec/subspecs/xmss/**', 'src/lean_spec/subspecs/poseidon1/**') }}
lookup-only: true
keygen:
name: Generate keys
needs: check
if: needs.check.outputs.cache-hit != 'true' && needs.check.outputs.scheme-changed == 'true'
uses: ./.github/workflows/generate-keys.yml
secrets: inherit
fill:
name: Fill production test fixtures
needs: [check, keygen]
# Trick to run even when keygen was skipped, but not on failure or cancel.
if: always() && !failure() && !cancelled()
runs-on: macos-latest
steps:
- name: Checkout leanSpec
uses: actions/checkout@v4
- name: Set up Python 3.14
uses: actions/setup-python@v5
with:
python-version: "3.14"
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
cache-dependency-glob: "pyproject.toml"
- name: Install just
uses: taiki-e/install-action@v2
with:
tool: just
- name: Restore prod key cache
id: key-cache
uses: actions/cache/restore@v4
with:
path: packages/testing/src/consensus_testing/test_keys/prod_scheme
key: prod-keys-${{ hashFiles('src/lean_spec/subspecs/xmss/**', 'src/lean_spec/subspecs/poseidon1/**') }}
- name: Download keys
if: steps.key-cache.outputs.cache-hit != 'true'
run: uv run keys --download --scheme prod
- name: Save key cache
if: steps.key-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: packages/testing/src/consensus_testing/test_keys/prod_scheme
key: prod-keys-${{ hashFiles('src/lean_spec/subspecs/xmss/**', 'src/lean_spec/subspecs/poseidon1/**') }}
- name: Fill production test fixtures
env:
# Only the real_crypto smoke vectors run genuine production XMSS proofs.
# Each proof parallelizes internally with rayon, so few heavy tasks dominate the run.
# Two xdist workers overlap the heavy proofs and chew through the mocked backlog.
# Leaving rayon unpinned lets each proof spread across cores instead of one thread.
FILL_WORKERS: "2"
run: just fill-ci --scheme=prod
- name: Bundle keys with fixtures
run: |
mkdir -p fixtures/keys
cp -r packages/testing/src/consensus_testing/test_keys/prod_scheme fixtures/keys/
- name: Create reproducible fixture archive
run: |
python - <<'PY'
from __future__ import annotations
import gzip
import hashlib
import tarfile
from pathlib import Path
archive_path = Path("fixtures-prod-scheme.tar.gz")
checksum_path = Path("fixtures-prod-scheme.tar.gz.sha256")
source_directory = Path("fixtures")
fixed_modification_time = 1_577_836_800
if not source_directory.is_dir():
raise SystemExit("Expected fixtures/ to exist before archiving.")
consensus_fixture_paths = sorted(source_directory.glob("consensus/**/*.json"))
if not consensus_fixture_paths:
raise SystemExit("No consensus fixture JSON files were generated.")
source_paths = [source_directory, *sorted(source_directory.rglob("*"))]
with archive_path.open("wb") as archive_file_handle:
with gzip.GzipFile(
filename="",
mode="wb",
fileobj=archive_file_handle,
mtime=0,
) as gzip_file_handle:
with tarfile.open(
fileobj=gzip_file_handle,
mode="w",
format=tarfile.PAX_FORMAT,
) as tar_file_handle:
for source_path in source_paths:
tar_file_information = tar_file_handle.gettarinfo(
source_path,
arcname=source_path.as_posix(),
)
tar_file_information.uid = 0
tar_file_information.gid = 0
tar_file_information.uname = ""
tar_file_information.gname = ""
tar_file_information.mtime = fixed_modification_time
if tar_file_information.isfile():
with source_path.open("rb") as source_file_handle:
tar_file_handle.addfile(
tar_file_information,
source_file_handle,
)
else:
tar_file_handle.addfile(tar_file_information)
archive_digest = hashlib.sha256(archive_path.read_bytes()).hexdigest()
checksum_path.write_text(f"{archive_digest} {archive_path.name}\n")
with tarfile.open(archive_path, "r:gz") as archive_file_handle:
archived_consensus_fixtures = [
archived_member.name
for archived_member in archive_file_handle.getmembers()
if archived_member.name.startswith("fixtures/consensus/")
and archived_member.name.endswith(".json")
]
if not archived_consensus_fixtures:
raise SystemExit("Archive does not contain generated consensus fixtures.")
PY
- name: Upload fixture archive
uses: actions/upload-artifact@v4
with:
name: fixtures-prod-scheme
path: |
fixtures-prod-scheme.tar.gz
fixtures-prod-scheme.tar.gz.sha256
if-no-files-found: error
- name: Publish latest release
run: |
gh release delete latest --cleanup-tag --yes || true
gh release create latest \
fixtures-prod-scheme.tar.gz \
fixtures-prod-scheme.tar.gz.sha256 \
--target "${{ github.sha }}" \
--title "Latest production fixtures" \
--notes "Auto-generated from leanSpec@${{ github.sha }}"
env:
GH_TOKEN: ${{ github.token }}