Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
33effe4
contracts-bedrock: add Espresso BatchAuthenticator and supporting infra
QuentinI May 7, 2026
1351b55
Update packages/contracts-bedrock/src/L1/BatchAuthenticator.sol
QuentinI May 13, 2026
e288e7f
Remove stray path
QuentinI May 13, 2026
4ad3806
Remove hardcoded Sepolia URL
QuentinI May 13, 2026
5fcdec6
Use OZ v5 in mock verifier
QuentinI May 13, 2026
d8278a8
Fix Codex's suggestion
QuentinI May 20, 2026
52d9ff7
Lower pragma
QuentinI May 20, 2026
da2a2d4
Remove unrelated foundry.toml changes
QuentinI May 20, 2026
014b5c1
scripts/checks: clean up exclude lists per PR review
QuentinI May 20, 2026
3405d9f
Fix re-initialization
QuentinI May 21, 2026
9f7a2a2
Add batcher address history
QuentinI May 25, 2026
46cbf9e
contracts-bedrock: drop OZ TUP from espresso deploy
palango May 20, 2026
9c200ea
Remove pause from BatchAuthenticator
QuentinI May 25, 2026
34cbb2c
Add a defensive check
QuentinI May 25, 2026
ce947ad
test: add end-to-end dual-batcher switch test
QuentinI May 25, 2026
1bb937e
Fix tests
QuentinI May 28, 2026
af3ae99
switchBatcher from toggle to a setter
QuentinI May 29, 2026
f18db0e
Use OZ Checkpoints for batcher history
QuentinI May 29, 2026
22a363b
contracts-bedrock: deploy espresso impls via vm.getCode, drop suppres…
QuentinI Jun 1, 2026
3195d14
Check batcher in Espresso mode
shenkeyao May 28, 2026
e2b0618
regenerate snapshots for UnauthorizedEspressoBatcher error
QuentinI Jun 2, 2026
d12cc06
contracts-bedrock: wire espresso proxies to shared OP Stack ProxyAdmin
QuentinI Jun 4, 2026
6dc87d8
add caller to BatchInfoAuthenticated event
QuentinI Jun 4, 2026
78005d6
forge fmt
piersy Jun 9, 2026
335fd19
Remove unused imports
piersy Jun 10, 2026
82d2683
Rename tests to fit test name convention
piersy Jun 10, 2026
41c9f34
op-chain-ops/script: resolve directory-qualified getCode artifact names
QuentinI Jun 11, 2026
b716fb5
contracts-bedrock: fix semgrep checks-fast findings
QuentinI Jun 11, 2026
f4c04c4
contracts-bedrock: prevent same-block espressoBatcher history corruption
QuentinI Jun 15, 2026
5b28541
Fix formatting
piersy Jun 17, 2026
d5ff5d1
Fix recompile tests
QuentinI Jun 17, 2026
f30c890
op-node: add event-based batch authentication
QuentinI May 25, 2026
e7efdef
op-node: rename EspressoEnforcementTime to EspressoTime
QuentinI May 25, 2026
272f231
op-node: require BatchAuthenticatorAddress when Espresso is enabled
QuentinI Jun 2, 2026
d0abe22
op-node: fix EspressoTime fork-activation doc comments
QuentinI Jun 2, 2026
19479cc
op-node: bind authenticated batches to the authenticating caller
QuentinI Jun 8, 2026
e6ecc61
op-node: replace global batch auth caches with dependency-injected in…
piersy Jun 2, 2026
5c31f2a
Use rollup.Config in DataSourceConfig
piersy Jun 3, 2026
6705563
op-node: fix up batch-auth cache DI and rollupCfg cherry-picks
QuentinI Jun 8, 2026
0bec1fc
Hardcode BatchAuthLookbackWindow
QuentinI Jun 8, 2026
7824719
Tighten assertions for batch auth tests
piersy Jun 11, 2026
6e569f2
op-node: test Espresso fork boundary and per-commitment batch auth
piersy Jun 11, 2026
7527f45
op-node: isolate Espresso derivation tests into espresso_-prefixed files
piersy Jun 11, 2026
cc7422f
Update op-node/rollup/derive/espresso_blob_data_source_test.go
piersy Jun 15, 2026
7467e81
Update op-node/rollup/derive/espresso_blob_data_source_test.go
piersy Jun 15, 2026
266fe6f
Expand LRU size comment
QuentinI Jun 18, 2026
105dc93
espresso/bindings: add regenerated BatchAuthenticator Go bindings
QuentinI May 27, 2026
a315e6d
op-batcher: integrate fallback batcher authentication
QuentinI May 27, 2026
1616378
op-batcher: route fallback auth through ordered tx queue
QuentinI Jun 18, 2026
595fd29
op-service: add ChainSigner interface and eth_sign helper
QuentinI May 26, 2026
aafb147
op-node: add EspressoBatch type and converters
QuentinI May 26, 2026
ea15846
espresso: add TEE batcher CLI flags, streamer interface, and L1 adapter
QuentinI May 27, 2026
1bcc7ea
op-batcher: add Nitro NSM attestation helper
QuentinI May 26, 2026
c03b7a5
op-batcher: integrate TEE batcher and Espresso submission loop
QuentinI May 27, 2026
4f9f6ad
op-batcher: route TEE auth through ordered tx queue
QuentinI Jun 18, 2026
6cf6a1f
op-node: add EspressoBatch roundtrip test, fix derive_test vet failure
QuentinI Jun 18, 2026
10d1ae4
op-service/txmgr: implement ChainSigner on SimpleTxManager
QuentinI Jun 19, 2026
a88e0ff
op-chain-ops/genesis: thread EspressoTime + BatchAuthenticatorAddress…
QuentinI Jun 19, 2026
85c1165
op-deployer: add Espresso BatchAuthenticator deploy step
QuentinI Jun 19, 2026
69a0f58
op-e2e: add Espresso system support to the e2e harness
QuentinI Jun 19, 2026
2a428d8
espresso/bindings: add EspressoTEEVerifier Go binding
QuentinI Jun 19, 2026
b217786
espresso/environment: port Espresso e2e (op-e2e) tests
QuentinI Jun 19, 2026
c082978
op-batcher: allow injecting the Espresso client via the SDK interface
QuentinI Jun 19, 2026
57c51a4
espresso: add in-memory mock Espresso client
QuentinI Jun 19, 2026
268bdf8
op-e2e/espresso: run Espresso e2e tests against the in-memory mock de…
QuentinI Jun 19, 2026
0fba9d1
op-e2e/espresso: drop Docker-only verifier tests and dead Docker helpers
QuentinI Jun 21, 2026
cc06a7e
op-e2e/espresso: fix caffeination height on batcher restart
QuentinI Jun 21, 2026
871e2e0
op-e2e/espresso: honour caller timeout for L2 burn verifier wait
QuentinI Jun 22, 2026
1fcbca5
op-e2e/espresso: stabilize batcher-switch/fallback tests
QuentinI Jun 22, 2026
6c6d764
op-e2e/espresso: fix and unskip TestValidEspressoTransactionCreation
QuentinI Jun 22, 2026
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
5 changes: 5 additions & 0 deletions .circleci/continue/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,11 @@ jobs:
enable-mise-cache: true
- attach_workspace:
at: .
# Pin the solc set to match contracts-bedrock-build. op-deployer tests run
# `forge script` against the embedded artifact bundle; if forge auto-detects a
# newer solc than the bundle was built with (floating ^0.8.0 pragmas), it
# recompiles and breaks the "must not recompile" assertions.
- install-solc-compilers
- restore_cache:
key: go-tests-v2-{{ checksum "go.mod" }}
- run:
Expand Down
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@
[submodule "packages/contracts-bedrock/lib/superchain-registry"]
path = packages/contracts-bedrock/lib/superchain-registry
url = https://github.com/ethereum-optimism/superchain-registry
[submodule "packages/contracts-bedrock/lib/espresso-tee-contracts"]
path = packages/contracts-bedrock/lib/espresso-tee-contracts
url = https://github.com/EspressoSystems/espresso-tee-contracts
[submodule "packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable-v5"]
path = packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable-v5
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
2,277 changes: 2,277 additions & 0 deletions espresso/bindings/batch_authenticator.go

