Skip to content

Commit

Permalink
Reth support (#12)
Browse files Browse the repository at this point in the history
* Add reth

* Add reth client

* Add support for reth client

* Use reth in testnet

* Just build debug version

* Fix witness creation

* Fix entrypoint

* Switch back to geth
  • Loading branch information
mdehoog authored Nov 5, 2024
1 parent b00a8e7 commit 1af0179
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 6 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ go 1.22.6

require (
github.com/aws/aws-sdk-go v1.55.5
github.com/base-org/op-enclave/op-enclave v0.0.0
github.com/ethereum-optimism/optimism v1.9.3
github.com/ethereum/go-ethereum v1.14.11
github.com/hashicorp/go-multierror v1.1.1
github.com/base-org/op-enclave/op-enclave v0.0.0
github.com/prometheus/client_golang v1.20.4
github.com/urfave/cli/v2 v2.27.4
)
Expand Down
8 changes: 8 additions & 0 deletions op-proposer/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ var (
EnvVars: prefixEnvVar("L2_ETH_RPC"),
Required: true,
}
L2RethFlag = &cli.BoolFlag{
Name: "l2-reth",
Usage: "Is the L2 HTTP provider running Reth?",
EnvVars: prefixEnvVar("L2_RETH"),
Value: false,
Required: false,
}
EnclaveRpcFlag = &cli.StringFlag{
Name: "enclave-rpc",
Usage: "HTTP provider URL for the enclave service",
Expand All @@ -33,6 +40,7 @@ var (

var requiredFlags = []cli.Flag{
L2EthRpcFlag,
L2RethFlag,
EnclaveRpcFlag,
MinProposalIntervalFlag,
}
Expand Down
4 changes: 4 additions & 0 deletions op-proposer/proposer/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ type ethClient struct {
}

func NewClient(client *ethclient.Client, metrics caching.Metrics) Client {
return newClient(client, metrics)
}

func newClient(client *ethclient.Client, metrics caching.Metrics) *ethClient {
cacheSize := 1000
return &ethClient{
client: client,
Expand Down
2 changes: 2 additions & 0 deletions op-proposer/proposer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
type CLIConfig struct {
*proposer.CLIConfig
L2EthRpc string
L2Reth bool
EnclaveRpc string
MinProposalInterval uint64
}
Expand All @@ -17,6 +18,7 @@ func NewConfig(ctx *cli.Context) *CLIConfig {
return &CLIConfig{
CLIConfig: proposer.NewConfig(ctx),
L2EthRpc: ctx.String(flags.L2EthRpcFlag.Name),
L2Reth: ctx.Bool(flags.L2RethFlag.Name),
EnclaveRpc: ctx.String(flags.EnclaveRpcFlag.Name),
MinProposalInterval: ctx.Uint64(flags.MinProposalIntervalFlag.Name),
}
Expand Down
73 changes: 73 additions & 0 deletions op-proposer/proposer/reth_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package proposer

import (
"bytes"
"context"
"fmt"

"github.com/ethereum-optimism/optimism/op-service/sources/caching"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/ethclient"
)

// see https://github.com/alloy-rs/alloy/blob/main/crates/rpc-types-debug/src/debug.rs
type RethExecutionWitness struct {
State map[common.Hash]hexutil.Bytes
Codes map[common.Hash]hexutil.Bytes
Keys map[common.Hash]hexutil.Bytes
}

type rethClient struct {
ethClient
}

func NewRethClient(client *ethclient.Client, metrics caching.Metrics) Client {
ethClient := newClient(client, metrics)
return &rethClient{
ethClient: *ethClient,
}
}

func (e *rethClient) ExecutionWitness(ctx context.Context, hash common.Hash) ([]byte, error) {
header, err := e.HeaderByHash(ctx, hash)
if err != nil {
return nil, err
}

var witness RethExecutionWitness
// TODO it would be nice if reth accepted a tx hash parameter here
if err := e.client.Client().CallContext(ctx, &witness, "debug_executionWitness", "0x"+header.Number.Text(16)); err != nil {
return nil, err
}

w := &stateless.Witness{
Codes: make(map[string]struct{}),
State: make(map[string]struct{}),
}
for _, code := range witness.Codes {
w.Codes[string(code)] = struct{}{}
}
for _, state := range witness.State {
w.State[string(state)] = struct{}{}
}

// reth doesn't return required headers (for BLOCKHASH), so eagerly populate them all:
parentHash := header.ParentHash
history := int(min(256, header.Number.Uint64()))
for i := 0; i < history; i++ {
parent, err := e.HeaderByHash(ctx, parentHash)
if err != nil {
return nil, err
}
w.Headers = append(w.Headers, parent)
parentHash = parent.ParentHash
}

var buf bytes.Buffer
if err = w.EncodeRLP(&buf); err != nil {
return nil, fmt.Errorf("failed to encode witness: %w", err)
}
return buf.Bytes(), nil
}
10 changes: 9 additions & 1 deletion op-proposer/proposer/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type ProposerService struct {
TxManager txmgr.TxManager
L1Client *ethclient.Client
L2Client *ethclient.Client
L2Reth bool
RollupClient *gethrpc.Client
EnclaveClient *gethrpc.Client

Expand Down Expand Up @@ -135,6 +136,7 @@ func (ps *ProposerService) initRPCClients(ctx context.Context, cfg *CLIConfig) e
return fmt.Errorf("failed to dial L2 RPC: %w", err)
}
ps.L2Client = l2Client
ps.L2Reth = cfg.L2Reth

rollupClient, err := dial.DialRPCClientWithTimeout(ctx, dial.DefaultDialTimeout, ps.Log, cfg.RollupRpc)
if err != nil {
Expand Down Expand Up @@ -214,13 +216,19 @@ func (ps *ProposerService) initL2ooAddress(cfg *CLIConfig) {
}

func (ps *ProposerService) initDriver() error {
var l2Client L2Client
if ps.L2Reth {
l2Client = NewRethClient(ps.L2Client, ps.Metrics.L2Cache)
} else {
l2Client = NewClient(ps.L2Client, ps.Metrics.L2Cache)
}
driver, err := NewL2OutputSubmitter(DriverSetup{
Log: ps.Log,
Metr: ps.Metrics,
Cfg: ps.ProposerConfig,
Txmgr: ps.TxManager,
L1Client: NewClient(ps.L1Client, ps.Metrics.L1Cache),
L2Client: NewClient(ps.L2Client, ps.Metrics.L2Cache),
L2Client: l2Client,
RollupClient: NewRollupClient(ps.RollupClient, ps.Metrics.WitnessCache),
EnclaveClient: &enclave.Client{Client: ps.EnclaveClient},
})
Expand Down
3 changes: 2 additions & 1 deletion testnet/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# per deploy
OP_GETH_GENESIS_FILE_PATH=./deployments/84532-<INSERT_CHAIN_ID>-genesis.json
GENESIS_FILE_PATH=./deployments/84532-<INSERT_CHAIN_ID>-genesis.json
OP_NODE_ROLLUP_CONFIG=./deployments/84532-<INSERT_CHAIN_ID>-rollup-config.json
DEPLOYED_JSON=./deployments/84532-<INSERT_CHAIN_ID>-deployed.json

Expand Down Expand Up @@ -53,6 +53,7 @@ OP_BATCHER_TXMGR_RECEIPT_QUERY_INTERVAL=1s

# op-proposer
OP_PROPOSER_L2_ETH_RPC=http://op-geth:8545
OP_PROPOSER_L2_RETH=false
OP_PROPOSER_ROLLUP_RPC=http://op-node:8545
OP_PROPOSER_ENCLAVE_RPC=http://op-enclave:1234
OP_PROPOSER_ALLOW_NON_FINALIZED=true
Expand Down
21 changes: 21 additions & 0 deletions testnet/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,25 @@ RUN git clone $REPO --branch $VERSION --single-branch . && \
RUN go run build/ci.go install -static ./cmd/geth


FROM ubuntu:22.04 AS op-reth

WORKDIR /app

RUN apt-get update && apt-get -y upgrade && apt-get install -y git libclang-dev pkg-config curl build-essential
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

ENV PATH="/root/.cargo/bin:${PATH}"

ENV REPO=https://github.com/paradigmxyz/reth.git
ENV VERSION=v1.1.0
ENV COMMIT=1ba631ba9581973e7c6cadeea92cfe1802aceb4a
RUN git clone $REPO --branch $VERSION --single-branch . && \
git switch -c branch-$VERSION && \
bash -c '[ "$(git rev-parse HEAD)" = "$COMMIT" ]'

RUN cargo build --bin op-reth --features jemalloc,asm-keccak,optimism --manifest-path crates/optimism/bin/Cargo.toml


FROM ubuntu:22.04

RUN apt-get update && apt-get install -y curl jq
Expand All @@ -57,6 +76,7 @@ WORKDIR /app

COPY --from=op-node /app/op-node/bin/op-node ./
COPY --from=op-geth /app/build/bin/geth ./
COPY --from=op-reth /app/target/debug/op-reth ./reth
COPY --from=op-enclave /app/bin/op-enclave ./
COPY --from=op-enclave /app/bin/op-batcher ./
COPY --from=op-enclave /app/bin/op-proposer ./
Expand All @@ -67,4 +87,5 @@ COPY testnet/entrypoint-enclave.sh ./
COPY testnet/entrypoint-geth.sh ./
COPY testnet/entrypoint-node.sh ./
COPY testnet/entrypoint-proposer.sh ./
COPY testnet/entrypoint-reth.sh ./
COPY deployments/ deployments/
11 changes: 11 additions & 0 deletions testnet/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ services:
- ./data/geth:/data
env_file:
- .env
# op-reth:
# build:
# context: ..
# dockerfile: testnet/Dockerfile
# ports:
# - "8545:8545"
# command: [ "bash", "./entrypoint-reth.sh" ]
# volumes:
# - ./data/reth:/data
# env_file:
# - .env
op-node:
build:
context: ..
Expand Down
6 changes: 3 additions & 3 deletions testnet/entrypoint-geth.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
GETH_DATA_DIR=${GETH_DATA_DIR:-/data}
GETH_CHAINDATA_DIR="$GETH_DATA_DIR/geth/chaindata"

mkdir -p $GETH_DATA_DIR
mkdir -p "$GETH_DATA_DIR"
if [ ! -d "$GETH_CHAINDATA_DIR" ]; then
echo "$GETH_CHAINDATA_DIR missing, running init"
echo "Initializing genesis."
./geth init \
--datadir="$GETH_DATA_DIR" \
--state.scheme=hash \
"$OP_GETH_GENESIS_FILE_PATH"
"$GENESIS_FILE_PATH"
else
echo "$GETH_CHAINDATA_DIR exists."
fi

echo "$L2_ENGINE_JWT" > /tmp/engine.jwt

exec ./geth \
--datadir=/data \
--datadir="$GETH_DATA_DIR" \
--http \
--http.corsdomain="*" \
--http.vhosts="*" \
Expand Down
18 changes: 18 additions & 0 deletions testnet/entrypoint-reth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

RETH_DATA_DIR=${RETH_DATA_DIR:-/data}
echo "$L2_ENGINE_JWT" > /tmp/engine.jwt

exec ./reth node \
--datadir="$RETH_DATA_DIR" \
--chain="$GENESIS_FILE_PATH" \
--http \
--http.corsdomain="*" \
--http.addr=0.0.0.0 \
--http.port=8545 \
--http.api=web3,debug,eth,net \
--authrpc.addr=0.0.0.0 \
--authrpc.port=8551 \
--authrpc.jwtsecret=/tmp/engine.jwt \
--port=30303 \
--rpc.eth-proof-window=10000

0 comments on commit 1af0179

Please sign in to comment.