Skip to content
Closed
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
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y \
faketime \
libclang-dev \
libfaketime \
lua5.4 \
liblua5.4-dev \
Expand Down Expand Up @@ -62,6 +63,9 @@ jobs:
timeout-minutes: 15
run: cargo test --workspace --all-targets --all-features --locked

- name: C application archive and downstream consumer
run: bash scripts/ci-c-application-smoke.sh

canonical-guest:
runs-on: ubuntu-latest
needs: rust
Expand Down
8 changes: 6 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ Top-level layout follows the system's data flow. Each sequencer module correspon
- `sequencer-core/` — shared domain types (`Application`, `SignedUserOp`, `SequencedL2Tx`, `Batch`, `Frame`).
- `examples/app-core/` — placeholder wallet app implementing the `Application` trait.
- `examples/wallet-sequencer/` — binary crate: wallet app + sequencer library. The model for what an app author builds (their `Application` impl ≙ `app-core`; their binary crate ≙ this).
- `bindings/c-app-engine/` — reusable C ABI adapter implementing `Application` for a native engine.
- `bindings/c-app-sequencer/` — optional C-engine CLI host and external-archive binary.
- `examples/c-wallet-engine/` — reference wallet engine exporting the C ABI, plus its genesis tool and conformance tests.
- `examples/c-wallet-sequencer/` — binary composing the C-engine host with the reference wallet engine.
- `examples/canonical-app/` — on-chain scheduler reference implementation.
- `examples/canonical-test/` — e2e test harness for the canonical app.
- `sdk/rust-client/` — Rust client library for the sequencer API.
Expand Down Expand Up @@ -247,7 +251,7 @@ Logical state changes, including `ApplicationProgress`, flow through the `apply_

User ops are executed only through `sequencer_core::application::validate_and_execute_user_op`; already-validated user ops and directs use `execute_valid_user_op` / `execute_direct_input`. The shared boundary preflights the checked successor, then verifies the engine's progress after a successful hook and returns its pre-execution offset. Count zero implies clock zero. Validation purity and native mutation remain self-trusted. `AppError` is fatal and defines no canonical successor; callers discard the instance rather than resume it. The inclusion lane, canonical scheduler, catch-up, and recovery fold all use this boundary — part of the duality agreement.

`Application` requires `Send`, with neither `Clone` nor `Sync`. Dumps must be durable and immutable, and restored engines must remain independent after source deletion. The opaque app prefix may be a file or directory. Canonical inspection belongs to the separate `CanonicalState` trait; the native sequencer serves the comparison file in the checkpoint.
`Application` requires `Send`, with neither `Clone` nor `Sync`. Dumps must be durable and immutable, and restored engines must remain independent after source deletion. The opaque app prefix may be a file or directory; checkpoint disposal uses ordinary recursive filesystem deletion. Canonical inspection belongs to the separate `CanonicalState` trait; the native sequencer serves the comparison file in the checkpoint. The [C binding guide](docs/protocol/c-application-binding.md) maps the contract to native engines.

## Hot-Path Invariants

Expand Down Expand Up @@ -455,7 +459,7 @@ Before finishing a change, ensure:

- [`README.md`](README.md) — product framing, user-facing trust model, **API contract** (endpoint shapes, caps, close codes, health semantics).
- [`CLAUDE.md`](CLAUDE.md) — shell setup, quick reference, pointer back here.
- [`docs/protocol/`](docs/protocol/) — the authoritative protocol contracts: [`scheduler-semantics.md`](docs/protocol/scheduler-semantics.md) (the canonical acceptance algorithm, I1) and [`application-contract.md`](docs/protocol/application-contract.md) (the `Application` FFI trait contract).
- [`docs/protocol/`](docs/protocol/) — the authoritative protocol contracts: [`scheduler-semantics.md`](docs/protocol/scheduler-semantics.md) (the canonical acceptance algorithm, I1), [`application-contract.md`](docs/protocol/application-contract.md) (the `Application` trait contract), and [`c-application-binding.md`](docs/protocol/c-application-binding.md) (the native C binding).
- [`docs/invariants.md`](docs/invariants.md) — register of cross-module invariants (what's load-bearing across files) + the fail-loud check policy.
- [`docs/review/register.md`](docs/review/register.md) — the review register: open findings, settled decisions, refuted proposals (do-not-re-propose), and the review history table; the dated ledgers beside it carry the evidence the table points at.
- [`docs/plans/`](docs/plans/) — the architecture decision record ([`2026-08-authority-boundary-adr.md`](docs/plans/2026-08-authority-boundary-adr.md)), active coordination tracks, and in-flight design handoffs.
Expand Down
6 changes: 5 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ Rust edition 2024 / Axum API / SQLite (rusqlite, WAL) / EIP-712 signing / SSZ en
- `sequencer-core/` — shared domain types consumed by both sequencer and scheduler.
- `examples/app-core/` — placeholder wallet app implementing `Application`.
- `examples/wallet-sequencer/` — binary crate: wallet app + sequencer library.
- `bindings/c-app-engine/` — reusable native engine adapter implementing `Application` through a C ABI.
- `bindings/c-app-sequencer/` — optional C-engine CLI host and external-archive binary.
- `examples/c-wallet-engine/` — reference C ABI exports, genesis tool, and conformance tests.
- `examples/c-wallet-sequencer/` — binary composing the C-engine host with the reference wallet engine.
- `examples/canonical-app/` — on-chain scheduler reference implementation.
- `examples/canonical-test/` — e2e test harness for the canonical app.
- `sdk/rust-client/` — Rust client library for the sequencer API.
Expand All @@ -58,7 +62,7 @@ Rust edition 2024 / Axum API / SQLite (rusqlite, WAL) / EIP-712 signing / SSZ en
## Before You Start Real Work

- **[`AGENTS.md`](AGENTS.md)** — mission, requirements, invariants, duality, recovery, conventions, rules.
- **[`docs/protocol/`](docs/protocol/)** — the authoritative protocol contracts: [`scheduler-semantics.md`](docs/protocol/scheduler-semantics.md) (canonical acceptance algorithm) and [`application-contract.md`](docs/protocol/application-contract.md) (the `Application` FFI trait). Read before touching the scheduler, the gold frontier, the fold, or an `Application` impl.
- **[`docs/protocol/`](docs/protocol/)** — the authoritative protocol contracts: [`scheduler-semantics.md`](docs/protocol/scheduler-semantics.md) (canonical acceptance algorithm), [`application-contract.md`](docs/protocol/application-contract.md) (the `Application` trait), and [`c-application-binding.md`](docs/protocol/c-application-binding.md) (the native C binding). Read before touching the scheduler, the gold frontier, the fold, or an `Application` impl.
- **[`docs/invariants.md`](docs/invariants.md)** — cross-module invariants register + the fail-loud check policy. Check it before changing anything it lists as load-bearing.
- **[`docs/review/register.md`](docs/review/register.md)** — the review register: open findings, settled decisions, refuted proposals (do-not-re-propose). Check it for open findings in code you're about to touch, and before proposing a mechanism or simplification.
- **[`docs/plans/`](docs/plans/)** — the [authority-boundary ADR](docs/plans/2026-08-authority-boundary-adr.md), active coordination tracks, and in-flight design handoffs. Check before starting work that might belong to a track.
Expand Down
41 changes: 41 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ members = [
"sequencer",
"sequencer-core",
"sdk/rust-client",
"bindings/c-app-engine",
"bindings/c-app-sequencer",
"examples/app-core",
"examples/canonical-app",
"examples/canonical-test",
"examples/wallet-sequencer",
"examples/c-wallet-engine",
"examples/c-wallet-sequencer",
"tests/benchmarks",
"tests/harness",
"tests/e2e",
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,15 @@ released even on client disconnect.
- `sequencer/src/storage/`: schema, migrations, SQLite persistence (split per writer role), and replay reads
- `sequencer-core/src/`: shared domain types and interfaces (`Application`, `SignedUserOp`, `SequencedL2Tx`, feed message types)
- `examples/app-core/src/`: wallet prototype implementing `Application`
- [`bindings/c-app-engine/`](bindings/c-app-engine/README.md): reusable C ABI adapter and external static-archive integration guide
- `bindings/c-app-sequencer/`: optional C-engine CLI host and external-archive binary
- `examples/c-wallet-engine/`: reference wallet C ABI exports, genesis tool, and conformance tests
- `examples/c-wallet-sequencer/`: binary composing the C-engine host with the reference wallet engine
- `tests/benchmarks/`: benchmark harnesses and benchmark spec

Related docs:

- C application binding: [`docs/protocol/c-application-binding.md`](docs/protocol/c-application-binding.md)
- App snapshots (format + lifecycle): `docs/snapshots/`
- Watchdog — local dev: [`docs/watchdog/getting-started.md`](docs/watchdog/getting-started.md); Sepolia/mainnet: [`docs/watchdog/operator-deployment.md`](docs/watchdog/operator-deployment.md)

Expand Down
19 changes: 19 additions & 0 deletions bindings/c-app-engine/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "c-app-engine"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Application shim over a static engine library implementing the application-engine C API"
homepage.workspace = true
repository.workspace = true
readme = "README.md"
authors.workspace = true

[build-dependencies]
# Generates the FFI declarations from the engine header at build time. It decides how this host
# reads every record crossing the seam, so a bump changes the ABI interpretation.
bindgen = "0.72"

[dependencies]
sequencer-core = { path = "../../sequencer-core" }
alloy-primitives = { workspace = true }
109 changes: 109 additions & 0 deletions bindings/c-app-engine/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# C application bridge

The crates under `bindings/` are reusable integration libraries. The wallet
engine and binary under `examples/` demonstrate their use.

`EngineApp` implements `sequencer_core::application::Application` using the
[application-engine C ABI](include/application-engine.h). The sequencer owns one
engine at a time. A handle can move between threads; calls on it never overlap.
The bridge is `Send`, without `Clone` or `Sync`.
The [binding guide](../../docs/protocol/c-application-binding.md) maps the ABI
to the Application and scheduler contracts.

The native engine owns application state and its execution count/safe-block
clock. Successful execution advances that progress, including counted no-ops;
protocol rejection leaves it unchanged. The shared Rust execution functions
check these transitions. Fatal validation, execution, or output-drain failures
return `AppError`; callers must discard that instance. Exceptions must not cross
the C ABI.

`NOT_FOUND` and `INVALID_DUMP` retain the distinction between missing/corrupt
checkpoint artifacts and other operational `IO_ERROR` failures. Error strings
are diagnostics and never determine classification. The engine and generated
bindings must use the same header, including these status declarations.

A dump prefix may be a file or a directory. Opening it produces independently
mutable state without changing the source; checkpoint creation may mutate the
engine's backing arrangement, while preserving logical state and progress.
Successful checkpoints are durable and immutable under subsequent execution.
All checkpoint artifacts reside at or below the prefix; the sequencer disposes
of them with ordinary recursive filesystem deletion. Restored engines remain
usable after source deletion.
`state_file_in_dump` names the one canonical comparison file, which can be the
whole dump or a projection alongside richer restoration artifacts. `EngineApp`
does not implement the optional Rust `CanonicalState` inspection trait.

## Reference wallet

The reference engine exports the Rust wallet through actual `extern "C"`
functions. Its static archive is also usable by the generic host. In the
repository's development shell:

```sh
cargo run -p c-wallet-engine --bin c-wallet-genesis -- /tmp/wallet-genesis devnet
cargo run -p c-wallet-sequencer -- --state-file /tmp/wallet-genesis setup
cargo run -p c-wallet-sequencer -- run
cargo test -p c-wallet-engine --test conformance
```

The ordinary setup/run environment configuration is still required. The genesis
path is required only when plain `setup` needs its first snapshot; completed
setup, warm startup, `flush-mempool`, and `setup --recovery` use the sequencer's
durable checkpoints.

The host adds `--state-file` through its own parser and passes the parsed command
to `sequencer::run_command`. This shares `run_main`'s command lifecycle and exit
policy. Both take a lazy `FnOnce() -> Result<A, AppError>` genesis factory;
infallible Rust constructors therefore use
`run_main(|| Ok(WalletApp::new(WalletConfig::default())))`. An absent required
genesis path or a missing/corrupt genesis dump is a terminal bootstrap error;
operational I/O failures retain their retryable classification. A caught factory
panic follows the shared terminal-error policy.

## External engine

Build the application's static archive against the header from the chosen
sequencer revision. From a checkout of that revision, build the generic host
with that same header:

```sh
APPLICATION_ENGINE_LIB=/absolute/path/libengine.a \
APPLICATION_ENGINE_HEADER=/absolute/path/application-engine.h \
cargo build -p c-app-sequencer
```

The linked engine reports its stable payload bound through
`application_engine_max_method_payload_bytes()`; zero permits only empty method
payloads. Bindgen generates the Rust records from the header, so a build needs
libclang. The engine also supplies its own genesis tool; configuration does not
cross this ABI. With no external archive configured, the generic binary reports
that no engine was linked, and
`c-wallet-sequencer` supplies the reference implementation through Cargo.

For a binary in another repository, depend on the host directly. Replace
`<full-commit-hash>` with the sequencer revision whose header the engine uses:

```toml
[dependencies]
c-app-sequencer = { git = "https://github.com/cartesi/sequencer", rev = "<full-commit-hash>" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

```rust
#[tokio::main]
async fn main() -> std::process::ExitCode {
c_app_sequencer::run().await
}
```

Set the same `APPLICATION_ENGINE_LIB` and `APPLICATION_ENGINE_HEADER` variables
when running `cargo build` in that binary's repository. The host's `run()` owns
CLI parsing and tracing setup. For custom host wiring, depend on `c-app-engine`
and `sequencer` at the same Git revision and compose `EngineApp` with
`sequencer::run_command` directly. No wallet crate is required in either case.

The conformance suite compares native and ABI execution over mixed inputs,
notices and vouchers, rejection/no-op progress, dump round trips, independent
instances, and fatal/error classification.
`cargo test -p c-app-engine --lib` also checks mixed-output ordering, copying
reused engine buffers, and full-width voucher values with a small ABI fixture.
Loading