Large diffs are not rendered by default.

1,797 changes: 1,797 additions & 0 deletions espresso/bindings/espresso_tee_verifier.go

Large diffs are not rendered by default.

306 changes: 306 additions & 0 deletions espresso/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
package espresso

import (
"crypto/ecdsa"
"fmt"
"strings"
"time"

op "github.com/EspressoSystems/espresso-streamers/op"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"

"github.com/urfave/cli/v2"

espressoClient "github.com/EspressoSystems/espresso-network/sdks/go/client"
espressoLightClient "github.com/EspressoSystems/espresso-network/sdks/go/light-client"
)

// espressoFlags returns the flag names for espresso
func espressoFlags(v string) string {
return "espresso." + v
}

func espressoEnvs(envprefix, v string) []string {
return []string{envprefix + "_ESPRESSO_" + v}
}

// Default values for batch submission receipt verification tuning.
// Defined here so that both the CLI flag defaults and the batcher logic
// can reference a single source of truth.
//
// Note: DefaultBatchAuthLookbackWindow lives in constants.go (mips64-clean
// build target shared with the derivation pipeline).
const (
DefaultVerifyReceiptMaxBlocks uint64 = 5
DefaultVerifyReceiptSafetyTimeout time.Duration = 5 * time.Minute
DefaultVerifyReceiptRetryDelay time.Duration = 100 * time.Millisecond
DefaultMaxInFlightRequestsToEspresso = 128
)

