Skip to content
This repository was archived by the owner on May 30, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2f4675e
test: run common test suite
tzdybal Feb 21, 2025
cf0b8e1
wip
tzdybal Feb 22, 2025
57990ab
feat: update TxInjector
tzdybal Feb 27, 2025
bbed286
build(deps): update go-execution dependency to latest version
tzdybal Mar 3, 2025
c5ed01e
feat: new Engine API approach
tzdybal Mar 6, 2025
69a9f83
feat: engine API that kind of works...
tzdybal Mar 7, 2025
b91579e
THIS WORKS! IT WAS GENESIS FILE ALL THE TIME!
tzdybal Mar 11, 2025
de358c3
refactor: clean up test and engine code, improve block validation checks
tzdybal Mar 11, 2025
0aa51fc
feat: enhance PureEngineClient with block retrieval and finalization
tzdybal Mar 11, 2025
f1271d1
refactor: clean up test and engine code, improve block validation checks
tzdybal Mar 11, 2025
691bd93
refactor: consolidate code in eexecution*.go files
tzdybal Mar 11, 2025
da82f20
refactor: restructure execution code and enhance testing framework
tzdybal Mar 15, 2025
b3fb10b
chore: fix linter errors
tzdybal Mar 15, 2025
80c017c
refactor: update execution tests and docker-compose configuration
tzdybal Mar 15, 2025
c6fb37e
docs: update README to reflect PureEngineClient implementation and usage
tzdybal Mar 15, 2025
ab9ef42
docs: enhance README with detailed genesis configuration for PureEngi…
tzdybal Mar 15, 2025
8f09ce6
fix: update transaction timestamp handling in execution logic
tzdybal Mar 15, 2025
19b1de2
feat: improve initial block handling, for rollkit compatibility
tzdybal Mar 19, 2025
79ebf16
fix: handle rollkit restarts
tzdybal Mar 19, 2025
c04c697
test: add manual transaction submission test for Ethereum client
tzdybal Mar 19, 2025
6987498
chore: fix CI
tzdybal Mar 21, 2025
b5deaaa
chore: Remove unused mock implementations in tests
tzdybal Mar 21, 2025
e4c0181
test: Fix loop condition in execution test to prevent overshooting
tzdybal Mar 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ help: Makefile
@sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /'
.PHONY: help

## build: build evm-middleware binary
build: build/evm-middleware
.PHONY: build

build/evm-middleware: cmd/evm-middleware/main.go execution.go go.mod go.sum
@echo "Building build/evm-middleware"
@go build -o build/evm-middleware ./cmd/evm-middleware

## clean: clean testcache
clean:
Expand Down Expand Up @@ -49,8 +42,6 @@ lint: vet
@golangci-lint run
@echo "--> Running markdownlint"
@markdownlint --config .markdownlint.yaml '**/*.md'
@echo "--> Running hadolint"
@hadolint docker/mockserv.Dockerfile
@echo "--> Running yamllint"
@yamllint --no-warnings . -c .yamllint.yml
@echo "--> Running actionlint"
Expand Down
165 changes: 98 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,91 +1,122 @@
# Architecture
# Go Execution EVM

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.

## PureEngineClient Implementation

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.

### Genesis and initial height

In the context of the EVM, the genesis block is designated as a unique block with the block number `0`.
To ensure compatibility with both rollkit and the EVM, the only permissible initial height is `1`.
During `InitChain` EVM genesis block is acknowledged (at height 0), and empty block is created (at height 1).
This approach ensures that the block numbers between the EVM and rollkit remain consistent and synchronized.

### Genesis Requirements

Since the `PureEngineClient` relies on the Engine API, the genesis configuration must properly enable it with the correct hardfork settings:

1. The genesis file must include post-merge hardfork configurations
2. `terminalTotalDifficulty` must be set to 0
3. `terminalTotalDifficultyPassed` must be set to true
4. Hardforks like `mergeNetsplitBlock`, `shanghaiTime`, and `cancunTime` should be properly configured

Example of required genesis configuration:

```json
{
"config": {
"chainId": 1234,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"mergeNetsplitBlock": 0,
"terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true,
"shanghaiTime": 0,
"cancunTime": 0
}
}
```

