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
54 changes: 54 additions & 0 deletions .changeset/app-native-redesign.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
"@deroll/core": minor
"@deroll/app": minor
"@deroll/wallet": minor
"@deroll/router": minor
---

Redesign the app stack on top of the native `@deroll/rollup` binding and the
`@deroll/codec` package. This is a **breaking** change across `@deroll/core`,
`@deroll/app`, `@deroll/wallet` and `@deroll/router`:

- **Flattened advance data.** Advance handlers receive the codec's `Advance`
object directly — `{ chainId, appContract, msgSender, blockNumber,
blockTimestamp, prevRandao, index, payload }` — with no `metadata` nesting.
Payloads (advance and inspect) are 0x-hex strings (`Hex`), no longer
`Buffer`s.
- **Boolean handler results.** Advance handlers return `true` (accept) or
`false` (reject) instead of the `"accept"` / `"reject"` strings, matching
the underlying binding. Inspect handlers receive the raw query payload
(`Hex`) directly, and `createReport` / `registerException` take the payload
directly instead of a `{ payload }` wrapper. The `AdvanceRequestData`,
`InspectRequestData`, `Report`, `Exception` and `RequestHandlerResult`
types are gone — use `Advance` and `Hex` from the codec.
- **Synchronous output methods.** The `create*` methods, `registerException`
and `stop` no longer return promises — the native binding emits outputs
synchronously, so `createNotice` etc. return the output index (`number`)
directly and no longer need `await`. Only `start()` remains async.
- **`createVoucher` is now `createCallVoucher`**, matching the rollup's
`CallVoucher` output format; `value` and `payload` are required (`0n` / `0x`
when unused). `createDelegateCallVoucher` is removed (the output type was
dropped by the rollup).
- **Typed asset transfer outputs.** New `App` methods `createErc20Transfer`,
`createErc721Transfer`, `createErc1155Transfer` and
`createErc1155BatchTransfer` emit the rollup's dedicated transfer formats
without manual ABI encoding, plus `createOutput(payload)` as an escape hatch
for already-encoded outputs.
- **Output `appContext`.** Every output accepts an optional `bytes32`
`appContext` tag (default zero hash); an application-wide default can be set
via the new `createApp({ appContext })` option. `App` also gains `stop()`.
- **Wallet withdrawals return typed outputs.** The `withdraw*` methods debit
the ledger and return the typed output object — a `CallVoucher` from
`withdrawEther`, the corresponding `ERC*Transfer` from the others — to be
emitted with the matching `App` method, e.g.
`app.createErc20Transfer(wallet.withdrawErc20(token, user, amount))`. This
routes wallet withdrawals through the App's encoders, so the app-wide
`appContext` default applies to them like any other output. The
ERC-721/1155 withdrawals no longer take the application address (`dapp`)
parameter nor a `data` payload (the wire formats dropped it). The deposit
parsers take `Hex` payloads, and the `create*TransferVoucher` /
`createWithdrawEtherVoucher` helpers are removed in favor of the typed
outputs.
- **Removed HTTP-era types** from `@deroll/core` (`Voucher`,
`DelegateCallVoucher`, `RequestMetadata`, ...); the request/output
vocabulary now comes from `@deroll/codec`.
4 changes: 2 additions & 2 deletions .changeset/cmio-initial.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
"@deroll/cmio": minor
"@deroll/rollup": minor
"@deroll/app": patch
"@deroll/create-app": patch
---

Add `@deroll/cmio` — Node.js bindings for libcmt (migrated from `@tuler/node-libcmt`). The libcmt C source is tracked as a git submodule (`machine-guest-tools`) and compiled into a native addon (host builds use the mock-IO driver). `@deroll/app` and the `create-app` scaffolding now depend on the in-repo `@deroll/cmio` instead of the external `@tuler/node-libcmt`.
Add `@deroll/rollup` — Node.js bindings for libcmt (migrated from `@tuler/node-libcmt`). The libcmt C source is tracked as a git submodule (`machine-guest-tools`) and compiled into a native addon (host builds use the mock-IO driver). `@deroll/app` and the `create-app` scaffolding now depend on the in-repo `@deroll/rollup` instead of the external `@tuler/node-libcmt`.
26 changes: 26 additions & 0 deletions .changeset/cmio-libcmt-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
"@deroll/rollup": minor
---

Port the binding to the libcmt v2 API overhaul (machine-guest-tools
`91dc33e`, "output indexing" era).

