Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
272bd98
feat: binary step-log replay verifier
Jun 16, 2026
818e970
fix: make step-log recorder scripts executable
Jun 16, 2026
a7221fa
ci: add solidity-step tests and drift check
Jun 16, 2026
9e8a509
ci: pin forge to v1.0.0; sync transpiled .sol
Jun 16, 2026
d8b2869
docs: pin forge v1.0.0, fix solidity-step cmds
Jun 16, 2026
95a0361
ci: build devel image in solidity-step job
Jun 16, 2026
abbf3bd
ci: render solidity-step coverage as HTML report
Jun 16, 2026
43a1ca4
ci: drop obsolete uarch JSON log path
Jun 17, 2026
b3b0dd1
chore: review-cycle cleanup of step-log verifier
Jun 22, 2026
50ccc2e
feat: CLI records > 1 uarch cycle
Jun 22, 2026
ae149d6
feat: add max pages flds program
Jun 22, 2026
3fc0ffe
ci: check emulator constants drift
Jun 23, 2026
4c281ed
chore: format
Jun 23, 2026
d2c1a0c
fix: tests
Jun 23, 2026
821f4fc
ci: gate risc0 Rust formatting with cargo fmt
Jun 23, 2026
d2bc8c7
chore: cleanup
Jun 23, 2026
6105056
fix: reject oversized CMIO response length
Jun 23, 2026
8597df7
fix: assert consumed nodes on Solidity revert path
Jun 23, 2026
48f82ba
chore: add more tests
Jun 23, 2026
e2b7171
chore: cleanup
Jun 24, 2026
91189ce
chore: cleanup
Jun 24, 2026
bd5bd4d
chore: cleanup
Jun 24, 2026
35d5ebc
fix: reject out-of-range collect bundle count
Jun 25, 2026
dc51dbc
fix: clear pretty-print output on failure
Jun 25, 2026
5056bfa
perf: skip rehashing clean pages on after-root
Jun 25, 2026
0a0cd23
refactor: rename vestigial check_ replay helpers
Jun 25, 2026
62881e4
refactor: remove mark_dirty_page from uarch
Jun 26, 2026
5f1b821
chore: format
Jun 27, 2026
9a8e32f
test: expand risc0 adversarial reject cases
Jun 27, 2026
349a87c
chore: drop dead risc0 const, fix clippy
Jun 27, 2026
84b48bd
chore: move step-log-util.lua to src
Jun 27, 2026
11299c6
chore: format
Jun 27, 2026
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
203 changes: 177 additions & 26 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -293,19 +293,6 @@ jobs:
run: |
docker run --rm -t ${{ github.repository_owner }}/machine-emulator:tests cartesi-machine-tests --concurrency=update_hash_tree:1 --test="^rv64ui.*$" --jobs=$(nproc) run_host_and_uarch
- name: Create uarch json logs to be used to test the Solidity based microarchitecture interpreter
run: |
docker run --name uarch-logs -w /tmp -t ${{ github.repository_owner }}/machine-emulator:tests /usr/share/cartesi-machine/tests/scripts/collect-uarch-test-logs.sh
docker cp uarch-logs:/tmp/uarch-riscv-tests-json-logs.tar.gz .
docker rm uarch-logs
- name: Upload uarch json logs to be used to test the Solidity based microarchitecture interpreter
uses: actions/upload-artifact@v4
with:
name: uarch-logs
path: uarch-riscv-tests-json-logs.tar.gz
compression-level: 0

- name: Build machine-emulator "tests" docker image
uses: docker/build-push-action@v5
with:
Expand Down Expand Up @@ -760,7 +747,6 @@ jobs:
artifacts/machine-emulator_*.deb
artifacts/uarch-ram.bin
add-generated-files.diff
uarch-logs/uarch-riscv-tests-json-logs.tar.gz
tests-amd64/machine-emulator-tests-data.deb
tests-amd64/machine-emulator-tests_*.deb
tests-arm64/machine-emulator-tests_*.deb
Expand Down Expand Up @@ -845,20 +831,29 @@ jobs:
- name: Simple boot inside the docker image
run: docker run --rm -t ${{ github.repository_owner }}/machine-emulator:tests /usr/bin/cartesi-machine /bin/true

