Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .github/workflows/test-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20.20"
node-version: "24.10"

- name: Enable Corepack
run: |
Expand Down Expand Up @@ -64,9 +64,10 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
# Pin >=20.18 — @solana/codecs-numbers (via @solana/web3.js) rejects older 20.x.
# act's amd64 toolcache ships 20.11 unless a specific version is requested.
node-version: "20.20"
# Pin 24.10 — MagicsVM's @solana/errors@8.3.0 pulls commander@15,
# which requires Node >=22.12. Example READMEs document 24.10.0.
# Pin a specific version so act's toolcache does not pick an older Node.
node-version: "24.10"

- name: Enable Corepack
run: |
Expand Down Expand Up @@ -101,8 +102,12 @@ jobs:
echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH

- name: Install Anchor
# Prebuilt release binary: building anchor-cli from source took ~5 min per job.
run: |
cargo install --git https://github.com/solana-foundation/anchor --tag v1.0.2 anchor-cli
curl -sSfL -o /tmp/anchor \
https://github.com/solana-foundation/anchor/releases/download/v1.0.2/anchor-1.0.2-x86_64-unknown-linux-gnu
sudo install -m 755 /tmp/anchor /usr/local/bin/anchor
anchor --version

- name: Install MagicBlock Ephemeral Validator
run: |
Expand Down
133 changes: 133 additions & 0 deletions .github/workflows/test-magicsvm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
name: Test MagicSVM

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
# Emit MagicSVM example names as JSON so the test job can fan out one runner
# per example. Source of truth: MAGICSVM_PROJECTS in scripts/projects.sh.
list-examples:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- id: set
run: |
# shellcheck source=scripts/projects.sh
. scripts/projects.sh
echo "matrix=$(magicsvm_projects_json)" >> "$GITHUB_OUTPUT"