var (
EnabledFlagName = espressoFlags("enabled")
PollIntervalFlagName = espressoFlags("poll-interval")
QueryServiceUrlsFlagName = espressoFlags("urls")
LightClientAddrFlagName = espressoFlags("light-client-addr")
L1UrlFlagName = espressoFlags("l1-url")
TestingBatcherPrivateKeyFlagName = espressoFlags("testing-batcher-private-key")
CaffeinationHeightEspresso = espressoFlags("origin-height-espresso")
CaffeinationHeightL2 = espressoFlags("origin-height-l2")
NamespaceFlagName = espressoFlags("namespace")
RollupL1UrlFlagName = espressoFlags("rollup-l1-url")
AttestationServiceFlagName = espressoFlags("espresso-attestation-service")
BatchAuthenticatorAddrFlagName = espressoFlags("batch-authenticator-addr")
VerifyReceiptMaxBlocksFlagName = espressoFlags("verify-receipt-max-blocks")
VerifyReceiptSafetyTimeoutFlagName = espressoFlags("verify-receipt-safety-timeout")
VerifyReceiptRetryDelayFlagName = espressoFlags("verify-receipt-retry-delay")
)

func CLIFlags(envPrefix string, category string) []cli.Flag {
return []cli.Flag{
&cli.BoolFlag{
Name: EnabledFlagName,
Usage: "Enable Espresso mode",
Value: false,
EnvVars: espressoEnvs(envPrefix, "ENABLED"),
Category: category,
},
&cli.DurationFlag{
Name: PollIntervalFlagName,
Usage: "Polling interval for Espresso queries",
Value: 250 * time.Millisecond,
EnvVars: espressoEnvs(envPrefix, "POLL_INTERVAL"),
Category: category,
},
&cli.StringSliceFlag{
Name: QueryServiceUrlsFlagName,
Usage: "Comma-separated list of Espresso query service URLs",
EnvVars: espressoEnvs(envPrefix, "URLS"),
Category: category,
},
&cli.StringFlag{
Name: LightClientAddrFlagName,
Usage: "Address of the Espresso light client",
EnvVars: espressoEnvs(envPrefix, "LIGHT_CLIENT_ADDR"),
Category: category,
},
&cli.StringFlag{
Name: L1UrlFlagName,
Usage: "L1 RPC URL Espresso contracts are deployed on",
EnvVars: espressoEnvs(envPrefix, "L1_URL"),
Category: category,
},
&cli.StringFlag{
Name: TestingBatcherPrivateKeyFlagName,
Usage: "Pre-approved batcher ephemeral key (testing only)",
EnvVars: espressoEnvs(envPrefix, "TESTING_BATCHER_PRIVATE_KEY"),
Category: category,
},
&cli.Uint64Flag{
Name: CaffeinationHeightEspresso,
Usage: "Espresso transactions below this height will not be considered",
EnvVars: espressoEnvs(envPrefix, "ORIGIN_HEIGHT_ESPRESSO"),
Category: category,
},
&cli.Uint64Flag{
Name: CaffeinationHeightL2,
Usage: "L2 batch position at which the Espresso streamer starts emitting batches. " +
"Operational parameter for restarting batchers mid-chain. " +
"When zero, the streamer falls back to its internal default. " +
"Independent of the EspressoTime hardfork, which gates derivation semantics.",
Value: 0,
EnvVars: espressoEnvs(envPrefix, "ORIGIN_HEIGHT_L2"),
Category: category,
},
&cli.Uint64Flag{
Name: NamespaceFlagName,
Usage: "Namespace of Espresso transactions",
EnvVars: espressoEnvs(envPrefix, "NAMESPACE"),
Category: category,
},
&cli.StringFlag{
Name: RollupL1UrlFlagName,
Usage: "RPC URL of L1 backing the Rollup we're streaming for",
EnvVars: espressoEnvs(envPrefix, "ROLLUP_L1_URL"),
Category: category,
},
&cli.StringFlag{
Name: AttestationServiceFlagName,
Usage: "URL of the Espresso attestation service",
EnvVars: espressoEnvs(envPrefix, "ESPRESSO_ATTESTATION_SERVICE"),
Category: category,
},
&cli.StringFlag{
Name: BatchAuthenticatorAddrFlagName,
Usage: "Address of the Batch Authenticator contract",
EnvVars: espressoEnvs(envPrefix, "BATCH_AUTHENTICATOR_ADDR"),
Category: category,
},
&cli.Uint64Flag{
Name: VerifyReceiptMaxBlocksFlagName,
Usage: "Number of HotShot blocks to wait for a submitted transaction to become queryable before re-submitting",
Value: DefaultVerifyReceiptMaxBlocks,
EnvVars: espressoEnvs(envPrefix, "VERIFY_RECEIPT_MAX_BLOCKS"),
Category: category,
},
&cli.DurationFlag{
Name: VerifyReceiptSafetyTimeoutFlagName,
Usage: "Wall-clock backstop for receipt verification; re-submits the transaction if this duration is exceeded",
Value: DefaultVerifyReceiptSafetyTimeout,
EnvVars: espressoEnvs(envPrefix, "VERIFY_RECEIPT_SAFETY_TIMEOUT"),
Category: category,
},
&cli.DurationFlag{
Name: VerifyReceiptRetryDelayFlagName,
Usage: "Delay between receipt verification retries",
Value: DefaultVerifyReceiptRetryDelay,
EnvVars: espressoEnvs(envPrefix, "VERIFY_RECEIPT_RETRY_DELAY"),
Category: category,
},
// Note: --espresso.fallback-auth-lead-time is registered by the
// fallback batcher in op-batcher/flags/flags.go; it is read by both
// the fallback and the TEE batcher paths.
}
}