This is a **breaking** change. libcmt v2 made the rollup layer raw I/O only and moved
all EVM-ABI encoding/decoding into a separate `codec` module, so the binding mirrors
that split — the package is now exclusively the native `rollup.h` binding, and is
**renamed from `@deroll/cmio` to `@deroll/rollup`** to reflect that:

- **`Rollup` is a thin, raw wrapper.** `finish()` is replaced by
`waitForInput({ accept })`, which returns `{ type, payload }` with the **raw, undecoded**
input bytes. Outputs are emitted with `emitOutput(bytes)` (returns the output index);
`emitReport`/`emitException`/`progress`/`close`/`run` are unchanged in spirit.
- **ABI encoding/decoding lives in the new [`@deroll/codec`](https://www.npmjs.com/package/@deroll/codec)
package** — pure JS, dual ESM + CommonJS, browser-compatible. Compose it with the raw API, e.g.
`rollup.emitOutput(encodeNotice(payload))` and `decodeAdvance(request.payload)`.
- **Removed:** delegate-call vouchers (dropped by libcmt v2 along with the
`Output1..Output4` envelope design), `gio()` (libcmt v2 dropped generic IO support),
and the `loadMerkle`/`saveMerkle`/`resetMerkle` methods (no longer part of the
rollup API).
- The high-level `emitVoucher`/`emitNotice`/`emitDelegateCallVoucher` methods and the
decoded `AdvanceRequest` fields on `finish()` are gone; use `@deroll/codec` instead.
- The package no longer depends on `ox`.
27 changes: 27 additions & 0 deletions .changeset/codec-initial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
"@deroll/codec": minor
---

New package: EVM-ABI codecs for Cartesi rollup inputs and outputs, extracted from
`@deroll/rollup` so the wire formats can be used without the native binding — in Node.js
**and in browsers**. Pure JavaScript (dual ESM + CommonJS) depending only on `ox` and `abitype`
(types only — argument types are derived from the ABI itself).
The codecs speak ox's native types — bytes/addresses are 0x-hex strings, numbers
are `bigint` — with no conversions inside; invalid values raise ox's own errors.
The full `abi` is also exported for direct use with viem/ox.

One function per libcmt `codec.h` entry, producing/consuming the exact same bytes
(verified against libcmt's own `cast`-generated golden vectors):

- `decodeAdvance` / `encodeAdvance` —
`EvmAdvance(uint64,address,address,uint64,uint64,uint256,uint64,bytes)`
- `encodeNotice` — `Notice(bytes32,bytes)`
- `encodeCallVoucher` — `CallVoucher(bytes32,address,uint256,bytes)`
- `encodeErc20Transfer` — `Erc20Transfer(bytes32,address,address,uint256)`
- `encodeErc721Transfer` — `Erc721Transfer(bytes32,address,address,uint256)`
- `encodeErc1155Transfer` — `Erc1155Transfer(bytes32,address,address,uint256,uint256)`
- `encodeErc1155BatchTransfer` — `Erc1155BatchTransfer(bytes32,address,address,(uint256,uint256)[])`

Every output carries `appContext`, a free-form `bytes32` applications use to tag
outputs (recipients can filter outputs by it); it is optional and defaults to the
zero hash.
2 changes: 1 addition & 1 deletion .changeset/fine-garlics-cut.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@deroll/cmio": patch
"@deroll/rollup": patch
---

bump node-gyp
2 changes: 1 addition & 1 deletion .changeset/hip-apes-hunt.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@deroll/cmio": patch
"@deroll/rollup": patch
"@deroll/cm": patch
---

Expand Down
2 changes: 1 addition & 1 deletion .changeset/pre.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@deroll/wallet": "1.0.0",
"@deroll/explorer": "0.1.0",
"@deroll/cm": "0.1.0",
"@deroll/cmio": "0.1.0",
"@deroll/rollup": "0.1.0",
"@deroll/decoder": "0.1.0",
"@deroll/json-decoder": "0.1.0",
"@deroll/mock-server": "0.1.0"
Expand Down
7 changes: 7 additions & 0 deletions .changeset/rename-rollup-binding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@deroll/app": patch
"@deroll/create-app": patch
---

Follow the libcmt binding rename: depend on `@deroll/rollup` instead of
`@deroll/cmio` (the scaffolded Dockerfiles stage the new package name).
16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- name: Checkout Repo
uses: actions/checkout@v6
with:
# cmio's native addon (cmt.node) compiles from the
# the rollup binding's native addon compiles from the
# machine-guest-tools submodule (deps/machine-guest-tools)
# during `bun install`, so it must be checked out.
submodules: recursive
Expand All @@ -44,7 +44,7 @@ jobs:
node-version: 24

# ubuntu-latest already ships gcc/g++/make/python3, which node-gyp
# needs to compile cmio's addon on install.
# needs to compile the rollup binding's addon on install.
- name: Install Dependencies
run: bun install --frozen-lockfile

Expand All @@ -62,8 +62,8 @@ jobs:
# linux prebuilds are already exercised by `bun run test` above; the riscv64
# addon can only be validated under emulation, so it's kept OFF the PR/push
# hot path and runs on demand and weekly.
cmio-machine:
name: cmio riscv64 machine test
rollup-machine:
name: rollup binding riscv64 machine test
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -93,19 +93,19 @@ jobs:
sudo apt-get install -y --allow-downgrades /tmp/linux-libc-dev.deb

- name: Cross-build libcmt (real IO driver)
working-directory: packages/bindings/cmio
working-directory: packages/bindings/rollup
run: make -C deps/machine-guest-tools/sys-utils/libcmt libcmt TOOLCHAIN_PREFIX=riscv64-linux-gnu-

- name: Prebuild riscv64 addon
working-directory: packages/bindings/cmio
working-directory: packages/bindings/rollup
env:
CC: riscv64-linux-gnu-gcc
CXX: riscv64-linux-gnu-g++
LIBCMT_LIB: ${{ github.workspace }}/packages/bindings/cmio/deps/machine-guest-tools/sys-utils/libcmt/build/riscv64/libcmt.a
LIBCMT_LIB: ${{ github.workspace }}/packages/bindings/rollup/deps/machine-guest-tools/sys-utils/libcmt/build/riscv64/libcmt.a
run: bun run prebuild -- --strip-bin riscv64-linux-gnu-strip --platform linux --arch riscv64

- name: Run end-to-end test inside cartesi-machine
working-directory: packages/bindings/cmio
working-directory: packages/bindings/rollup
run: |
CARTESI_MACHINE="docker run --rm -u $(id -u):$(id -g) -v $PWD:/mnt -w /mnt cartesi/machine-emulator:0.19.0 cartesi-machine" \
SKIP_PREBUILD=1 test/machine/run.sh
46 changes: 23 additions & 23 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ env:
LINUX_VERSION: 6.5.13-ctsi-1

jobs:
# Build cmio prebuilds only when @deroll/cmio is actually about to be
# Build rollup-binding prebuilds only when @deroll/rollup is actually about to be
# published — i.e. its package.json version is not yet on npm. This is the
# only reason the prebuild matrix needs to run, and it's correct in every
# case: false on Version-PR runs (cmio not bumped yet) and on already-
# case: false on Version-PR runs (@deroll/rollup not bumped yet) and on already-
# published versions. (Counting .changeset/*.md does NOT work: in changesets
# pre mode the .md files persist after `changeset version`, so they can't
# signal whether this push publishes.)
detect:
name: Detect cmio publish
name: Detect rollup binding publish
runs-on: ubuntu-latest
outputs:
publish: ${{ steps.check.outputs.publish }}
Expand All @@ -38,20 +38,20 @@ jobs:
node-version: 24
- id: check
run: |
LOCAL=$(node -p "require('./packages/bindings/cmio/package.json').version")
if npm view "@deroll/cmio@${LOCAL}" version >/dev/null 2>&1; then
LOCAL=$(node -p "require('./packages/bindings/rollup/package.json').version")
if npm view "@deroll/rollup@${LOCAL}" version >/dev/null 2>&1; then
echo "publish=false" >> "$GITHUB_OUTPUT"
echo "@deroll/cmio@${LOCAL} already on npm -> skip prebuilds."
echo "@deroll/rollup@${LOCAL} already on npm -> skip prebuilds."
else
echo "publish=true" >> "$GITHUB_OUTPUT"
echo "@deroll/cmio@${LOCAL} not yet published -> build prebuilds."
echo "@deroll/rollup@${LOCAL} not yet published -> build prebuilds."
fi

# @deroll/cmio native prebuilds, built from the exact commit being published
# @deroll/rollup native prebuilds, built from the exact commit being published
# (linux-x64/arm64, darwin-x64/arm64). Each job uploads a prebuilds-<os>
# artifact the release job collects. riscv64 validation lives in ci.yml.
prebuild:
name: cmio prebuild ${{ matrix.os }}
name: rollup prebuild ${{ matrix.os }}
needs: detect
if: needs.detect.outputs.publish == 'true'
strategy:
Expand All @@ -71,19 +71,19 @@ jobs:
with:
node-version: 24
# bun (not npm) — the workspace uses bun's `catalog:` protocol, which
# npm can't resolve. Install at the repo root, then prebuild in cmio.
# npm can't resolve. Install at the repo root, then prebuild in the rollup package.
- run: bun install --frozen-lockfile
- name: Build prebuild
working-directory: packages/bindings/cmio
working-directory: packages/bindings/rollup
run: bun run prebuild
- uses: actions/upload-artifact@v7
with:
name: prebuilds-${{ matrix.os }}
if-no-files-found: error
path: packages/bindings/cmio/prebuilds/
path: packages/bindings/rollup/prebuilds/

prebuild-riscv64:
name: cmio prebuild linux-riscv64 (cross)
name: rollup prebuild linux-riscv64 (cross)
needs: detect
if: needs.detect.outputs.publish == 'true'
runs-on: ubuntu-latest
Expand All @@ -104,26 +104,26 @@ jobs:
"https://github.com/cartesi/machine-linux-image/releases/download/${LINUX_IMAGE_VERSION}/linux-libc-dev-riscv64-cross-${LINUX_VERSION}-${LINUX_IMAGE_VERSION}.deb"
sudo apt-get install -y --allow-downgrades /tmp/linux-libc-dev.deb
- name: Cross-build libcmt (real IO driver)
working-directory: packages/bindings/cmio
working-directory: packages/bindings/rollup
run: make -C deps/machine-guest-tools/sys-utils/libcmt libcmt TOOLCHAIN_PREFIX=riscv64-linux-gnu-
- name: Prebuild riscv64 addon
working-directory: packages/bindings/cmio
working-directory: packages/bindings/rollup
env:
CC: riscv64-linux-gnu-gcc
CXX: riscv64-linux-gnu-g++
LIBCMT_LIB: ${{ github.workspace }}/packages/bindings/cmio/deps/machine-guest-tools/sys-utils/libcmt/build/riscv64/libcmt.a
LIBCMT_LIB: ${{ github.workspace }}/packages/bindings/rollup/deps/machine-guest-tools/sys-utils/libcmt/build/riscv64/libcmt.a
run: bun run prebuild -- --strip-bin riscv64-linux-gnu-strip --platform linux --arch riscv64
- uses: actions/upload-artifact@v7
with:
name: prebuilds-riscv64
if-no-files-found: error
path: packages/bindings/cmio/prebuilds/
path: packages/bindings/rollup/prebuilds/

release:
name: Release
needs: [detect, prebuild, prebuild-riscv64]
# Run when creating the Version PR (publish=false, prebuilds skipped), or
# when publishing AND every prebuild succeeded. Never publish cmio without
# when publishing AND every prebuild succeeded. Never publish @deroll/rollup without
# its prebuilds: a prebuild failure blocks the release (re-runnable).
if: >-
always() && needs.detect.result == 'success' &&
Expand All @@ -134,7 +134,7 @@ jobs:
- name: Checkout Repo
uses: actions/checkout@v6
with:
# cmio's native addon compiles from the machine-guest-tools
# the rollup binding's native addon compiles from the machine-guest-tools
# submodule (deps/machine-guest-tools) during `bun install`.
submodules: recursive

Expand All @@ -155,16 +155,16 @@ jobs:
- name: Install Dependencies
run: bun install --frozen-lockfile

# Collect all platform prebuilds into the cmio package so
# `changeset publish` packs @deroll/cmio with them instead of forcing
# Collect all platform prebuilds into the rollup package so
# `changeset publish` packs @deroll/rollup with them instead of forcing
# consumers to compile from source. Only present when publishing.
- name: Collect cmio prebuilds
- name: Collect rollup prebuilds
if: needs.detect.outputs.publish == 'true'
uses: actions/download-artifact@v8
with:
pattern: prebuilds-*
merge-multiple: true
path: packages/bindings/cmio/prebuilds
path: packages/bindings/rollup/prebuilds

- name: Create Release Pull Request or Publish to npm
id: changesets
Expand Down
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "packages/bindings/cmio/deps/machine-guest-tools"]
path = packages/bindings/cmio/deps/machine-guest-tools
[submodule "packages/bindings/rollup/deps/machine-guest-tools"]
path = packages/bindings/rollup/deps/machine-guest-tools
url = https://github.com/cartesi/machine-guest-tools
Loading