Architecture
How Rome's components fit together — EVM execution inside a Solana program.
Rome embeds an EVM bytecode interpreter inside a Solana on-chain program. Users talk to the Rome Proxy over standard Ethereum JSON-RPC, and the proxy submits their transactions straight to the Rome EVM program on Solana. There is no separate execution layer to keep in sync — EVM state is Solana state.
System overview
Components
Rome EVM Program (on-chain)
The core of Rome — a Solana BPF program containing a full EVM bytecode interpreter (a fork of SputnikVM). It:
Receives serialized EVM transactions as Solana instructions
Executes Solidity bytecode inside the Solana runtime
Maps each Ethereum address (H160) to a Solana PDA
Exposes precompiles for calling into Solana (CPI, System, Helper, Withdraw) alongside the standard Ethereum precompiles
Stores EVM state (balances, nonce, code, storage) as Solana account data
Rome Proxy (JSON-RPC server)
A standard Ethereum JSON-RPC server on port 9090 — the entry point for the public chains. It translates Ethereum API calls into Solana activity:
eth_sendRawTransaction→ serialize the EVM tx → submit a Solana instructioneth_call→ emulate execution off-chain via the Mollusk SVM emulatoreth_estimateGas→ simulate for gas estimationeth_getBalance,eth_getCode,eth_getBlockByNumber, receipts, logs → served from indexed state
It also exposes Rome extensions: rome_emulateTx, rome_emulateRegRollup, rome_mintId, rome_buildInfo, rome_getResources, and more.
Hercules (indexer)
Watches the Rome EVM program on Solana and reconstructs Ethereum-compatible blocks — transactions, receipts, logs, and state changes — backed by PostgreSQL. On the public chains it runs in slot-aligned mode, so a block number maps to a Solana slot and the same slot yields the same block on any indexer. The proxy serves these blocks to wallets and explorers.
Precompiles
Rome implements the standard Ethereum precompiles (ecrecover, SHA-256, RIPEMD-160, identity, modexp, the BN254 curve operations, blake2f) with mainnet-equivalent semantics, plus non-EVM precompiles that reach into Solana: CpiProgram (0xFF…08, arbitrary CPI), System (0xFF…07, PDA derivation and base58 helpers), HelperProgram (0xFF…09, ATA/PDA creation, SPL transfers, gas↔lamports), and Withdraw (0x42…16). See the Contract Addresses reference for the full table.
Execution modes
Rome executes an EVM transaction in one of two ways:
Atomic (VmAt)
A single Solana transaction. The whole EVM transaction executes within one Solana transaction's compute budget (~1.4M compute units). Used for most operations — transfers, ordinary contract calls, swaps.
Iterative (VmIt)
For work that exceeds a single transaction's budget. Execution is split across multiple Solana transactions:
Each step (a Solana transaction) runs as many EVM opcodes as fit in its compute budget — the step size is adaptive, not fixed
VM state is Borsh-serialized into a
StateHolderaccount between stepsAccounts are TTL-locked for a few seconds during execution
Used for heavy operations such as BN254 pairing
Account mapping
Every Ethereum address maps deterministically to a Solana PDA derived from the chain ID and the address under the Rome EVM program. That PDA owns the account's balance (as SPL token accounts), contract code, storage slots, and nonce — all as Solana account data.
Holder accounts
Solana transactions are capped at 1,232 bytes, but EVM transactions (especially contract deployments) can be much larger. Rome stages large transactions into holder accounts: the transaction is split into chunks written sequentially into a holder (up to 80 KB), then assembled and executed on-chain. The Rome SDK manages this transparently.
Gas and pricing
Each chain has its own gas token — any SPL token. Gas pricing reads a Meteora DAMM pool (v1 or v2, configurable) to convert between the gas token and SOL for the underlying Solana transaction fees.
What's next
Networks — connect to Martius or Hadrian
Quickstart — deploy your first contract
Execution Model — atomic vs iterative execution in depth
Last updated
Was this helpful?