- name: Create step log test files
- name: Generate risc0 fixtures
run: |
mkdir -p /tmp/cartesi-machine/tests/data/step-logs
chmod -R 777 /tmp/cartesi-machine/tests/data
docker run --rm -t -v /tmp/cartesi-machine/tests/data:/tmp/cartesi-machine/tests/data ${{ github.repository_owner }}/machine-emulator:tests /usr/bin/cartesi-machine-tests --hash-function=sha256 --save-step-logs=/tmp/cartesi-machine/tests/data/step-logs run_step
docker run --rm -t -v /tmp/cartesi-machine/tests/data:/tmp/cartesi-machine/tests/data ${{ github.repository_owner }}/machine-emulator:tests /usr/share/cartesi-machine/tests/lua/create-step-logs.lua
ls -l /tmp/cartesi-machine/tests/data/step-logs
mkdir -p risc0/test/fixtures/cartesi-machine-tests risc0/test/fixtures/one-mcycle
chmod -R 777 risc0/test/fixtures
docker run --rm -t -v ${{ github.workspace }}/risc0/test/fixtures:/fixtures ${{ github.repository_owner }}/machine-emulator:tests \
cartesi-machine-tests --jobs=$(nproc) --hash-function=sha256 --save-step-logs=/fixtures/cartesi-machine-tests run_step
docker run --rm -t -v ${{ github.workspace }}/risc0/test/fixtures:/fixtures ${{ github.repository_owner }}/machine-emulator:tests \
/usr/share/cartesi-machine/tests/lua/record-one-mcycle.lua --output-dir=/fixtures/one-mcycle
# Adversarial logs the guest must reject (test_reject_fixtures.rs). Mirrors the third
# recorder in risc0/Makefile's fixtures target; tampers the positive logs above.
docker run --rm -t -v ${{ github.workspace }}/risc0/test/fixtures:/fixtures ${{ github.repository_owner }}/machine-emulator:tests \
/usr/share/cartesi-machine/tests/lua/record-adversarial-machine.lua --fixtures-dir=/fixtures --output-dir=/fixtures/reject-machine
ls -lR risc0/test/fixtures
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true

- name: Check Rust formatting
run: make -C risc0 check-format

- name: Install rzup
run: |
cargo install --git https://github.com/risc0/risc0 rzup
Expand All @@ -875,18 +870,17 @@ jobs:
run: sudo apt-get update && sudo apt-get install -y lua5.4

- name: Install Foundry
# Pinned to the same forge version as the solidity-step job (single version across the
# workflow; the version that generated the committed transpiled .sol).
uses: foundry-rs/foundry-toolchain@v1
with:
version: v1.0.0

- name: Build risc0 prover/verifier
run: make risc0

- name: Copy step log fixture for RISC0 tests
run: |
mkdir -p risc0/test/fixtures
cp /tmp/cartesi-machine/tests/data/step-logs/step-0.log risc0/test/fixtures/step.log
- name: Run risc0 tests
run: CARTESI_STEP_LOGS_PATH=/tmp/cartesi-machine/tests/data/step-logs make test-risc0
run: CARTESI_STEP_LOGS_PATH=${{ github.workspace }}/risc0/test/fixtures/cartesi-machine-tests make test-risc0

- name: Export RISC0 artifacts
run: make -C risc0 export-artifacts
Expand All @@ -899,3 +893,160 @@ jobs:
risc0/artifacts/cartesi-risc0-guest-step-prover.bin
risc0/artifacts/cartesi-risc0-guest-step-prover-image-id.txt
risc0/artifacts/ImageID.sol
solidity-step:
name: Solidity Step
needs: [check-format, check-commits]
runs-on: ubuntu-latest-8-cores
steps:
- name: Checkout machine emulator source code
uses: actions/checkout@v4
with:
submodules: recursive