```mermaid
graph LR
subgraph Test Environment
TestClient[Test Client]
MockExecutor[Mock Executor]
end
Without these settings, the Engine API will not be available, and the `PureEngineClient` will not function correctly.

subgraph Execution Client
EngineAPIExecutionClient
subgraph Client Components
EthClient[Eth Client]
JsonRpcClient[JSON-RPC Client]
end
end
### PayloadID Storage

subgraph Execution Layer
Reth[Reth Node]
subgraph Reth APIs
EngineAPI[Engine API]
JsonRPC[JSON-RPC API]
end
end
The `PureEngineClient` maintains the `payloadID` between calls:

%% Test Environment Connections
TestClient -->|uses| EngineAPIExecutionClient
JsonRpcClient -->|test mode| MockExecutor

%% Execution Client Connections
EngineAPIExecutionClient -->|eth calls| EthClient
EngineAPIExecutionClient -->|engine calls| JsonRpcClient
EthClient -->|eth/net/web3| JsonRPC
JsonRpcClient -->|engine api| EngineAPI

%% Reth Internal Connections
JsonRPC -->|internal| Reth
EngineAPI -->|internal| Reth

%% Styling
classDef primary fill:#f9f,stroke:#333,stroke-width:2px
classDef secondary fill:#bbf,stroke:#333,stroke-width:1px
class EngineAPIExecutionClient primary
class EthClient,JsonRpcClient,MockExecutor,EngineAPI,JsonRPC secondary
```
1. During `InitChain`, a payload ID is obtained from the Engine API via `engine_forkchoiceUpdatedV3`
2. This payload ID is stored in the client instance as `c.payloadID`
3. The stored payload ID is used in subsequent calls to `GetTxs` to retrieve the current execution payload
4. After each `ExecuteTxs` call, a new payload ID is obtained and stored for the next block

The architecture consists of several key components:
### Payload as First Transaction

1. **Execution Client**
The `PureEngineClient` implements a unique approach to transaction execution:

- `EngineAPIExecutionClient`: Main client interface that implements the Execute interface
- `EthClient`: Handles standard Ethereum JSON-RPC calls
- `JsonRpcClient`: Handles Engine API calls
1. In `GetTxs`, the entire execution payload is serialized to JSON and returned as the first transaction
2. In `ExecuteTxs`, this first transaction is deserialized back into an execution payload
3. The remaining transactions are added to the payload's transaction list
4. The complete payload is then submitted to the execution client via `engine_newPayloadV3`

2. **Execution Layer**
This approach ensures that:

- `Reth Node`: Ethereum execution client
- Exposes Engine API and standard JSON-RPC endpoints
- The execution payload structure is preserved between calls
- All execution happens within the EVM
- It's not possible to create a payload outside of the EVM
- Transactions cannot be selected or ordered outside of the EVM

3. **Test Environment**
- `Test Client`: Integration tests
- `Mock Executor`: Simulates execution behavior for unit tests
### How Eth API is Used

## Development
The `PureEngineClient` uses the standard Ethereum JSON-RPC API for:

Run RETH in docker:
1. Retrieving block information (via `HeaderByNumber`)
2. Reading the genesis block hash and state root
3. Getting gas limits and other block parameters

```bash
cd docker
docker compose up -d
```
This allows the client to interact with the execution layer for read operations while using the Engine API for write operations.

Compile `evm-middleware` binary:
## Deployment Architecture

```mermaid
graph LR
subgraph Rollkit Binary
RollkitCore[Rollkit Core]
PureEngineClient[PureEngineClient]
end

%% Connections
RollkitCore --> PureEngineClient
PureEngineClient -->|Engine API| Reth
PureEngineClient -->|Eth API| Reth

```bash
make build
```

Run `evm-middleware` binary:
## Development and Testing

### Running Reth in Docker

```bash
./build/evm-middleware run --jwt-secret $(cat docker/jwttoken/jwt.hex)
cd docker
docker compose up -d
```

Compile rollkit from `feature/exec_api` branch and run it:
### Reading Genesis Information

If you've modified the genesis file, you can read the genesis hash and state root using the Ethereum JSON-RPC API:

```bash
git checkout feature/exec_api
go build ./cmd/rollkit
./rollkit start
# Get genesis block hash
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'

# Get genesis state root
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'
```
13 changes: 0 additions & 13 deletions cmd/evm-middleware/commands/root.go

This file was deleted.

101 changes: 0 additions & 101 deletions cmd/evm-middleware/commands/run.go

This file was deleted.

15 changes: 0 additions & 15 deletions cmd/evm-middleware/main.go

This file was deleted.

24 changes: 15 additions & 9 deletions docker/chain/genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,19 @@
"istanbulBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"shanghaiTime": 1677557088,
"cancunTime": 1710338100
"mergeNetsplitBlock": 0,
"terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true,
"shanghaiTime": 0,
"cancunTime": 0
},
"nonce": "0x0",
"timestamp": "0x0",
"extraData": "0x",
"gasLimit": "0x1c9c380",
"difficulty": "0x0",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"0xd143C405751162d0F96bEE2eB5eb9C61882a736E": {
"balance": "0x4a47e3c12448f4ad000000"
Expand All @@ -22,12 +32,8 @@
"balance": "0x4a47e3c12448f4ad000000"
}
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0xf4240",
"nonce": "0x0000000000000042",
"mixhash": "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46",
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
"baseFeePerGas": "0x3b9aca00"
}
Loading
Loading