> For the complete documentation index, see [llms.txt](https://docs.rome.builders/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rome.builders/core-concepts/execution-model.md).

# Execution Model

How Rome EVM processes Ethereum transactions on Solana — proxy emulation, atomic (VmAt) vs. iterative (VmIt) modes, and the full transaction lifecycle.

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 (a Solana transaction) executes **as many EVM opcodes as fit in its compute budget** — an adaptive step size, not a fixed count
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; a session is capped at **160 steps**; past that, the next step releases the session's locks and ends it without committing anything

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

**Account locking:**

* One **exclusive lock** per managed account (balance and storage accounts) — only one iterative session can hold an account at a time; an atomic transaction that writes a locked account is refused with `AccountLocked` until the lock lapses, and the client resends
* **TTL:** 3 seconds, renewed every step (4 seconds when the session touches more than 28 accounts)
* **Legacy-track CPIs are refused** inside an iterative transaction (`CpiProhibitedInIterativeTx`); cached-track effects are staged and committed at the end

**When used:** large contract deployments, deep call stacks, any operation exceeding \~1.4M CU. A BN254 pairing check on its own does not need it; see [Compute Budget](/core-concepts/compute-budget.md).

## 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:

```
Ethereum address (H160, 20 bytes)
    ↓
PDA = findProgramAddress(
    [chain_id, "ACCOUN_SEED", H160, bump],
    ROME_EVM_PROGRAM_ID
)
    ↓
Solana account (Pubkey, 32 bytes)
```

**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

Rome sends Solana **v1 transactions**, which are limited to 4 KB (4,096 bytes) and 64 addresses. 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                                                                                                                                                                             |
| Unsigned EIP-1559 | —         | A `0x02`-typed body with no secp256k1 signature, authorised by a Solana wallet's Ed25519 signature instead (the Solana lane; see [Call EVM from Solana](/developer-guides/call-evm-from-solana.md)) |
| Deposit           | Type 0x7E | Deposit transactions, e.g. bridge inbound settlement                                                                                                                                                |

## 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

* [Compute Budget](/core-concepts/compute-budget.md) — CU costs and optimization strategies
* [Constraints](/core-concepts/constraints.md) — important limits and boundaries


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.rome.builders/core-concepts/execution-model.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
