A provable execution environment that executes transactions, generates state transitions, and produces zero-knowledge proofs using Risc0 zkVM.
- Core Processor: Handles transfers, contract calls, and contract creation
- State Management: Sparse Merkle Tree backed by RocksDB
- zkVM Integration:
- Execute: Processes transaction batches
- Prove: Generates execution witnesses and ZK proofs
- Verify: Commits public outputs (State Root, Gas Used, etc.)
- Integration Interfaces:
- Sequencer:
Batchstructure for input - Submitter:
SubmitterPayloadfor L1/DA output
- Sequencer:
cd executor
cargo build --releaseThe project has comprehensive test coverage (89 tests passing):
cargo test- Unit Tests: Core logic, state, proofs
- Integration Tests: End-to-end execution flows
- Interface Tests: Sequencer/Submitter integration
Serialize your transactions into a Batch and send to the Executor.
use executor::{Batch, Transaction};
// 1. Create a batch
let batch = Batch::new(id, timestamp, vec![/* transactions */]);
// 2. Serialize and send to Executor
let bytes = batch.to_bytes()?;Receive SubmitterPayload from the Executor and push to L1/DA.
use executor::SubmitterPayload;
// 1. Deserialize payload
let payload: SubmitterPayload = bincode::deserialize(&received_bytes)?;
// 2. Extract Data
let proof_data = payload.proof; // -> Verify on L1
let public_io = payload.journal; // -> Public Outputs (Root, BlockNum)
let da_data = payload.batch_data; // -> Store on Celestia/BlobstreamThe Sequencer must provide data matching these Rust structures:
Batch (The Input Container)
struct Batch {
id: u64, // Unique Batch ID
timestamp: u64, // UNIX Timestamp
transactions: Vec<Transaction>,
}Transaction Types
enum Transaction {
Transfer(TransferTx),
ContractCall(ContractCallTx),
ContractCreate(ContractCreateTx),
}
struct TransferTx {
from: [u8; 20], // Sender Address
to: [u8; 20], // Receiver Address
value: [u8; 32], // Amount (Big-Endian U256)
nonce: u64, // Account Nonce
signature: Vec<u8>, // 65-byte ECDSA Signature
}
struct ContractCallTx {
caller: [u8; 20],
contract: [u8; 20],
calldata: Vec<u8>, // Function Selector + Args
value: [u8; 32],
gas_limit: u64,
nonce: u64,
signature: Vec<u8>,
}The Executor produces data matching this Rust structure for the Submitter:
SubmitterPayload ( The Output Container)
struct SubmitterPayload {
proof: Vec<u8>, // ZK Proof (Opaque bytes)
journal: Vec<u8>, // Public Outputs (64 bytes)
batch_data: Vec<u8>, // Raw Batch Data (for DA)
block_number: u64, // Block Height
tx_count: u64, // Transaction Count
}The journal (64 bytes) verifies the execution correctness:
| Offset | Field | Type | Description |
|---|---|---|---|
| 0 | post_state_root |
[u8; 32] | Final Merkle State Root |
| 32 | block_number |
u64 | Block Height |
| 40 | transaction_count |
u64 | Total Transactions |
| 48 | total_gas_used |
u64 | Total Gas Consumed |
| 56 | successful_txs |
u64 | Txs with Status::Success |
use executor::{Database, StateManager, Processor, ProofGenerator, PublicOutputs};
fn main() -> anyhow::Result<()> {
// 1. Setup
let db = Database::new("./data")?;
let state = StateManager::new(db);
let mut processor = Processor::new(state);
// 2. Execute Transactions
// ... (load txs from batch) ...
let witness = processor.generate_witness(&txs, block_num, timestamp)?;
// 3. Generate Proof
let generator = ProofGenerator::new();
let (journal, proof) = generator.generate_proof(&witness)?;
// 4. Verify & Commit
let outputs = PublicOutputs::from_journal(&journal)?;
println!("New State Root: {:?}", outputs.post_state_root);
Ok(())
}src/core: Transaction types, Batch structsrc/state: Database, Merkle Tree, State Managersrc/executor: Transaction validation and execution logicsrc/proof: Witness generation, Host program, Submitter payloadmethods/guest: The zkVM guest program (runs inside ZK circuit)
MIT