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

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

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

* [Compute Budget](/core-concepts/compute-budget.md) — CU costs and optimization strategies
* [Constraints](/core-concepts/constraints.md) — important limits and boundaries
* [Transaction Lifecycle](https://github.com/rome-protocol/docs/blob/main/core-concepts/transaction-lifecycle.md) — detailed step-by-step walkthrough


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

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

The question should be specific, self-contained, and written in natural language.
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.