# In-process MagicSVM tests: no local validators, VRF oracle, or TEE stack.
# The tests themselves take seconds; the job time is toolchain install plus
# `anchor build`, so Anchor comes from its prebuilt binary and the program and
# Rust-suite build outputs are cached between runs.
test-magicsvm:
needs: list-examples
name: magicsvm (${{ matrix.example }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
example: ${{ fromJSON(needs.list-examples.outputs.matrix) }}
env:
# One native target dir for every example's tests-magicsvm-rs suite: they share
# the same magicsvm/solana dependency graph, so one cache serves all of them.
MAGICSVM_RS_TARGET_DIR: ${{ github.workspace }}/.magicsvm-rs-target
steps:
- uses: actions/checkout@v4

- name: Resolve example directory
id: dir
run: |
# shellcheck source=scripts/projects.sh
. scripts/projects.sh
echo "dir=$(project_dir "${{ matrix.example }}")" >> "$GITHUB_OUTPUT"

# Node only runs the `yarn build` / `yarn test` scripts: the suites are Rust, so
# there are no node_modules to install or cache.
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24.10"

- name: Enable Corepack
run: |
corepack enable
corepack prepare yarn@1.22.19 --activate
corepack prepare yarn@1.22.22 --activate

- name: Setup Rust 1.89 (Anchor builds)
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.89.0"

# The MagicSVM suites run on `cargo +stable` (MagicSVM does not build on 1.89),
# and anchor idl build also invokes the host `stable` toolchain.
- name: Setup stable Rust (MagicSVM suites, Anchor IDL)
id: stable
run: |
rustup toolchain install stable --profile minimal
rustup default 1.89.0
echo "rustc=$(rustc +stable --version | cut -d' ' -f2)" >> "$GITHUB_OUTPUT"

- name: Install native dependencies
run: |
sudo apt-get update
sudo apt-get install -y libudev-dev pkg-config

- name: Install Solana
run: |
sh -c "$(curl -sSfL https://release.anza.xyz/v3.1.9/install)"
echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH

- name: Install Anchor
# Prebuilt release binary: building anchor-cli from source took ~5 min per job.
run: |
curl -sSfL -o /tmp/anchor \
https://github.com/solana-foundation/anchor/releases/download/v1.0.2/anchor-1.0.2-x86_64-unknown-linux-gnu
sudo install -m 755 /tmp/anchor /usr/local/bin/anchor
anchor --version

# Program build cache (per example): the SBF toolchain download plus the
# example's target/ so `anchor build` / `cargo build-sbf` only recompiles the
# program crate itself.
- name: Cache program build
uses: actions/cache@v4
with:
path: |
~/.cache/solana
${{ steps.dir.outputs.dir }}/target
key: magicsvm-program-${{ matrix.example }}-${{ hashFiles(format('{0}/Cargo.lock', steps.dir.outputs.dir)) }}-${{ hashFiles(format('{0}/programs/**', steps.dir.outputs.dir), format('{0}/src/**', steps.dir.outputs.dir), format('{0}/Cargo.toml', steps.dir.outputs.dir)) }}
restore-keys: |
magicsvm-program-${{ matrix.example }}-${{ hashFiles(format('{0}/Cargo.lock', steps.dir.outputs.dir)) }}-
magicsvm-program-${{ matrix.example }}-

# Cargo registry plus the shared native target dir for the Rust MagicSVM suites. The key
# carries the stable rustc version: an exact-key hit is never re-saved, so without it a
# stable release would leave CI restoring stale artifacts and recompiling on every run.
- name: Cache Rust suite build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
${{ env.MAGICSVM_RS_TARGET_DIR }}
key: magicsvm-rs-${{ steps.stable.outputs.rustc }}-${{ hashFiles('**/tests-magicsvm-rs/Cargo.lock', 'test-utils/rust/Cargo.lock') }}-${{ matrix.example }}
restore-keys: |
magicsvm-rs-${{ steps.stable.outputs.rustc }}-${{ hashFiles('**/tests-magicsvm-rs/Cargo.lock', 'test-utils/rust/Cargo.lock') }}-
magicsvm-rs-${{ steps.stable.outputs.rustc }}-

- name: Test MagicSVM ${{ matrix.example }}
env:
EXACT_MATCH: "1"
run: bash scripts/test-magicsvm.sh "${{ matrix.example }}"
41 changes: 30 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,34 +297,53 @@ Deployed frontends for the examples that ship a UI.

## Testing

To run local tests for any example project, use the following steps:
Most examples test in-process with [MagicSVM](https://github.com/magicblock-labs/magicsvm): a base
layer and an Ephemeral Rollup in one process, no validators and no network.

1. **Install Dependencies (Local nodes + example directory):**
```bash
cd <example-directory>
yarn build
yarn test
```

Each example's suite is Rust, in `tests-magicsvm-rs/`; shared helpers are in `test-utils/rust`.
`yarn test` runs `cargo +stable test`, since MagicSVM needs a newer Rust than the 1.89 toolchain
used for program builds. To run every MagicSVM example from the repo root:

```bash
bash scripts/test-magicsvm.sh # all MagicSVM examples
bash scripts/test-magicsvm.sh spl-tokens # one example (substring match)
```

### Examples that still need local nodes

MagicSVM does not simulate scheduled tasks, the VRF oracle, or the private-permission flow yet, so
`crank-counter`, `gachapon-example`, `roll-dice` (Anchor and Pinocchio), `rewards-delegated-vrf`
and `sealed-auction` run against a local MagicBlock cluster instead:

1. **Install the local nodes and the example:**

```bash
npm install -g @magicblock-labs/ephemeral-validator@latest
cd <example-directory>
yarn install
```

2. **Setup local nodes:**
2. **Start the local nodes** (builds the example, boots the validators, holds them until a key press):

```bash
yarn setup
```

3. **Run Tests Locally:**
3. **Run the tests against them** in a second terminal:

```bash
yarn test:local
```

**Example:** To test the `pinocchio-roll-dice` example:

```bash
cd roll-dice/pinocchio
yarn build
yarn test:local
```
CI mirrors this split: `.github/workflows/test-magicsvm.yml` runs one MagicSVM job per example and
`.github/workflows/test-examples.yml` runs the validator-based examples. Both matrices come from
`scripts/projects.sh`.

### Local nodes

Expand Down
2 changes: 1 addition & 1 deletion binary-prediction/anchor/Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ program = "tests/fixtures/ephemeral_oracle.so"
upgradeable = false

[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/binary-prediction.ts"
test = "yarn test"
22 changes: 8 additions & 14 deletions binary-prediction/anchor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,17 @@ yarn
yarn build
```

This example runs against a local MagicBlock cluster: a base Solana validator, an Ephemeral Rollup,
and the Query Filtering Service. Start it in one terminal and leave it running:
Run the Rust test suite in `tests-magicsvm-rs/` in-process with [MagicSVM](https://github.com/magicblock-labs/magicsvm):

```bash
yarn setup
yarn test
```

Then, in a second terminal, run the lifecycle test:
MagicSVM simulates the base layer and the Ephemeral Rollup in one process: no validators, no
network. The suite runs prediction initialization, betting, settlement, and withdrawal with a
vendored session-keys program.

```bash
yarn test:local
```

`test:local` sources `scripts/local-env.sh` so the SDK targets the local cluster. The test uses a
vendored `--features test-mode` `ephemeral_oracle.so` fixture, so prices are deterministic and seeded
by the test wallet.
`yarn test` runs `cargo +stable test`: MagicSVM needs a newer Rust than the 1.89 toolchain used for program builds.

## Client

Expand All @@ -89,9 +84,8 @@ By default the client targets MagicBlock devnet — `https://rpc.magicblock.app/
layer and `https://devnet-as.magicblock.app` (`wss://devnet-as.magicblock.app`) for the ER — so
`yarn dev` with no overrides works out of the box against devnet.

To point it at a local MagicBlock cluster instead, start the cluster with `yarn setup` and set these
env vars before `yarn dev` (the client reads `VITE_`-prefixed vars, not the shell exports from
`scripts/local-env.sh`):
To point it at a separately running local MagicBlock cluster, set these environment variables before
`yarn dev`:

```bash
export VITE_PROVIDER_ENDPOINT=http://localhost:8899
Expand Down
23 changes: 3 additions & 20 deletions binary-prediction/anchor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,11 @@
"scripts": {
"lint:fix": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --no-error-on-unmatched-pattern */*.js \"*/**/*{.js,.ts}\" -w",
"lint": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --no-error-on-unmatched-pattern */*.js \"*/**/*{.js,.ts}\" --check",
"test": "yarn test:local",
"build": "anchor keys sync && anchor build",
"test:local": ". ../../scripts/local-env.sh && npx ts-mocha -p ./tsconfig.json -t 1000000 tests/binary-prediction.ts",
"setup": "cd ../.. && SETUP_ONLY=1 ./scripts/test-locally.sh binary-prediction"
},
"dependencies": {
"@coral-xyz/anchor": "0.32.1",
"@magicblock-labs/ephemeral-rollups-sdk": "0.14.3",
"@magicblock-labs/gum-sdk": "^3.0.10"
"test": "cargo +stable test --manifest-path tests-magicsvm-rs/Cargo.toml",
"build": "anchor build --ignore-keys"
},
"devDependencies": {
"@solana/spl-token": "^0.4.14",
"@types/bn.js": "^5.1.0",
"@types/chai": "^4.3.20",
"@types/mocha": "^10.0.10",
"chai": "^4.5.0",
"mocha": "^11.2.2",
"prettier": "^3.5.3",
"ts-mocha": "^11.1.0",
"ts-node": "^10.9.2",
"tsx": "^4.22.0",
"typescript": "^5.8.3"
"prettier": "^3.5.3"
},
"license": "MIT",
"packageManager": "yarn@1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod state;
mod utils;

use error::ErrorCode;
use state::{Bet, Direction, Pool};
pub use state::{Bet, Direction, Pool};
use utils::*;

declare_id!("7HHiv8th2wY24iZp2ReF7QkJyFJHwHWCgZWg7CWrQnnm");
Expand Down
Loading
Loading