From 94f14ae305a00beee55e310e1fe234be273045ef Mon Sep 17 00:00:00 2001 From: r4bbit <445106+0x-r4bbit@users.noreply.github.com> Date: Thu, 9 Apr 2026 19:29:03 +0200 Subject: [PATCH] ci: add IDL freshness check and consolidate artifacts Move IDL files to artifacts/ and add a convention-based CI check that discovers all programs via */methods/guest/src/bin/*.rs and fails if any program is missing its IDL or has one that is out of date. --- .github/workflows/ci.yml | 45 +++++++++++++++++++++ CLAUDE.md | 17 +++++++- Cargo.lock | 62 ++++++++++++++++++++++++----- Cargo.toml | 1 + README.md | 22 +++++++--- {amm => artifacts}/amm-idl.json | 0 {ata => artifacts}/ata-idl.json | 0 {token => artifacts}/token-idl.json | 0 tools/idl-gen/Cargo.toml | 14 +++++++ tools/idl-gen/src/main.rs | 19 +++++++++ 10 files changed, 163 insertions(+), 17 deletions(-) rename {amm => artifacts}/amm-idl.json (100%) rename {ata => artifacts}/ata-idl.json (100%) rename {token => artifacts}/token-idl.json (100%) create mode 100644 tools/idl-gen/Cargo.toml create mode 100644 tools/idl-gen/src/main.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52078f1..e3b0b22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,3 +116,48 @@ jobs: run: cargo test -p integration_tests env: RISC0_DEV_MODE: 1 + + check-idl: + name: Check IDL + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: "1.94.0" + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Build idl-gen + run: cargo build -p idl-gen --release + + - name: Check IDL files are present and up to date + run: | + set -e + failed=0 + for src in $(find . -path '*/methods/guest/src/bin/*.rs' | sort); do + program=$(basename "$src" .rs) + idl="artifacts/${program}-idl.json" + if [ ! -f "$idl" ]; then + echo "Missing IDL for '${program}' — generate with: cargo run -p idl-gen -- ${src#./} > ${idl}" + failed=1 + continue + fi + ./target/release/idl-gen "$src" > /tmp/${program}-idl.json + if ! diff "$idl" /tmp/${program}-idl.json > /dev/null 2>&1; then + echo "IDL for '${program}' is out of date — regenerate with: cargo run -p idl-gen -- ${src#./} > ${idl}" + failed=1 + fi + done + exit $failed diff --git a/CLAUDE.md b/CLAUDE.md index 2b5ffcd..992296f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,11 +35,24 @@ Built binaries output to: `/methods/guest/target/riscv32im-risc0-zkvm-e ## IDL Generation +Using the `idl-gen` crate (no external toolchain required — this is what CI uses): + ```bash -spel generate-idl token/methods/guest/src/bin/token.rs > token/token-idl.json -spel generate-idl amm/methods/guest/src/bin/amm.rs > amm/amm-idl.json +cargo run -p idl-gen -- token/methods/guest/src/bin/token.rs > artifacts/token-idl.json +cargo run -p idl-gen -- amm/methods/guest/src/bin/amm.rs > artifacts/amm-idl.json +cargo run -p idl-gen -- ata/methods/guest/src/bin/ata.rs > artifacts/ata-idl.json ``` +Alternatively, using the `spel` CLI (requires the SPEL toolchain): + +```bash +spel generate-idl token/methods/guest/src/bin/token.rs > artifacts/token-idl.json +spel generate-idl amm/methods/guest/src/bin/amm.rs > artifacts/amm-idl.json +spel generate-idl ata/methods/guest/src/bin/ata.rs > artifacts/ata-idl.json +``` + +Generated IDL files live in `artifacts/`. CI checks that every program under `*/methods/guest/src/bin/` has a corresponding `artifacts/-idl.json` that matches the source. + ## Deployment `wallet` and `spel` are CLI tools that ship with the [SPEL](https://github.com/logos-co/spel.git) toolchain. `wallet` requires `NSSA_WALLET_HOME_DIR` to point to a directory containing the wallet config. diff --git a/Cargo.lock b/Cargo.lock index c5cf3d1..cc0c9f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -433,7 +433,7 @@ dependencies = [ "maybe-async", "reqwest", "serde", - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -539,7 +539,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -604,7 +604,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -1510,6 +1510,14 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idl-gen" +version = "0.1.0" +dependencies = [ + "serde_json", + "spel-framework-core", +] + [[package]] name = "idna" version = "1.1.0" @@ -1828,7 +1836,7 @@ dependencies = [ "serde", "serde_with", "sha2", - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -1845,7 +1853,7 @@ dependencies = [ "risc0-zkvm", "serde", "serde_with", - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -2133,7 +2141,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -2154,7 +2162,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -2271,7 +2279,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -2744,7 +2752,7 @@ dependencies = [ "sha2", "strum", "tempfile", - "thiserror", + "thiserror 2.0.18", "toml", "yaml-rust2", ] @@ -2952,6 +2960,20 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "spel-framework-core" +version = "0.1.0" +source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6" +dependencies = [ + "borsh", + "nssa_core", + "serde", + "serde_json", + "sha2", + "syn 2.0.117", + "thiserror 1.0.69", +] + [[package]] name = "spin" version = "0.9.8" @@ -3072,13 +3094,33 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a42f579..a5c2f2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "ata", "ata/methods", "integration_tests", + "tools/idl-gen", ] exclude = [ "token/methods/guest", diff --git a/README.md b/README.md index 794fa52..607ae21 100644 --- a/README.md +++ b/README.md @@ -76,17 +76,29 @@ spel inspect The IDL describes the program's instructions and can be used to interact with a deployed program. +**Using the `idl-gen` crate** (no external toolchain required — this is what CI uses): + ```bash -# Example -spel generate-idl token/methods/guest/src/bin/token.rs > token/token-idl.json -spel generate-idl amm/methods/guest/src/bin/amm.rs > amm/amm-idl.json +cargo run -p idl-gen -- token/methods/guest/src/bin/token.rs > artifacts/token-idl.json +cargo run -p idl-gen -- amm/methods/guest/src/bin/amm.rs > artifacts/amm-idl.json +cargo run -p idl-gen -- ata/methods/guest/src/bin/ata.rs > artifacts/ata-idl.json ``` +**Using the `spel` CLI** (requires the SPEL toolchain): + +```bash +spel generate-idl token/methods/guest/src/bin/token.rs > artifacts/token-idl.json +spel generate-idl amm/methods/guest/src/bin/amm.rs > artifacts/amm-idl.json +spel generate-idl ata/methods/guest/src/bin/ata.rs > artifacts/ata-idl.json +``` + +Generated IDL files are committed under `artifacts/`. CI will fail if a program's IDL is missing or out of date. + ### Invoke Instructions Use `spel --idl [ARGS...]` to call a deployed program instruction: ```bash -spel --idl token/token-idl.json [args...] -spel --idl amm/amm-idl.json [args...] +spel --idl artifacts/token-idl.json [args...] +spel --idl artifacts/amm-idl.json [args...] ``` diff --git a/amm/amm-idl.json b/artifacts/amm-idl.json similarity index 100% rename from amm/amm-idl.json rename to artifacts/amm-idl.json diff --git a/ata/ata-idl.json b/artifacts/ata-idl.json similarity index 100% rename from ata/ata-idl.json rename to artifacts/ata-idl.json diff --git a/token/token-idl.json b/artifacts/token-idl.json similarity index 100% rename from token/token-idl.json rename to artifacts/token-idl.json diff --git a/tools/idl-gen/Cargo.toml b/tools/idl-gen/Cargo.toml new file mode 100644 index 0000000..dd05892 --- /dev/null +++ b/tools/idl-gen/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "idl-gen" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "idl-gen" +path = "src/main.rs" + +[dependencies] +spel-framework-core = { git = "https://github.com/logos-co/spel.git", rev = "57201f64b4542bb3f592bc9a0aa654c47aa908a6", features = [ + "idl-gen", +] } +serde_json = "1.0" diff --git a/tools/idl-gen/src/main.rs b/tools/idl-gen/src/main.rs new file mode 100644 index 0000000..f1abee5 --- /dev/null +++ b/tools/idl-gen/src/main.rs @@ -0,0 +1,19 @@ +use std::{path::PathBuf, process}; + +fn main() { + let path: PathBuf = match std::env::args().nth(1) { + Some(p) => PathBuf::from(p), + None => { + eprintln!("Usage: idl-gen "); + process::exit(1); + } + }; + + match spel_framework_core::idl_gen::generate_idl_from_file(&path) { + Ok(idl) => println!("{}", serde_json::to_string_pretty(&idl).unwrap()), + Err(e) => { + eprintln!("Error: {e}"); + process::exit(1); + } + } +}