Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
99 changes: 99 additions & 0 deletions espresso/environment/5_batch_authentication_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package environment_test

import (
"context"
"math/big"
"strings"
"testing"
"time"

env "github.com/ethereum-optimism/optimism/espresso/environment"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum/go-ethereum/crypto"
)

// TestE2eDevNetWithInvalidAttestation verifies that the batcher correctly fails to register
// when provided with an invalid attestation. This test ensures that the batch inbox contract
// properly validates attestations
func TestE2eDevNetWithInvalidAttestation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

launcher := new(env.EspressoDevNodeLauncherDocker)

privateKey, err := crypto.GenerateKey()
if err != nil {
t.Fatalf("failed to generate private key")
}

system, _, err :=
launcher.StartDevNet(ctx, t,
env.SetBatcherKey(*privateKey),
env.Config(func(cfg *e2esys.SystemConfig) {
cfg.DisableBatcher = true
}),
)

if have, want := err, error(nil); have != want {
t.Fatalf("failed to start dev environment with espresso dev node:\nhave:\n\t\"%v\"\nwant:\n\t\"%v\"\n", have, want)
}

batchDriver := system.BatchSubmitter.TestDriver()
batchDriver.Attestation = []byte{1}
err = batchDriver.StartBatchSubmitting()

if err == nil {
t.Fatalf("batcher should've failed to register with invalid attestation but got nil error")
}

// Check for the key part of the error message
expectedMsg := "could not register with batch inbox contract"
errMsg := err.Error()
if !strings.Contains(errMsg, expectedMsg) {
t.Fatalf("error message does not contain expected message %q:\ngot: %q", expectedMsg, errMsg)
}

cancel()
}

