- Overview
- Project Structure
- Requirements
- Usage
- Building and Running the Sample application
- Testing
- License
This repository provides Rust bindings for the Cartesi machine guest library (libcmt). The bindings expose libcmt’s C API (rollup I/O, ABI, Merkle trees, buffers, etc.) for utilization in rust applications. This would serve as an alternative to the HttpServer and offer methods to manage a Cartesi application instance.
The repo includes:
- Library:
libcmt-binding-rust— the main crate (FFI bindings and Rust wrappers and helpers). - Sample apps:
echo_app(handles asset deposit and voucher emission) andapp_template(minimal starter). - Cartesi config:
cartesi.echoApp.tomlandbuild/Dockerfile.echoAppfor building and running the echo app in the Cartesi machine. - Test Instance:
/testsUtilizes cartesapp to test the sample application which uses the libcmt-rust-bindings.
libcmt-binding-rust/
├── src/ # Library source (bindings + Rust API)
│ ├── lib.rs
│ ├── abi.rs
│ ├── buf.rs
│ ├── io.rs
│ ├── keccak.rs
│ ├── merkle.rs
│ ├── rollup.rs
│ └── util.rs
├── build.rs # bindgen build script (wrapper.h → bindings)
├── wrapper.h # C header include for bindgen
├── Cargo.toml # Library crate
├── cartesi.echoApp.toml # Cartesi config for echo app
├── build/
│ └── Dockerfile.echoApp # Multi-stage Dockerfile (echo app)
├── sample_apps/
│ ├── echo_app/ # Echo dApp (emits a voucher for all asset deposit)
│ │ ├── src/main.rs
│ │ ├── Cargo.toml
│ │ ├── cartesi.toml
│ │ └── tests/
│ └── app_template/ # Minimal app template
├── tests/ # Integration tests (Python, cartesapp)
│ ├── model.py
│ └── test_echo.py
└── third_party/
└── machine-guest-tools # Cartesi libcmt (submodule)
- Rust (stable) — to build the library and sample apps.
- Clang / libclang-dev — for
bindgen(used inbuild.rs). - Git — managing
third_party/machine-guest-tools(Submodule containing C headers and libcmt). - Docker — for building the RISC-V image and running the Cartesi machine.
- Python 3.12+ — for the test suite (cartesapp).
Modify your projects Cargo.toml file to include:
[dependencies]
libcmt-binding-rust = { git = "https://github.com/Mugen-Builders/libcmt-binding-rust.git", tag = "v0.1.0" }Then import and use the rollup API in your Rust code.
The following snippets show how to use the libcmt Rust bindings. A more detailed use can be found on the echo app.
Creating a rollup and main request loop:
use libcmt_binding_rust::rollup::{Rollup, Advance, Inspect};
use libcmt_binding_rust::cmt_rollup_finish_t;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut accept_previous_request = true;
let mut rollup = Rollup::new()?;
loop {
let mut finish = cmt_rollup_finish_t {
accept_previous_request,
next_request_type: 0,
next_request_payload_length: 0,
};
rollup.finish(&mut finish)?;
accept_previous_request = match finish.next_request_type {
0 => handle_advance(&mut rollup).await?,
1 => handle_inspect(&mut rollup).await?,
_ => false,
};
}
}Handling an advance request (read input, optionally emit voucher/notice):
async fn handle_advance(rollup: &mut Rollup) -> Result<bool, Box<dyn std::error::Error>> {
let advance = rollup.read_advance_state()?;
let payload = advance.payload; // hex string, e.g. "0x..."
let msg_sender = advance.msg_sender; // 20-byte address (hex)
let app_contract = advance.app_contract;
rollup.emit_notice(&payload)?; // emit notice (payload in hex)
// or
rollup.emit_voucher(&target_address, Some("0x0"), &calldata_hex)?;
Ok(true) // accept this advance
}Handling an inspect request (read-only query):
async fn handle_inspect(rollup: &mut Rollup) -> Result<bool, Box<dyn std::error::Error>> {
let inspect = rollup.read_inspect_state()?;
let payload = inspect.payload; // hex string
// Optional: emit a report (only output allowed for inspect)
rollup.emit_report(&payload)?;
Ok(true)
}Emitting a notice (data that can be validated on-chain):
// payload_hex: hex-encoded bytes, e.g. "0x48656c6c6f"
rollup.emit_notice("0x48656c6c6f")?;Emitting a voucher (transaction to be executed on L1):
// address_hex: 20-byte destination (40 hex chars), e.g. "0x..."
// value_hex: optional ETH value, e.g. Some("0xde0b6b3a7640000") or None
// payload_hex: calldata (hex)
rollup.emit_voucher(
"0xc70076a466789B595b50959cdc261227F0D70051",
Some("0xde0b6b3a7640000"),
"0x...",
)?;Emitting a report (log; not validated on-chain):
rollup.emit_report("0x7265706f7274")?;Config is in cartesi.echoApp.toml; the root filesystem is built from build/Dockerfile.echoApp.
Build the machine image (RISC-V):
cartesi build -c "./cartesi.echoApp.toml"Run the Cartesi machine:
cartesi runThis starts the rollup node with the echo app; you can then send deposits, advances and inspect requests to the application.
Tests are written in Python using cartesapp and run inside the Cartesi machine.
Prerequisites: Python 3.12+, virtualenv with cartesapp installed (see Installation).
Run tests (with Cartesi machine emulator):
. .venv/bin/activate
pip3 install cartesapp[dev]@git+https://github.com/prototyp3-dev/cartesapp@v1.2.1
cartesapp test --config-file "./cartesi.echoApp.toml" --log-level debug --cartesi-machineThis builds, starts the machine, and runs the test client.
Run tests (pytest only, if you have a running node):
Test modules live in tests/ (e.g. test_echo.py, model.py) and in sample_apps/echo_app/tests/.
See LICENSE.