# The transpiler drift check and its golden tests need only lua + lpeg + forge (no built
# emulator), so they run first and fail fast before the expensive image build below.
- name: Install lua5.4 and lpeg
run: |
sudo apt-get update && sudo apt-get install -y lua5.4 lua-lpeg
lua5.4 -e 'require("lpeg")'
- name: Install Foundry
# Pinned: forge fmt output must match the version that generated the committed transpiled
# .sol files (the check-gen-transpiled drift check below), the same reason we pin clang-format.
uses: foundry-rs/foundry-toolchain@v1
with:
version: v1.0.0

- name: Check transpiled Solidity is in sync with the C++ sources
run: make -C solidity-step check-gen-transpiled

- name: Transpiler golden tests
run: make -C solidity-step test-transpile

- name: Setup variables
run: echo MACHINE_EMULATOR_VERSION=`make version` >> $GITHUB_ENV

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Depot CLI
uses: depot/setup-action@v1

- name: Build machine-emulator "builder" docker image
uses: depot/build-push-action@v1
with:
file: Dockerfile
context: .
target: builder
platforms: linux/amd64
tags: ${{ github.repository_owner }}/machine-emulator:builder
push: false
load: true
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
MACHINE_EMULATOR_VERSION=${{ env.MACHINE_EMULATOR_VERSION }}
project: ${{ vars.DEPOT_PROJECT }}
token: ${{ secrets.DEPOT_TOKEN }}

# tests/Dockerfile's runtime stage is FROM cartesi/machine-emulator:devel, so build it too.
- name: Build machine-emulator docker image
uses: depot/build-push-action@v1
with:
file: Dockerfile
context: .
platforms: linux/amd64
tags: ${{ github.repository_owner }}/machine-emulator:devel
push: false
load: true
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
MACHINE_EMULATOR_VERSION=${{ env.MACHINE_EMULATOR_VERSION }}
project: ${{ vars.DEPOT_PROJECT }}
token: ${{ secrets.DEPOT_TOKEN }}

- name: Build machine-emulator "tests" docker image
uses: docker/build-push-action@v5
with:
file: tests/Dockerfile
context: .
platforms: linux/amd64
tags: ${{ github.repository_owner }}/machine-emulator:tests
push: false
load: true
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
MACHINE_EMULATOR_VERSION=${{ env.MACHINE_EMULATOR_VERSION }}
# check-gen-constants reads the live cartesi Lua module, so the generator runs INSIDE the tests
# image (no built emulator on the runner); forge fmt + the diff run on the runner. -t is omitted
# so the container's stdout redirects to the file uncorrupted, and forge fmt runs from
# solidity-step/ so it picks up that project's [fmt] config (matching how the file was generated).
- name: Check emulator constants are in sync with the C++ headers
run: |
docker run --rm -v ${{ github.workspace }}:/work:ro -w /work ${{ github.repository_owner }}/machine-emulator:tests \
lua5.4 solidity-step/tools/gen-emulator-constants.lua > /tmp/EmulatorConstants.gen.sol
cd solidity-step
forge fmt /tmp/EmulatorConstants.gen.sol
diff -u src/EmulatorConstants.sol /tmp/EmulatorConstants.gen.sol \
|| { echo "ERROR: src/EmulatorConstants.sol is stale. Run 'make -C solidity-step gen-constants' and commit."; exit 1; }
- name: Generate solidity-step fixtures
run: |
FIX=solidity-step/test/fixtures
mkdir -p $FIX/uarch-tests $FIX/uarch-tests-per-cycle $FIX/send-cmio-response $FIX/reset-uarch
chmod -R 777 $FIX
IMG=${{ github.repository_owner }}/machine-emulator:tests
# uarch-riscv-tests is the installed wrapper (it bakes CARTESI_TESTS_UARCH_PATH); the
# record-*.lua recorders are run directly (executable, with a lua5.4 shebang). Mirrors
# solidity-step/Makefile's fixtures target; adversarial recorders tamper the positive sets.
docker run --rm -t -v ${{ github.workspace }}/$FIX:/fixtures $IMG \
uarch-riscv-tests --test='rv64ui%-uarch%-.+%.bin' --output-dir=/fixtures/uarch-tests record_uarch_tests
docker run --rm -t -v ${{ github.workspace }}/$FIX:/fixtures $IMG \
uarch-riscv-tests --test='rv64ui%-uarch%-.+%.bin' --per-cycle-logs --output-dir=/fixtures/uarch-tests-per-cycle record_uarch_tests
docker run --rm -t -v ${{ github.workspace }}/$FIX:/fixtures $IMG \
/usr/share/cartesi-machine/tests/lua/record-send-cmio-response.lua --output-dir=/fixtures/send-cmio-response
docker run --rm -t -v ${{ github.workspace }}/$FIX:/fixtures $IMG \
/usr/share/cartesi-machine/tests/lua/record-reset-uarch.lua --output-dir=/fixtures/reset-uarch
docker run --rm -t -v ${{ github.workspace }}/$FIX:/fixtures $IMG \
/usr/share/cartesi-machine/tests/lua/record-adversarial-uarch.lua --fixtures-dir=/fixtures --output-dir=/fixtures/reject-uarch
docker run --rm -t -v ${{ github.workspace }}/$FIX:/fixtures $IMG \
/usr/share/cartesi-machine/tests/lua/record-adversarial-send-cmio-response.lua --fixtures-dir=/fixtures --output-dir=/fixtures/reject-send-cmio-response
ls -lR $FIX
- name: Run solidity-step tests
run: make -C solidity-step test