// TestE2eDevNetWithUnattestedBatcherKey verifies that when a batcher key is not properly
// attested, the L2 chain can still produce unsafe blocks but cannot progress to safe L2 blocks.
func TestE2eDevNetWithUnattestedBatcherKey(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

launcher := new(env.EspressoDevNodeLauncherDocker)

privateKey, err := crypto.GenerateKey()
if err != nil {
t.Fatalf("failed to generate private key")
}

system, _, err :=
launcher.StartDevNet(ctx, t,
env.SetBatcherKey(*privateKey),
)
if have, want := err, error(nil); have != want {
t.Fatalf("failed to start dev environment with espresso dev node:\nhave:\n\t\"%v\"\nwant:\n\t\"%v\"\n", have, want)
}

l2Seq := system.NodeClient("sequencer")

// Check that unsafe L2 is progressing...
_, err = geth.WaitForBlock(big.NewInt(15), l2Seq)
if have, want := err, error(nil); have != want {
t.Fatalf("failed to wait for block:\nhave:\n\t\"%v\"\nwant:\n\t\"%v\"\n", have, want)
}

// ...but safe L2 is not
_, err = geth.WaitForBlockToBeSafe(big.NewInt(1), l2Seq, 2*time.Minute)
if err == nil {
t.Fatalf("block shouldn't be safe")
}

_ = system

// Signal the testnet to shut down
cancel()
}
5 changes: 5 additions & 0 deletions espresso/environment/espresso_dev_net_launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type DevNetLauncherContext struct {
// Any Current Error
Error error

// The Current System configuration
SystemCfg *e2esys.SystemConfig

// The Current System instance
System *e2esys.System

Expand All @@ -45,6 +48,8 @@ type DevNetLauncherOption func(
// e2e system that is being launched. It contains the GethOptions and
// any relevant StartOptions that may be needed for the system.
type E2eSystemOption struct {
SysConfigOption func(*e2esys.SystemConfig)

// The GethOptions to pass to the Geth Node.
GethOptions map[string][]geth.GethOption

Expand Down
40 changes: 38 additions & 2 deletions espresso/environment/optitmism_espresso_test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package environment
import (
"bytes"
"context"
"crypto/ecdsa"
"errors"
"fmt"
"io"
"log/slog"
"math/big"
"net"
"net/http"
Expand All @@ -20,6 +22,8 @@ import (
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/ethconfig"
gethNode "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
Expand All @@ -37,6 +41,8 @@ const ESPRESSO_MNEMONIC = "giant issue aisle success illegal bike spike question
// contracts on the L1
const ESPRESSO_MNEMONIC_INDEX = "0"

const ESPRESSO_TESTING_BATCHER_KEY = "0xfad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19"

// This is address that corresponds to the menmonic we pass to the espresso-dev-node
var ESPRESSO_CONTRACT_ACCOUNT = common.HexToAddress("0x8943545177806ed17b9f23f0a21ee5948ecaa776")

Expand Down Expand Up @@ -207,7 +213,7 @@ var ErrUnableToDetermineEspressoDevNodeSequencerHost = errors.New("unable to det
func (l *EspressoDevNodeLauncherDocker) StartDevNet(ctx context.Context, t *testing.T, options ...DevNetLauncherOption) (*e2esys.System, EspressoDevNode, error) {
originalCtx := ctx

sysConfig := e2esys.DefaultSystemConfig(t, e2esys.WithAllocType(config.AllocTypeStandard))
sysConfig := e2esys.DefaultSystemConfig(t, e2esys.WithAllocType(config.AllocTypeEspresso))
sysConfig.DeployConfig.DeployCeloContracts = true

// Ensure that we fund the dev accounts
Expand All @@ -223,7 +229,8 @@ func (l *EspressoDevNodeLauncherDocker) StartDevNet(ctx context.Context, t *test
}

launchContext := DevNetLauncherContext{
Ctx: originalCtx,
Ctx: originalCtx,
SystemCfg: &sysConfig,
}

allOptions := append(initialOptions, options...)
Expand All @@ -243,6 +250,10 @@ func (l *EspressoDevNodeLauncherDocker) StartDevNet(ctx context.Context, t *test
if startOption := options.StartOptions; startOption != nil {
startOptions = append(startOptions, startOption...)
}

if sysConfigOption := options.SysConfigOption; sysConfigOption != nil {
sysConfigOption(&sysConfig)
}
}

// We want to run the espresso-dev-node. But we need it to be able to
Expand Down Expand Up @@ -356,6 +367,29 @@ func determineFreePort() (port int, err error) {
return addr.Port, nil
}

func SetBatcherKey(privateKey ecdsa.PrivateKey) DevNetLauncherOption {
return func(ct *DevNetLauncherContext) E2eSystemOption {
return E2eSystemOption{
StartOptions: []e2esys.StartOption{
{
Role: "set-batcher-key",
BatcherMod: func(c *batcher.CLIConfig) {
c.TestingEspressoBatcherPrivateKey = hexutil.Encode(crypto.FromECDSA(&privateKey))
},
},
},
}
}
}

func Config(fn func(*e2esys.SystemConfig)) DevNetLauncherOption {
return func(ct *DevNetLauncherContext) E2eSystemOption {
return E2eSystemOption{
SysConfigOption: fn,
}
}
}

// launchEspressoDevNodeDocker is DevNetLauncherOption that launches th
// Espresso Dev Node within a Docker container. It also ensures that the
// Espresso Dev Node is actively producing blocks before returning.
Expand Down Expand Up @@ -515,6 +549,8 @@ func launchEspressoDevNodeDocker() DevNetLauncherOption {
}

c.EspressoUrl = "http://" + hostPort
c.LogConfig.Level = slog.LevelDebug
c.TestingEspressoBatcherPrivateKey = "0x" + config.ESPRESSO_PRE_APPROVED_BATCHER_PRIVATE_KEY
}
},
},
Expand Down
60 changes: 31 additions & 29 deletions op-batcher/batcher/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@ type CLIConfig struct {
RPC oprpc.CLIConfig
AltDA altda.CLIConfig

EspressoUrl string
EspressoLightClientAddr string
EspressoUrl string
EspressoLightClientAddr string
TestingEspressoBatcherPrivateKey string
}

func (c *CLIConfig) Check() error {
Expand Down Expand Up @@ -194,32 +195,33 @@ func NewConfig(ctx *cli.Context) *CLIConfig {
EspressoPollInterval: ctx.Duration(flags.EspressoPollIntervalFlag.Name),

/* Optional Flags */
MaxPendingTransactions: ctx.Uint64(flags.MaxPendingTransactionsFlag.Name),
MaxChannelDuration: ctx.Uint64(flags.MaxChannelDurationFlag.Name),
MaxL1TxSize: ctx.Uint64(flags.MaxL1TxSizeBytesFlag.Name),
MaxBlocksPerSpanBatch: ctx.Int(flags.MaxBlocksPerSpanBatch.Name),
TargetNumFrames: ctx.Int(flags.TargetNumFramesFlag.Name),
ApproxComprRatio: ctx.Float64(flags.ApproxComprRatioFlag.Name),
Compressor: ctx.String(flags.CompressorFlag.Name),
CompressionAlgo: derive.CompressionAlgo(ctx.String(flags.CompressionAlgoFlag.Name)),
Stopped: ctx.Bool(flags.StoppedFlag.Name),
WaitNodeSync: ctx.Bool(flags.WaitNodeSyncFlag.Name),
CheckRecentTxsDepth: ctx.Int(flags.CheckRecentTxsDepthFlag.Name),
BatchType: ctx.Uint(flags.BatchTypeFlag.Name),
DataAvailabilityType: flags.DataAvailabilityType(ctx.String(flags.DataAvailabilityTypeFlag.Name)),
ActiveSequencerCheckDuration: ctx.Duration(flags.ActiveSequencerCheckDurationFlag.Name),
TxMgrConfig: txmgr.ReadCLIConfig(ctx),
LogConfig: oplog.ReadCLIConfig(ctx),
MetricsConfig: opmetrics.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx),
RPC: oprpc.ReadCLIConfig(ctx),
AltDA: altda.ReadCLIConfig(ctx),
ThrottleThreshold: ctx.Uint64(flags.ThrottleThresholdFlag.Name),
ThrottleTxSize: ctx.Uint64(flags.ThrottleTxSizeFlag.Name),
ThrottleBlockSize: ctx.Uint64(flags.ThrottleBlockSizeFlag.Name),
ThrottleAlwaysBlockSize: ctx.Uint64(flags.ThrottleAlwaysBlockSizeFlag.Name),
PreferLocalSafeL2: ctx.Bool(flags.PreferLocalSafeL2Flag.Name),
EspressoUrl: ctx.String(flags.EspressoUrlFlag.Name),
EspressoLightClientAddr: ctx.String(flags.EspressoLCAddrFlag.Name),
MaxPendingTransactions: ctx.Uint64(flags.MaxPendingTransactionsFlag.Name),
MaxChannelDuration: ctx.Uint64(flags.MaxChannelDurationFlag.Name),
MaxL1TxSize: ctx.Uint64(flags.MaxL1TxSizeBytesFlag.Name),
MaxBlocksPerSpanBatch: ctx.Int(flags.MaxBlocksPerSpanBatch.Name),
TargetNumFrames: ctx.Int(flags.TargetNumFramesFlag.Name),
ApproxComprRatio: ctx.Float64(flags.ApproxComprRatioFlag.Name),
Compressor: ctx.String(flags.CompressorFlag.Name),
CompressionAlgo: derive.CompressionAlgo(ctx.String(flags.CompressionAlgoFlag.Name)),
Stopped: ctx.Bool(flags.StoppedFlag.Name),
WaitNodeSync: ctx.Bool(flags.WaitNodeSyncFlag.Name),
CheckRecentTxsDepth: ctx.Int(flags.CheckRecentTxsDepthFlag.Name),
BatchType: ctx.Uint(flags.BatchTypeFlag.Name),
DataAvailabilityType: flags.DataAvailabilityType(ctx.String(flags.DataAvailabilityTypeFlag.Name)),
ActiveSequencerCheckDuration: ctx.Duration(flags.ActiveSequencerCheckDurationFlag.Name),
TxMgrConfig: txmgr.ReadCLIConfig(ctx),
LogConfig: oplog.ReadCLIConfig(ctx),
MetricsConfig: opmetrics.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx),
RPC: oprpc.ReadCLIConfig(ctx),
AltDA: altda.ReadCLIConfig(ctx),
ThrottleThreshold: ctx.Uint64(flags.ThrottleThresholdFlag.Name),
ThrottleTxSize: ctx.Uint64(flags.ThrottleTxSizeFlag.Name),
ThrottleBlockSize: ctx.Uint64(flags.ThrottleBlockSizeFlag.Name),
ThrottleAlwaysBlockSize: ctx.Uint64(flags.ThrottleAlwaysBlockSizeFlag.Name),
PreferLocalSafeL2: ctx.Bool(flags.PreferLocalSafeL2Flag.Name),
EspressoUrl: ctx.String(flags.EspressoUrlFlag.Name),
EspressoLightClientAddr: ctx.String(flags.EspressoLCAddrFlag.Name),
TestingEspressoBatcherPrivateKey: ctx.String(flags.TestingEspressoBatcherPrivateKeyFlag.Name),
}
}
5 changes: 5 additions & 0 deletions op-batcher/batcher/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ func (l *BatchSubmitter) StartBatchSubmitting() error {
}

if l.Config.UseEspresso {
err := l.registerBatcher(l.killCtx)
if err != nil {
return fmt.Errorf("could not register with batch inbox contract: %w", err)
}

l.wg.Add(4)
go l.receiptsLoop(l.wg, receiptsCh) // ranges over receiptsCh channel
go l.espressoBatchQueueingLoop(l.shutdownCtx, l.wg)
Expand Down
13 changes: 4 additions & 9 deletions op-batcher/batcher/espresso.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,6 @@ func (l *BatchSubmitter) espressoBatchLoadingLoop(ctx context.Context, wg *sync.
defer ticker.Stop()
defer close(publishSignal)

err := l.registerBatcher(ctx)
if err != nil {
l.Log.Error("could not register with batch inbox contract", "err", err)
return
}

streamer := espresso.NewEspressoStreamer(
l.RollupConfig.L2ChainID.Uint64(),
l.L1Client,
Expand Down Expand Up @@ -341,7 +335,7 @@ func (l *BatchSubmitter) registerBatcher(ctx context.Context) error {
return nil
}

batchAuthenticator, err := bindings.NewBatchAuthenticator(l.RollupConfig.CaffNodeConfig.BatchAuthenticatorAddress, l.L1Client)
batchAuthenticator, err := bindings.NewBatchAuthenticator(l.RollupConfig.BatchAuthenticatorAddress, l.L1Client)
if err != nil {
return fmt.Errorf("failed to create batch authenticator contract bindings: %w", err)
}
Expand Down Expand Up @@ -436,18 +430,19 @@ func (l *BatchSubmitter) sendEspressoTx(txdata txData, isCancel bool, candidate

verifyCandidate := txmgr.TxCandidate{
TxData: authenticateBatchCalldata,
To: &l.RollupConfig.CaffNodeConfig.BatchAuthenticatorAddress,
To: &l.RollupConfig.BatchAuthenticatorAddress,
}

l.Log.Debug(
"Sending authenticateBatch transaction",
"txRef", transactionReference,
"commitment", hexutil.Encode(commitment[:]),
"sig", hexutil.Encode(signature),
"address", l.RollupConfig.CaffNodeConfig.BatchAuthenticatorAddress.String(),
"address", l.RollupConfig.BatchAuthenticatorAddress.String(),
)
_, err = l.Txmgr.Send(l.killCtx, verifyCandidate)
if err != nil {
l.Log.Error("Failed to send authenticateBatch transaction", "txRef", transactionReference, "err", err)
receiptsCh <- txmgr.TxReceipt[txRef]{
ID: transactionReference,
Err: fmt.Errorf("failed to send authenticateBatch transaction: %w", err),
Expand Down
4 changes: 2 additions & 2 deletions op-batcher/batcher/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ func (bs *BatcherService) initFromCLIConfig(ctx context.Context, version string,
if err != nil {
bs.Log.Info("Not running in enclave, skipping attestation", "info", err)

// Replace ephemeral keys with persistent keys, as in devnet they'll be pre-approved for batching
privateKey, err := crypto.HexToECDSA(strings.TrimPrefix(cfg.TxMgrConfig.PrivateKey, "0x"))
// Replace ephemeral keys with configured keys, as in devnet they'll be pre-approved for batching
privateKey, err := crypto.HexToECDSA(strings.TrimPrefix(cfg.TestingEspressoBatcherPrivateKey, "0x"))
if err != nil {
return fmt.Errorf("Failed to parse batcher's private key")
}
Expand Down
6 changes: 6 additions & 0 deletions op-batcher/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ var (
Value: "0x703848f4c85f18e3acd8196c8ec91eb0b7bd0797",
EnvVars: prefixEnvVars("ESPRESSO_LIGHT_CLIENT_ADDR"),
}
TestingEspressoBatcherPrivateKeyFlag = &cli.StringFlag{
Name: "testing-espresso-batcher-private-key",
Usage: "Private key of batcher in Espresso mode: ONLY FOR TESTING",
Value: "",
EnvVars: prefixEnvVars("TESTING_ESPRESSO_BATCHER_PRIVATE_KEY"),
}
// Legacy Flags
SequencerHDPathFlag = txmgr.SequencerHDPathFlag
)
Expand Down
Loading