Skip to content

Commit 6557c21

Browse files
authored
Decouple Espresso L1 & OP L1 (#248)
1 parent a2749f2 commit 6557c21

File tree

17 files changed

+242
-179
lines changed

17 files changed

+242
-179
lines changed

espresso/cli.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package espresso
2+
3+
import (
4+
"crypto/ecdsa"
5+
"fmt"
6+
"strings"
7+
"time"
8+
9+
"github.com/ethereum/go-ethereum/common"
10+
"github.com/ethereum/go-ethereum/crypto"
11+
"github.com/urfave/cli/v2"
12+
)
13+
14+
// espressoFlags returns the flag names for espresso
15+
func espressoFlags(v string) string {
16+
return "espresso." + v
17+
}
18+
19+
func espressoEnvs(envprefix, v string) []string {
20+
return []string{envprefix + "_ESPRESSO_" + v}
21+
}
22+
23+
var (
24+
EnabledFlagName = espressoFlags("enabled")
25+
PollIntervalFlagName = espressoFlags("poll-interval")
26+
UseFetchApiFlagName = espressoFlags("fetch-api")
27+
QueryServiceUrlsFlagName = espressoFlags("urls")
28+
LightClientAddrFlagName = espressoFlags("light-client-addr")
29+
L1UrlFlagName = espressoFlags("l1-url")
30+
TestingBatcherPrivateKeyFlagName = espressoFlags("testing-batcher-private-key")
31+
)
32+
33+
func CLIFlags(envPrefix string, category string) []cli.Flag {
34+
return []cli.Flag{
35+
&cli.BoolFlag{
36+
Name: EnabledFlagName,
37+
Usage: "Enable Espresso mode",
38+
Value: false,
39+
EnvVars: espressoEnvs(envPrefix, "ENABLED"),
40+
Category: category,
41+
},
42+
&cli.DurationFlag{
43+
Name: PollIntervalFlagName,
44+
Usage: "Polling interval for Espresso queries",
45+
Value: 250 * time.Millisecond,
46+
EnvVars: espressoEnvs(envPrefix, "POLL_INTERVAL"),
47+
Category: category,
48+
},
49+
&cli.BoolFlag{
50+
Name: UseFetchApiFlagName,
51+
Usage: "Use fetch API for Espresso queries",
52+
Value: false,
53+
EnvVars: espressoEnvs(envPrefix, "FETCH_API"),
54+
Category: category,
55+
},
56+
&cli.StringSliceFlag{
57+
Name: QueryServiceUrlsFlagName,
58+
Usage: "Comma-separated list of Espresso query service URLs",
59+
EnvVars: espressoEnvs(envPrefix, "URLS"),
60+
Category: category,
61+
},
62+
&cli.StringFlag{
63+
Name: LightClientAddrFlagName,
64+
Usage: "Address of the Espresso light client",
65+
EnvVars: espressoEnvs(envPrefix, "LIGHT_CLIENT_ADDR"),
66+
Category: category,
67+
},
68+
&cli.StringFlag{
69+
Name: L1UrlFlagName,
70+
Usage: "L1 RPC URL Espresso contracts are deployed on",
71+
EnvVars: espressoEnvs(envPrefix, "L1_URL"),
72+
Category: category,
73+
},
74+
&cli.StringFlag{
75+
Name: TestingBatcherPrivateKeyFlagName,
76+
Usage: "Pre-approved batcher ephemeral key (testing only)",
77+
EnvVars: espressoEnvs(envPrefix, "TESTING_BATCHER_PRIVATE_KEY"),
78+
Category: category,
79+
},
80+
}
81+
}
82+
83+
type CLIConfig struct {
84+
Enabled bool
85+
PollInterval time.Duration
86+
UseFetchAPI bool
87+
QueryServiceURLs []string
88+
LightClientAddr common.Address
89+
L1URL string
90+
TestingBatcherPrivateKey *ecdsa.PrivateKey
91+
}
92+
93+
func (c CLIConfig) Check() error {
94+
if c.Enabled {
95+
// Check required fields when Espresso is enabled
96+
if len(c.QueryServiceURLs) == 0 {
97+
return fmt.Errorf("query service URLs are required when Espresso is enabled")
98+
}
99+
if c.LightClientAddr == (common.Address{}) {
100+
return fmt.Errorf("light client address is required when Espresso is enabled")
101+
}
102+
if c.L1URL == "" {
103+
return fmt.Errorf("L1 URL is required when Espresso is enabled")
104+
}
105+
}
106+
return nil
107+
}
108+
109+
func ReadCLIConfig(c *cli.Context) CLIConfig {
110+
config := CLIConfig{
111+
Enabled: c.Bool(EnabledFlagName),
112+
PollInterval: c.Duration(PollIntervalFlagName),
113+
UseFetchAPI: c.Bool(UseFetchApiFlagName),
114+
L1URL: c.String(L1UrlFlagName),
115+
}
116+
117+
config.QueryServiceURLs = c.StringSlice(QueryServiceUrlsFlagName)
118+
119+
addrStr := c.String(LightClientAddrFlagName)
120+
config.LightClientAddr = common.HexToAddress(addrStr)
121+
122+
pkStr := c.String(TestingBatcherPrivateKeyFlagName)
123+
pkStr = strings.TrimPrefix(pkStr, "0x")
124+
pk, err := crypto.HexToECDSA(pkStr)
125+
if err == nil {
126+
config.TestingBatcherPrivateKey = pk
127+
}
128+
129+
return config
130+
}

espresso/docker-compose.yml

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ services:
9696
l1-genesis:
9797
condition: service_completed_successfully
9898
healthcheck:
99-
test: [ "CMD", "curl", "-f", "http://localhost:${L1_HTTP_PORT}" ]
99+
test: ["CMD", "curl", "-f", "http://localhost:${L1_HTTP_PORT}"]
100100
interval: 3s
101101
timeout: 2s
102102
retries: 40
@@ -191,7 +191,7 @@ services:
191191
dockerfile: espresso/docker/op-stack/Dockerfile
192192
target: op-node-target
193193
healthcheck:
194-
test: [ "CMD", "curl", "-f", "http://localhost:${ROLLUP_PORT}" ]
194+
test: ["CMD", "curl", "-f", "http://localhost:${ROLLUP_PORT}"]
195195
interval: 3s
196196
timeout: 2s
197197
retries: 40
@@ -233,7 +233,7 @@ services:
233233
dockerfile: espresso/docker/op-stack/Dockerfile
234234
target: op-node-target
235235
healthcheck:
236-
test: [ "CMD", "curl", "-f", "http://localhost:${VERIFIER_PORT}" ]
236+
test: ["CMD", "curl", "-f", "http://localhost:${VERIFIER_PORT}"]
237237
interval: 3s
238238
timeout: 2s
239239
retries: 40
@@ -271,7 +271,7 @@ services:
271271
dockerfile: espresso/docker/op-stack/Dockerfile
272272
target: op-node-target
273273
healthcheck:
274-
test: [ "CMD", "curl", "-f", "http://localhost:${CAFF_PORT}" ]
274+
test: ["CMD", "curl", "-f", "http://localhost:${CAFF_PORT}"]
275275
interval: 3s
276276
timeout: 2s
277277
retries: 40
@@ -287,9 +287,9 @@ services:
287287
OP_NODE_L1_ETH_RPC: http://l1-geth:${L1_HTTP_PORT}
288288
OP_NODE_L1_BEACON: http://l1-beacon:${L1_BEACON_PORT}
289289
OP_NODE_L2_ENGINE_RPC: http://op-geth-caff-node:${OP_ENGINE_PORT}
290-
OP_NODE_CAFF_L1_ETH_RPC: http://l1-geth:${L1_HTTP_PORT}
291-
OP_NODE_CAFF_ESPRESSO_LIGHT_CLIENT_ADDR: "0x703848f4c85f18e3acd8196c8ec91eb0b7bd0797"
292-
OP_NODE_CAFF_HOTSHOT_URLS: http://espresso-dev-node:${ESPRESSO_SEQUENCER_API_PORT},http://espresso-dev-node:${ESPRESSO_SEQUENCER_API_PORT}
290+
OP_NODE_ESPRESSO_L1_URL: http://l1-geth:${L1_HTTP_PORT}
291+
OP_NODE_ESPRESSO_LIGHT_CLIENT_ADDR: "0x703848f4c85f18e3acd8196c8ec91eb0b7bd0797"
292+
OP_NODE_ESPRESSO_URLS: http://espresso-dev-node:${ESPRESSO_SEQUENCER_API_PORT},http://espresso-dev-node:${ESPRESSO_SEQUENCER_API_PORT}
293293
OP_NODE_RPC_PORT: ${CAFF_PORT}
294294
ports:
295295
- "${CAFF_PORT}:${CAFF_PORT}"
@@ -301,22 +301,21 @@ services:
301301
- --rollup.config=/config/rollup.json
302302
- --rpc.addr=0.0.0.0
303303
- --sequencer.enabled=false
304-
- --caff.node=true
304+
- --espresso.enabled=true
305305
- --verifier.l1-confs=0
306306
- --rollup.load-protocol-versions=false
307307
- --rollup.halt=none
308308
- --l1.trustrpc=true
309309
- --rpc.enable-admin=true
310-
- --caff.next-hotshot-block-num=1
311-
- --caff.polling-hotshot-polling-interval=500ms
310+
- --espresso.poll-interval=500ms
312311
- --log.level=debug
313312
- --p2p.disable=true
314313
- --l1.http-poll-interval=1s
315314
- --l1.epoch-poll-interval=1s
316315
restart: "no"
317316

318317
op-batcher:
319-
profiles: [ "default" ]
318+
profiles: ["default"]
320319
build:
321320
context: ../
322321
dockerfile: espresso/docker/op-stack/Dockerfile
@@ -339,30 +338,35 @@ services:
339338
OP_BATCHER_L1_ETH_RPC: http://l1-geth:${L1_HTTP_PORT}
340339
OP_BATCHER_L2_ETH_RPC: http://op-geth-sequencer:${OP_HTTP_PORT}
341340
OP_BATCHER_ROLLUP_RPC: http://op-node-sequencer:${ROLLUP_PORT}
342-
OP_BATCHER_ESPRESSO_URL: http://espresso-dev-node:${ESPRESSO_SEQUENCER_API_PORT},http://espresso-dev-node:${ESPRESSO_SEQUENCER_API_PORT}
341+
OP_BATCHER_ESPRESSO_URLS: http://espresso-dev-node:${ESPRESSO_SEQUENCER_API_PORT},http://espresso-dev-node:${ESPRESSO_SEQUENCER_API_PORT}
343342
volumes:
344343
- ../packages/contracts-bedrock/lib/superchain-registry/ops/testdata/monorepo:/config
345344
command:
346345
- op-batcher
347-
- --espresso-light-client-addr=0x703848f4c85f18e3acd8196c8ec91eb0b7bd0797
348-
- --testing-espresso-batcher-private-key=${OP_TESTING_BATCHER_PRIVATE_KEY:-$OPERATOR_PRIVATE_KEY}
346+
- --espresso.enabled=true
347+
- --espresso.poll-interval=1s
348+
- --espresso.light-client-addr=0x703848f4c85f18e3acd8196c8ec91eb0b7bd0797
349+
- --espresso.testing-batcher-private-key=${OP_TESTING_BATCHER_PRIVATE_KEY:-$OPERATOR_PRIVATE_KEY}
349350
- --private-key=${OP_BATCHER_PRIVATE_KEY:-$OPERATOR_PRIVATE_KEY}
350351
- --throttle-threshold=0
351352
- --max-channel-duration=2
352353
- --target-num-frames=1
353354
- --max-pending-tx=32
354355
- --altda.max-concurrent-da-requests=32
355-
- --espresso-poll-interval=1s
356356

357357
op-batcher-tee:
358-
profiles: [ "tee" ]
358+
profiles: ["tee"]
359359
build:
360360
context: ../
361361
dockerfile: espresso/docker/op-stack/Dockerfile
362362
target: op-batcher-enclave-target
363363
image: op-batcher-tee:espresso
364364
healthcheck:
365-
test: [ "CMD-SHELL", "test -f /tmp/enclave-tools.pid && kill -0 $(cat /tmp/enclave-tools.pid) 2>/dev/null || exit 1" ]
365+
test:
366+
[
367+
"CMD-SHELL",
368+
"test -f /tmp/enclave-tools.pid && kill -0 $(cat /tmp/enclave-tools.pid) 2>/dev/null || exit 1",
369+
]
366370
interval: 30s
367371
timeout: 10s
368372
retries: 3
@@ -408,7 +412,7 @@ services:
408412
/source/espresso/docker/op-batcher-tee/run-enclave.sh
409413
410414
op-proposer:
411-
profiles: [ "default" ]
415+
profiles: ["default"]
412416
build:
413417
context: ../
414418
dockerfile: espresso/docker/op-stack/Dockerfile
@@ -432,10 +436,10 @@ services:
432436
OP_PROPOSER_PROPOSAL_INTERVAL: 6s
433437
OP_PROPOSER_MNEMONIC: "test test test test test test test test test test test junk"
434438
OP_PROPOSER_HD_PATH: "m/44'/60'/0'/0/1"
435-
OP_PROPOSER_GAME_TYPE: '1'
439+
OP_PROPOSER_GAME_TYPE: "1"
436440

437441
op-proposer-tee:
438-
profiles: [ "tee" ]
442+
profiles: ["tee"]
439443
build:
440444
context: ../
441445
dockerfile: espresso/docker/op-stack/Dockerfile
@@ -459,11 +463,10 @@ services:
459463
OP_PROPOSER_PROPOSAL_INTERVAL: 6s
460464
OP_PROPOSER_MNEMONIC: "test test test test test test test test test test test junk"
461465
OP_PROPOSER_HD_PATH: "m/44'/60'/0'/0/1"
462-
OP_PROPOSER_GAME_TYPE: '1'
463-
466+
OP_PROPOSER_GAME_TYPE: "1"
464467

465468
op-challenger:
466-
profiles: [ "default" ]
469+
profiles: ["default"]
467470
build:
468471
context: ../
469472
dockerfile: espresso/docker/op-stack/Dockerfile

espresso/docker/op-batcher-tee/run-enclave.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,15 @@ echo "====================================="
3838
BATCHER_ARGS="--l1-eth-rpc=$L1_RPC_URL"
3939
BATCHER_ARGS="$BATCHER_ARGS,--l2-eth-rpc=$L2_RPC_URL"
4040
BATCHER_ARGS="$BATCHER_ARGS,--rollup-rpc=$ROLLUP_RPC_URL"
41-
BATCHER_ARGS="$BATCHER_ARGS,--espresso-url=$ESPRESSO_URL1"
42-
BATCHER_ARGS="$BATCHER_ARGS,--espresso-url=$ESPRESSO_URL2"
43-
BATCHER_ARGS="$BATCHER_ARGS,--testing-espresso-batcher-private-key=$OPERATOR_PRIVATE_KEY"
41+
BATCHER_ARGS="$BATCHER_ARGS,--espresso.enabled=true"
42+
BATCHER_ARGS="$BATCHER_ARGS,--espresso.urls=$ESPRESSO_URL1"
43+
BATCHER_ARGS="$BATCHER_ARGS,--espresso.urls=$ESPRESSO_URL2"
4444
BATCHER_ARGS="$BATCHER_ARGS,--mnemonic=test test test test test test test test test test test junk"
4545
BATCHER_ARGS="$BATCHER_ARGS,--hd-path=m/44'/60'/0'/0/0"
4646
BATCHER_ARGS="$BATCHER_ARGS,--throttle-threshold=0"
4747
BATCHER_ARGS="$BATCHER_ARGS,--max-channel-duration=1"
4848
BATCHER_ARGS="$BATCHER_ARGS,--target-num-frames=1"
49-
BATCHER_ARGS="$BATCHER_ARGS,--espresso-light-client-addr=0x703848f4c85f18e3acd8196c8ec91eb0b7bd0797"
49+
BATCHER_ARGS="$BATCHER_ARGS,--espresso.light-client-addr=0x703848f4c85f18e3acd8196c8ec91eb0b7bd0797"
5050

5151
# Add debug arguments if enabled
5252
if [ "$ENCLAVE_DEBUG" = "true" ]; then

espresso/environment/enclave_helpers.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"testing"
1414
"time"
1515

16+
"github.com/ethereum-optimism/optimism/espresso"
1617
altda "github.com/ethereum-optimism/optimism/op-alt-da"
1718
"github.com/ethereum-optimism/optimism/op-batcher/batcher"
1819
"github.com/ethereum-optimism/optimism/op-batcher/bindings"
@@ -92,6 +93,7 @@ func LaunchBatcherInEnclave() E2eDevnetLauncherOption {
9293
l1Rpc := sys.L1.UserRPC().(endpoint.HttpRPC).HttpRPC()
9394
appendArg(&args, flags.L1EthRpcFlag.Name, l1Rpc)
9495
appendArg(&args, txmgr.L1RPCFlagName, l1Rpc)
96+
appendArg(&args, espresso.L1UrlFlagName, l1Rpc)
9597
l2EthRpc := sys.EthInstances[e2esys.RoleSeq].UserRPC().(endpoint.HttpRPC).HttpRPC()
9698
appendArg(&args, flags.L2EthRpcFlag.Name, l2EthRpc)
9799
rollupRpc := sys.RollupNodes[e2esys.RoleSeq].UserRPC().(endpoint.HttpRPC).HttpRPC()
@@ -105,8 +107,6 @@ func LaunchBatcherInEnclave() E2eDevnetLauncherOption {
105107
appendArg(&args, flags.CompressionAlgoFlag.Name, c.CompressionAlgo.String())
106108
appendArg(&args, flags.CompressorFlag.Name, c.Compressor)
107109
appendArg(&args, flags.DataAvailabilityTypeFlag.Name, c.DataAvailabilityType.String())
108-
appendArg(&args, flags.EspressoLCAddrFlag.Name, c.EspressoLightClientAddr)
109-
appendArg(&args, flags.EspressoPollIntervalFlag.Name, c.EspressoPollInterval)
110110
appendArg(&args, flags.MaxBlocksPerSpanBatch.Name, c.MaxBlocksPerSpanBatch)
111111
appendArg(&args, flags.MaxChannelDurationFlag.Name, c.MaxChannelDuration)
112112
appendArg(&args, flags.MaxL1TxSizeBytesFlag.Name, c.MaxL1TxSize)
@@ -120,11 +120,6 @@ func LaunchBatcherInEnclave() E2eDevnetLauncherOption {
120120
appendArg(&args, flags.ThrottleThresholdFlag.Name, c.ThrottleThreshold)
121121
appendArg(&args, flags.ThrottleTxSizeFlag.Name, c.ThrottleTxSize)
122122
appendArg(&args, flags.WaitNodeSyncFlag.Name, c.WaitNodeSync)
123-
for _, url := range c.EspressoUrls {
124-
appendArg(&args, flags.EspressoUrlsFlag.Name, url)
125-
}
126-
appendArg(&args, flags.EspressoLCAddrFlag.Name, c.EspressoLightClientAddr)
127-
appendArg(&args, flags.TestingEspressoBatcherPrivateKeyFlag.Name, c.TestingEspressoBatcherPrivateKey)
128123

129124
// TxMgr flags
130125
appendArg(&args, txmgr.MnemonicFlagName, c.TxMgrConfig.Mnemonic)
@@ -175,6 +170,16 @@ func LaunchBatcherInEnclave() E2eDevnetLauncherOption {
175170
appendArg(&args, altda.GetTimeoutFlagName, c.AltDA.GetTimeout)
176171
appendArg(&args, altda.MaxConcurrentRequestsFlagName, c.AltDA.MaxConcurrentRequests)
177172

173+
// Espresso flags
174+
appendArg(&args, espresso.EnabledFlagName, c.Espresso.Enabled)
175+
appendArg(&args, espresso.PollIntervalFlagName, c.Espresso.PollInterval)
176+
appendArg(&args, espresso.LightClientAddrFlagName, c.Espresso.LightClientAddr)
177+
appendArg(&args, espresso.TestingBatcherPrivateKeyFlagName, hexutil.Encode(crypto.FromECDSA(c.Espresso.TestingBatcherPrivateKey)))
178+
appendArg(&args, espresso.UseFetchApiFlagName, c.Espresso.UseFetchAPI)
179+
for _, url := range c.Espresso.QueryServiceURLs {
180+
appendArg(&args, espresso.QueryServiceUrlsFlagName, url)
181+
}
182+
178183
err := SetupEnclaver(ct.Ctx, sys, args...)
179184
if err != nil {
180185
panic(fmt.Sprintf("failed to setup enclaver: %v", err))

espresso/environment/espresso_caff_node.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ import (
1010
"testing"
1111
"time"
1212

13+
"github.com/ethereum-optimism/optimism/espresso"
1314
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
1415
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/opnode"
1516
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
1617
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
17-
"github.com/ethereum-optimism/optimism/op-node/rollup"
1818
"github.com/ethereum-optimism/optimism/op-service/testlog"
19+
"github.com/ethereum/go-ethereum/common"
1920
)
2021

2122
const (
@@ -111,13 +112,13 @@ func LaunchCaffNode(t *testing.T, system *e2esys.System, espressoDevNode Espress
111112

112113
caffNodeConfig := *system.Cfg.Nodes[e2esys.RoleVerif]
113114
caffNodeConfig.Rollup = *system.RollupConfig
114-
caffNodeConfig.Rollup.CaffNodeConfig = rollup.CaffNodeConfig{
115-
IsCaffNode: true,
116-
PollingHotShotPollingInterval: 30 * time.Millisecond,
115+
caffNodeConfig.Rollup.CaffNodeConfig = espresso.CLIConfig{
116+
Enabled: true,
117+
PollInterval: 30 * time.Millisecond,
117118
// To create a valid multiple nodes client, we need to provide at least 2 URLs.
118-
HotShotUrls: []string{u.String(), u.String()},
119-
L1EthRpc: system.L1.UserRPC().RPC(),
120-
EspressoLightClientAddr: ESPRESSO_LIGHT_CLIENT_ADDRESS,
119+
QueryServiceURLs: []string{u.String(), u.String()},
120+
L1URL: system.L1.UserRPC().RPC(),
121+
LightClientAddr: common.HexToAddress(ESPRESSO_LIGHT_CLIENT_ADDRESS),
121122
}
122123

123124
// Configure

0 commit comments

Comments
 (0)