# Coverage is informational and forge's --ir-minimum pass is slow, so it never gates the job.
- name: Solidity-step coverage report
continue-on-error: true
run: |
sudo apt-get update && sudo apt-get install -y lcov
cd solidity-step
forge coverage --ir-minimum --report summary --report lcov | tee coverage-summary.txt
genhtml lcov.info --output-directory coverage-html --title "solidity-step coverage" --quiet || true
- name: Upload solidity-step coverage
continue-on-error: true
uses: actions/upload-artifact@v4
with:
name: solidity-step-coverage
# coverage-html/ is the browsable report; coverage-summary.txt is the quick text table;
# lcov.info is the raw tracefile for tooling.
path: |
solidity-step/coverage-html
solidity-step/coverage-summary.txt
solidity-step/lcov.info
if-no-files-found: warn
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
build
tests/fuzz/seed-corpus
tests/fuzz/corpus
tests/fuzz/fuzz-config
tests/fuzz/fuzz-interpret
tests/fuzz/fuzz-interpret-step
tests/fuzz/*.dSYM
pkg
third-party/downloads
src/cartesi-jsonrpc-machine
Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ brew install cartesi-machine
- Boost >= 1.83
- Lua >= 5.4.6 (optional, required for scripting support and interactive terminal)
- Libslirp >= 4.6.0 (optional, required for networking support)
- luaposix (optional, required for running the test suite; install into the same Lua tree, e.g. `luarocks install luaposix`)
- Rust and RISC Zero toolchain (optional, required for building the RISC Zero prover)

###### Debian Requirements
Expand Down Expand Up @@ -155,11 +156,25 @@ rzup install r0vm

Then build with `make risc0`.

###### Foundry Requirements (optional, for Solidity tests only)
###### Foundry Requirements (optional, for the Solidity step library)

The in-tree `solidity-step/` library replays binary step logs on-chain for fraud-proof verification.
It is optional and lateral to the core: the main `make` build needs neither Foundry nor Rust. To
build and test it you'll need [Foundry](https://getfoundry.sh/), pinned to the version CI uses
(`forge fmt` output is version-specific, and the transpiled Solidity is drift-checked against it):

```sh
curl -L https://foundry.paradigm.xyz | bash
foundryup
foundryup --install v1.0.0
```

The library has its own `solidity-step/` Makefile; drive it directly (recording fixtures needs a
built emulator and its uarch test programs):

```sh
make -C solidity-step build # compile the contracts
make -C solidity-step fixtures # record step-log fixtures from the emulator
make -C solidity-step test # forge fmt --check + forge test
```

#### Build
Expand Down
Loading
Loading