type CLIConfig struct {
Enabled bool
PollInterval time.Duration
QueryServiceURLs []string
LightClientAddr common.Address
BatchAuthenticatorAddr common.Address
L1URL string
RollupL1URL string
TestingBatcherPrivateKey *ecdsa.PrivateKey
Namespace uint64
CaffeinationHeightEspresso uint64
CaffeinationHeightL2 uint64
EspressoAttestationService string

// Batch submission receipt verification tuning
VerifyReceiptMaxBlocks uint64
VerifyReceiptSafetyTimeout time.Duration
VerifyReceiptRetryDelay time.Duration

// Non directly configurable option
allowEmptyAttestationService bool `json:"-"`
}

// AllowEmptyAttestationService allows the attestation service URL to be
// empty. This is set explicitly from a public method, and isn't derivable
// from serialization or any other form other than this method. This allows
// this setting to be configured via the code, but not externally.
func (c *CLIConfig) AllowEmptyAttestationService() {
c.allowEmptyAttestationService = true
}

func (c CLIConfig) Check() error {
if c.Enabled {
// Check required fields when Espresso is enabled
if len(c.QueryServiceURLs) == 0 {
return fmt.Errorf("query service URLs are required when Espresso is enabled")
}
if c.LightClientAddr == (common.Address{}) {
return fmt.Errorf("light client address is required when Espresso is enabled")
}
if c.L1URL == "" {
return fmt.Errorf("L1 URL is required when Espresso is enabled")
}
if c.RollupL1URL == "" {
return fmt.Errorf("rollup L1 URL is required when Espresso is enabled")
}
if c.Namespace == 0 {
return fmt.Errorf("namespace is required when Espresso is enabled")
}
if !c.allowEmptyAttestationService && c.EspressoAttestationService == "" {
return fmt.Errorf("attestation service URL is required when Espresso is enabled")
}
if c.VerifyReceiptMaxBlocks == 0 {
return fmt.Errorf("verify-receipt-max-blocks must be > 0")
}
if c.VerifyReceiptSafetyTimeout <= 0 {
return fmt.Errorf("verify-receipt-safety-timeout must be > 0")
}
if c.VerifyReceiptRetryDelay <= 0 {
return fmt.Errorf("verify-receipt-retry-delay must be > 0")
}
}
return nil
}

