|
1 |
| -# Architecture |
| 1 | +# Go Execution EVM |
| 2 | + |
| 3 | +This repository implements the `execution.Executor` interface from `github.com/rollkit/rollkit/core/execution` (currently on feature branch `feature/exec_api`). It provides a pure Engine API-based execution client for Rollkit. |
| 4 | + |
| 5 | +## PureEngineClient Implementation |
| 6 | + |
| 7 | +The `PureEngineClient` is a 100% Engine API compatible implementation of the `execution.Executor` interface. It connects to an Ethereum execution client (like Reth) and uses both the Engine API and standard Ethereum JSON-RPC API to execute transactions. |
| 8 | + |
| 9 | +### Genesis and initial height |
| 10 | + |
| 11 | +In the context of the EVM, the genesis block is designated as a unique block with the block number `0`. |
| 12 | +To ensure compatibility with both rollkit and the EVM, the only permissible initial height is `1`. |
| 13 | +During `InitChain` EVM genesis block is acknowledged (at height 0), and empty block is created (at height 1). |
| 14 | +This approach ensures that the block numbers between the EVM and rollkit remain consistent and synchronized. |
| 15 | + |
| 16 | +### Genesis Requirements |
| 17 | + |
| 18 | +Since the `PureEngineClient` relies on the Engine API, the genesis configuration must properly enable it with the correct hardfork settings: |
| 19 | + |
| 20 | +1. The genesis file must include post-merge hardfork configurations |
| 21 | +2. `terminalTotalDifficulty` must be set to 0 |
| 22 | +3. `terminalTotalDifficultyPassed` must be set to true |
| 23 | +4. Hardforks like `mergeNetsplitBlock`, `shanghaiTime`, and `cancunTime` should be properly configured |
| 24 | + |
| 25 | +Example of required genesis configuration: |
| 26 | + |
| 27 | +```json |
| 28 | +{ |
| 29 | + "config": { |
| 30 | + "chainId": 1234, |
| 31 | + "homesteadBlock": 0, |
| 32 | + "eip150Block": 0, |
| 33 | + "eip155Block": 0, |
| 34 | + "eip158Block": 0, |
| 35 | + "byzantiumBlock": 0, |
| 36 | + "constantinopleBlock": 0, |
| 37 | + "petersburgBlock": 0, |
| 38 | + "istanbulBlock": 0, |
| 39 | + "berlinBlock": 0, |
| 40 | + "londonBlock": 0, |
| 41 | + "mergeNetsplitBlock": 0, |
| 42 | + "terminalTotalDifficulty": 0, |
| 43 | + "terminalTotalDifficultyPassed": true, |
| 44 | + "shanghaiTime": 0, |
| 45 | + "cancunTime": 0 |
| 46 | + } |
| 47 | +} |
| 48 | +``` |
2 | 49 |
|
3 |
| -```mermaid |
4 |
| -graph LR |
5 |
| - subgraph Test Environment |
6 |
| - TestClient[Test Client] |
7 |
| - MockExecutor[Mock Executor] |
8 |
| - end |
| 50 | +Without these settings, the Engine API will not be available, and the `PureEngineClient` will not function correctly. |
9 | 51 |
|
10 |
| - subgraph Execution Client |
11 |
| - EngineAPIExecutionClient |
12 |
| - subgraph Client Components |
13 |
| - EthClient[Eth Client] |
14 |
| - JsonRpcClient[JSON-RPC Client] |
15 |
| - end |
16 |
| - end |
| 52 | +### PayloadID Storage |
17 | 53 |
|
18 |
| - subgraph Execution Layer |
19 |
| - Reth[Reth Node] |
20 |
| - subgraph Reth APIs |
21 |
| - EngineAPI[Engine API] |
22 |
| - JsonRPC[JSON-RPC API] |
23 |
| - end |
24 |
| - end |
| 54 | +The `PureEngineClient` maintains the `payloadID` between calls: |
25 | 55 |
|
26 |
| - %% Test Environment Connections |
27 |
| - TestClient -->|uses| EngineAPIExecutionClient |
28 |
| - JsonRpcClient -->|test mode| MockExecutor |
29 |
| -
|
30 |
| - %% Execution Client Connections |
31 |
| - EngineAPIExecutionClient -->|eth calls| EthClient |
32 |
| - EngineAPIExecutionClient -->|engine calls| JsonRpcClient |
33 |
| - EthClient -->|eth/net/web3| JsonRPC |
34 |
| - JsonRpcClient -->|engine api| EngineAPI |
35 |
| -
|
36 |
| - %% Reth Internal Connections |
37 |
| - JsonRPC -->|internal| Reth |
38 |
| - EngineAPI -->|internal| Reth |
39 |
| -
|
40 |
| - %% Styling |
41 |
| - classDef primary fill:#f9f,stroke:#333,stroke-width:2px |
42 |
| - classDef secondary fill:#bbf,stroke:#333,stroke-width:1px |
43 |
| - class EngineAPIExecutionClient primary |
44 |
| - class EthClient,JsonRpcClient,MockExecutor,EngineAPI,JsonRPC secondary |
45 |
| -``` |
| 56 | +1. During `InitChain`, a payload ID is obtained from the Engine API via `engine_forkchoiceUpdatedV3` |
| 57 | +2. This payload ID is stored in the client instance as `c.payloadID` |
| 58 | +3. The stored payload ID is used in subsequent calls to `GetTxs` to retrieve the current execution payload |
| 59 | +4. After each `ExecuteTxs` call, a new payload ID is obtained and stored for the next block |
46 | 60 |
|
47 |
| -The architecture consists of several key components: |
| 61 | +### Payload as First Transaction |
48 | 62 |
|
49 |
| -1. **Execution Client** |
| 63 | +The `PureEngineClient` implements a unique approach to transaction execution: |
50 | 64 |
|
51 |
| - - `EngineAPIExecutionClient`: Main client interface that implements the Execute interface |
52 |
| - - `EthClient`: Handles standard Ethereum JSON-RPC calls |
53 |
| - - `JsonRpcClient`: Handles Engine API calls |
| 65 | +1. In `GetTxs`, the entire execution payload is serialized to JSON and returned as the first transaction |
| 66 | +2. In `ExecuteTxs`, this first transaction is deserialized back into an execution payload |
| 67 | +3. The remaining transactions are added to the payload's transaction list |
| 68 | +4. The complete payload is then submitted to the execution client via `engine_newPayloadV3` |
54 | 69 |
|
55 |
| -2. **Execution Layer** |
| 70 | +This approach ensures that: |
56 | 71 |
|
57 |
| - - `Reth Node`: Ethereum execution client |
58 |
| - - Exposes Engine API and standard JSON-RPC endpoints |
| 72 | +- The execution payload structure is preserved between calls |
| 73 | +- All execution happens within the EVM |
| 74 | +- It's not possible to create a payload outside of the EVM |
| 75 | +- Transactions cannot be selected or ordered outside of the EVM |
59 | 76 |
|
60 |
| -3. **Test Environment** |
61 |
| - - `Test Client`: Integration tests |
62 |
| - - `Mock Executor`: Simulates execution behavior for unit tests |
| 77 | +### How Eth API is Used |
63 | 78 |
|
64 |
| -## Development |
| 79 | +The `PureEngineClient` uses the standard Ethereum JSON-RPC API for: |
65 | 80 |
|
66 |
| -Run RETH in docker: |
| 81 | +1. Retrieving block information (via `HeaderByNumber`) |
| 82 | +2. Reading the genesis block hash and state root |
| 83 | +3. Getting gas limits and other block parameters |
67 | 84 |
|
68 |
| -```bash |
69 |
| -cd docker |
70 |
| -docker compose up -d |
71 |
| -``` |
| 85 | +This allows the client to interact with the execution layer for read operations while using the Engine API for write operations. |
72 | 86 |
|
73 |
| -Compile `evm-middleware` binary: |
| 87 | +## Deployment Architecture |
| 88 | + |
| 89 | +```mermaid |
| 90 | +graph LR |
| 91 | + subgraph Rollkit Binary |
| 92 | + RollkitCore[Rollkit Core] |
| 93 | + PureEngineClient[PureEngineClient] |
| 94 | + end |
| 95 | +
|
| 96 | + %% Connections |
| 97 | + RollkitCore --> PureEngineClient |
| 98 | + PureEngineClient -->|Engine API| Reth |
| 99 | + PureEngineClient -->|Eth API| Reth |
74 | 100 |
|
75 |
| -```bash |
76 |
| -make build |
77 | 101 | ```
|
78 | 102 |
|
79 |
| -Run `evm-middleware` binary: |
| 103 | +## Development and Testing |
| 104 | + |
| 105 | +### Running Reth in Docker |
80 | 106 |
|
81 | 107 | ```bash
|
82 |
| -./build/evm-middleware run --jwt-secret $(cat docker/jwttoken/jwt.hex) |
| 108 | +cd docker |
| 109 | +docker compose up -d |
83 | 110 | ```
|
84 | 111 |
|
85 |
| -Compile rollkit from `feature/exec_api` branch and run it: |
| 112 | +### Reading Genesis Information |
| 113 | + |
| 114 | +If you've modified the genesis file, you can read the genesis hash and state root using the Ethereum JSON-RPC API: |
86 | 115 |
|
87 | 116 | ```bash
|
88 |
| -git checkout feature/exec_api |
89 |
| -go build ./cmd/rollkit |
90 |
| -./rollkit start |
| 117 | +# Get genesis block hash |
| 118 | +curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' http://localhost:8545 | jq -r '.result.hash' |
| 119 | + |
| 120 | +# Get genesis state root |
| 121 | +curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' http://localhost:8545 | jq -r '.result.stateRoot' |
91 | 122 | ```
|
0 commit comments