Execution Model

Rome EVM executes Solidity bytecode inside a Solana on-chain program. This page explains how EVM transactions are processed.

Transaction Lifecycle

1. User signs EVM transaction (MetaMask / ethers.js)

2. Rome Proxy receives via eth_sendRawTransaction

3. Proxy emulates transaction off-chain (Mollusk SVM emulator)
   → Estimates gas, checks atomicity, identifies required accounts

4. Proxy wraps EVM tx as Solana instruction(s)
   → If tx fits in one Solana tx → Atomic (VmAt)
   → If tx exceeds CU budget → Iterative (VmIt)

5. Solana validator executes the instruction(s)
   → Rome EVM program interprets EVM bytecode
   → CPI calls to other Solana programs (if any)

6. State changes committed to Solana accounts

7. Hercules indexes the event → produces EVM block

Atomic Execution (VmAt)

The default mode. The entire EVM transaction executes within a single Solana transaction.

State machine: Lock → Init → Execute → Commit → GasTransfer → Exit

Properties:

  • All-or-nothing execution — if any step fails, the entire transaction reverts

  • ~1.4M compute units available per Solana transaction

  • Suitable for transfers, simple contract calls, swaps, most DeFi operations

  • Sub-second finality (Solana block time)

When used: Automatically selected when the emulator determines the transaction fits within a single Solana transaction's compute budget.

Iterative Execution (VmIt)

For compute-intensive operations that exceed a single transaction's budget. The EVM execution is split across multiple Solana transactions.

How it works:

  1. Each step executes approximately 500 EVM opcodes

  2. After each step, the VM state is serialized (Borsh format) into a StateHolder account

  3. The next step deserializes state and continues execution

  4. Accounts involved are TTL-locked for 3-4 seconds during multi-step execution

State machine: FromStateHolder → Lock → Init → Execute → Serialize → NextIteration → ... → Completed

Account locking:

  • RoLock (shared read-only) — Multiple iterative transactions can hold simultaneously

  • RwLock (exclusive write) — Only one transaction can modify an account at a time

  • TTL: 3 seconds (standard), 4 seconds (when using Address Lookup Tables)

When used: BN254 pairing verification, large contract deployments, deep call stacks, any operation exceeding ~1.4M CU.

Emulation

Before submitting a transaction to Solana, the Proxy emulates it off-chain using the Mollusk SVM emulator. This:

  1. Estimates gas consumption

  2. Determines if atomic or iterative mode is needed

  3. Identifies all Solana accounts the transaction will touch

  4. Validates the transaction won't fail on-chain

The emulator executes the same EVM logic as the on-chain program — the entrypoint! macro ensures identical dispatch tables in both the program and emulator codebases.

Mollusk SVM can also execute arbitrary Solana BPF programs during emulation, which means eth_call and eth_estimateGas correctly handle CPI calls to SPL Token, Jupiter, Kamino, etc.

Account Mapping

Every Ethereum address maps to a Solana PDA:

Account types stored on-chain:

Type
Seeds
Purpose

Balance

[chain, "ACCOUN_SEED", H160, bump]

Nonce, balance, contract code

Storage

[chain, "STORAGE", H160, slot_index, bump]

Contract storage (256 slots per account)

TxHolder

[signer, "TX_HOLDER_SEED", index, bump]

Staged transaction data (max 80 KB)

StateHolder

[signer, "STATE_HOLDER_SEED", index, bump]

Serialized VM state between iterations

Holder Accounts

Solana transactions are limited to 1,232 bytes. EVM transactions — especially contract deployments — can be much larger.

Splitting mechanism:

  1. The SDK splits the RLP-encoded transaction into chunks

  2. Each chunk is written to a TxHolder account via TransmitTx instructions

  3. Once all chunks are staged, a DoTxHolder instruction assembles and executes the full transaction

  4. Maximum holder size: 80 KB per TxHolder

This is completely transparent to the developer — the Rome SDK handles splitting and reassembly automatically.

Supported Transaction Types

Type
EIP
Description

Legacy

Traditional Ethereum transactions

Access List

EIP-2930

Optimized state access patterns

Dynamic Fee

EIP-1559

Base fee + priority fee

Deposit

Type 0x7E

L2 deposit transactions (sequencer-initiated)

Journaled State

Rome EVM uses a journaled state model for managing state changes during execution:

  • All changes (nonce, balance, storage, code) are tracked in a Journal

  • Nested CALL/CREATE operations push snapshot frames

  • On revert: journal entries roll back to the snapshot

  • On success: changes are committed to Solana accounts

  • Non-EVM CPI instructions execute immediately (Solana's own atomicity guarantees correctness)

What's Next

Last updated

Was this helpful?