func ReadCLIConfig(c *cli.Context) CLIConfig {
config := CLIConfig{
Enabled: c.Bool(EnabledFlagName),
PollInterval: c.Duration(PollIntervalFlagName),
L1URL: c.String(L1UrlFlagName),
RollupL1URL: c.String(RollupL1UrlFlagName),
Namespace: c.Uint64(NamespaceFlagName),
CaffeinationHeightEspresso: c.Uint64(CaffeinationHeightEspresso),
CaffeinationHeightL2: c.Uint64(CaffeinationHeightL2),
EspressoAttestationService: c.String(AttestationServiceFlagName),
VerifyReceiptMaxBlocks: c.Uint64(VerifyReceiptMaxBlocksFlagName),
VerifyReceiptSafetyTimeout: c.Duration(VerifyReceiptSafetyTimeoutFlagName),
VerifyReceiptRetryDelay: c.Duration(VerifyReceiptRetryDelayFlagName),
}

config.QueryServiceURLs = c.StringSlice(QueryServiceUrlsFlagName)

addrStr := c.String(LightClientAddrFlagName)
config.LightClientAddr = common.HexToAddress(addrStr)

batchAuthenticatorAddrStr := c.String(BatchAuthenticatorAddrFlagName)
config.BatchAuthenticatorAddr = common.HexToAddress(batchAuthenticatorAddrStr)

pkStr := c.String(TestingBatcherPrivateKeyFlagName)
pkStr = strings.TrimPrefix(pkStr, "0x")
pk, err := crypto.HexToECDSA(pkStr)
if err == nil {
config.TestingBatcherPrivateKey = pk
}

return config
}

func BatchStreamerFromCLIConfig[B op.Batch](
cfg CLIConfig,
log log.Logger,
unmarshalBatch func([]byte) (*B, error),
) (*op.BatchStreamer[B], error) {
if !cfg.Enabled {
return nil, fmt.Errorf("espresso is not enabled")
}

l1Client, err := ethclient.Dial(cfg.L1URL)
if err != nil {
return nil, fmt.Errorf("failed to dial L1 RPC at %s: %w", cfg.L1URL, err)
}

RollupL1Client, err := ethclient.Dial(cfg.RollupL1URL)
if err != nil {
return nil, fmt.Errorf("failed to dial Rollup L1 RPC at %s: %w", cfg.RollupL1URL, err)
}

urlZero := cfg.QueryServiceURLs[0]
espressoClient := espressoClient.NewClient(urlZero)

espressoLightClient, err := espressoLightClient.NewLightclientCaller(cfg.LightClientAddr, l1Client)
if err != nil {
return nil, fmt.Errorf("failed to create Espresso light client")
}

return op.NewEspressoStreamer(
cfg.Namespace,
NewAdaptL1BlockRefClient(l1Client),
NewAdaptL1BlockRefClient(RollupL1Client),
espressoClient,
espressoLightClient,
log,
unmarshalBatch,
cfg.CaffeinationHeightEspresso,
cfg.CaffeinationHeightL2,
cfg.BatchAuthenticatorAddr,
false,
)
}
Loading