Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
9 changes: 0 additions & 9 deletions op-batcher/batcher/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,6 @@ type CLIConfig struct {
PprofConfig oppprof.CLIConfig
RPC oprpc.CLIConfig
AltDA altda.CLIConfig

// FallbackAuthLeadTime is the lead time for the fallback batcher's
// authentication gate. See BatcherConfig.FallbackAuthLeadTime in
// service.go and isFallbackAuthRequired in espresso_active.go.
FallbackAuthLeadTime time.Duration
}

func (c *CLIConfig) Check() error {
Expand Down Expand Up @@ -196,9 +191,6 @@ func (c *CLIConfig) Check() error {
if !flags.ValidDataAvailabilityType(c.DataAvailabilityType) {
return fmt.Errorf("unknown data availability type: %q", c.DataAvailabilityType)
}
if c.FallbackAuthLeadTime <= 0 {
return fmt.Errorf("FallbackAuthLeadTime must be positive: %v", c.FallbackAuthLeadTime)
}
// Most chains' L1s still have only Cancun active, but we don't want to
// overcomplicate this check with a dynamic L1 query, so we just use maxBlobsPerBlock.
// We want to check for both, blobs and auto da-type.
Expand Down Expand Up @@ -256,7 +248,6 @@ func NewConfig(ctx *cli.Context) *CLIConfig {
PprofConfig: oppprof.ReadCLIConfig(ctx),
RPC: oprpc.ReadCLIConfig(ctx),
AltDA: altda.ReadCLIConfig(ctx),
FallbackAuthLeadTime: ctx.Duration(flags.FallbackAuthLeadTimeFlag.Name),
ThrottleConfig: ThrottleConfig{
AdditionalEndpoints: ctx.StringSlice(flags.AdditionalThrottlingEndpointsFlag.Name),
TxSizeLowerLimit: ctx.Uint64(flags.ThrottleTxSizeLowerLimitFlag.Name),
Expand Down
11 changes: 0 additions & 11 deletions op-batcher/batcher/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func validBatcherConfig() batcher.CLIConfig {
BatchType: 0,
DataAvailabilityType: flags.CalldataType,
TxMgrConfig: txmgr.NewCLIConfig("fake", txmgr.DefaultBatcherFlagValues),
FallbackAuthLeadTime: flags.FallbackAuthLeadTimeFlag.Value,
LogConfig: log.DefaultCLIConfig(),
MetricsConfig: metrics.DefaultCLIConfig(),
PprofConfig: oppprof.DefaultCLIConfig(),
Expand Down Expand Up @@ -107,16 +106,6 @@ func TestBatcherConfig(t *testing.T) {
override: func(c *batcher.CLIConfig) { c.DataAvailabilityType = "foo" },
errString: "unknown data availability type: \"foo\"",
},
{
name: "negative fallback auth lead time",
override: func(c *batcher.CLIConfig) { c.FallbackAuthLeadTime = -time.Second },
errString: "FallbackAuthLeadTime must be positive",
},
{
name: "zero fallback auth lead time",
override: func(c *batcher.CLIConfig) { c.FallbackAuthLeadTime = 0 },
errString: "FallbackAuthLeadTime must be positive",
},
{
name: "zero TargetNumFrames",
override: func(c *batcher.CLIConfig) { c.TargetNumFrames = 0 },
Expand Down
33 changes: 11 additions & 22 deletions op-batcher/batcher/espresso_active.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package batcher
import (
"context"
"fmt"
"time"

"github.com/ethereum/go-ethereum/common"
)
Expand All @@ -14,25 +13,16 @@ import (
// zero BatchAuthenticatorAddress, indicating that the BatchAuthenticator-based
// authentication path is not in use.
//
// This decision must align with the verifier's per-L1-block fork gate
// (rollupCfg.IsEspresso(l1OriginTime) in data_source.go, which evaluates the
// hardfork activation predicate against the *containing* L1 block's timestamp). Since
// the tx is not yet mined at decision time, its eventual containing block
// has a strictly greater timestamp than the L1 tip the batcher observes:
//
// l1Tip.Time (batcher's view) < l1OriginTime (block containing the tx)
//
// Without compensation, in the window [forkTime − maxL1InclusionDelay, forkTime)
// the batcher would skip authenticateBatchInfo while the verifier — once the
// tx lands in a post-fork block — would require the resulting
// BatchInfoAuthenticated event, silently dropping the batch.
//
// To prevent this, we add Config.FallbackAuthLeadTime to the L1 tip's
// timestamp before evaluating the fork predicate. This makes the batcher
// start authenticating slightly before the verifier requires it. The reverse
// asymmetry (authenticated tx lands pre-fork) is harmless: pre-fork the
// verifier uses sender-based authorization and the auth event is just an
// unrelated L1 tx that does not affect derivation.
// The batcher switches at Espresso activation (tip.Time >= EspressoTime), while the
// verifier only starts enforcing event-based authentication one grace period later
// (derive.BatchAuthEnforcementDelay).
// The gap absorbs the delay between the batcher's gate decision (based on L1 tip time)
// and the batch tx's eventual inclusion (based on containing-block time): a batch
// decided pre-fork that lands post-activation is still accepted under sender
// authorization as long as its inclusion delay stays below the grace period (~20 min).
// The reverse asymmetry (authenticated tx lands before enforcement) is harmless:
// pre-enforcement the verifier uses sender-based authorization and the auth event is
// just an unrelated L1 tx that does not affect derivation.
func (l *BatchSubmitter) isFallbackAuthRequired(ctx context.Context) (bool, error) {
if l.RollupConfig.BatchAuthenticatorAddress == (common.Address{}) {
return false, nil
Expand All @@ -41,6 +31,5 @@ func (l *BatchSubmitter) isFallbackAuthRequired(ctx context.Context) (bool, erro
if err != nil {
return false, fmt.Errorf("failed to fetch L1 tip for fallback-auth gate: %w", err)
}
leadSec := uint64(l.Config.FallbackAuthLeadTime / time.Second)
return l.RollupConfig.IsEspresso(tip.Time + leadSec), nil
return l.RollupConfig.IsEspresso(tip.Time), nil
Comment thread
piersy marked this conversation as resolved.
}
9 changes: 0 additions & 9 deletions op-batcher/batcher/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,6 @@ type BatcherConfig struct {

// For throttling DA. See CLIConfig in config.go for details on these parameters.
ThrottleParams config.ThrottleParams

// FallbackAuthLeadTime is consulted by the fallback batcher's
// authentication gate to advance the switch to authenticated batches
// relative to the on-chain EspressoTime hardfork. It absorbs the
// worst-case L1 inclusion delay between batcher decision time (L1 tip)
// and verifier evaluation time (containing L1 block). See
// isFallbackAuthRequired in espresso_active.go for details.
FallbackAuthLeadTime time.Duration
}

// BatcherService represents a full batch-submitter instance and its resources,
Expand Down Expand Up @@ -117,7 +109,6 @@ func (bs *BatcherService) initFromCLIConfig(ctx context.Context, closeApp contex
bs.NetworkTimeout = cfg.TxMgrConfig.NetworkTimeout
bs.CheckRecentTxsDepth = cfg.CheckRecentTxsDepth
bs.WaitNodeSync = cfg.WaitNodeSync
bs.FallbackAuthLeadTime = cfg.FallbackAuthLeadTime

bs.ThrottleParams = config.ThrottleParams{
LowerThreshold: cfg.ThrottleConfig.LowerThreshold,
Expand Down
16 changes: 0 additions & 16 deletions op-batcher/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,21 +160,6 @@ var (
Value: false,
EnvVars: prefixEnvVars("WAIT_NODE_SYNC"),
}
FallbackAuthLeadTimeFlag = &cli.DurationFlag{
Name: "espresso.fallback-auth-lead-time",
Usage: "Lead time for the fallback batcher's Espresso authentication gate. " +
"How far ahead of the on-chain EspressoTime the fallback batcher " +
"starts routing batch txs through BatchAuthenticator.authenticateBatchInfo. " +
"This absorbs worst-case L1 inclusion delay between the batcher's decision " +
"(based on L1 tip time) and the verifier's gate (based on the containing " +
"L1 block's time). Has no effect outside the boundary window around the " +
"EspressoTime hardfork. Must not be negative, and must exceed the worst-case " +
"L1 inclusion delay: with 0 the safety margin is gone, and a batch decided " +
"pre-fork that lands in a post-fork block is silently dropped by the verifier.",
Value: 5 * time.Minute,
EnvVars: prefixEnvVars("ESPRESSO_FALLBACK_AUTH_LEAD_TIME"),
}

// Legacy Flags
SequencerHDPathFlag = txmgr.SequencerHDPathFlag
)
Expand Down Expand Up @@ -203,7 +188,6 @@ var optionalFlags = []cli.Flag{
DataAvailabilityTypeFlag,
ActiveSequencerCheckDurationFlag,
CompressionAlgoFlag,
FallbackAuthLeadTimeFlag,
}

func init() {
Expand Down
11 changes: 11 additions & 0 deletions op-node/rollup/derive/batch_authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,20 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"

"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/eth"
)

// isEspressoAuthEnforced returns true once event-based batch authentication is enforced
// at the given L1 origin time: the Espresso fork is active AND at least
// BatchAuthEnforcementDelay has elapsed since activation. Before that, derivation keeps
// accepting sender-authenticated batches.
// The batcher's fallback-auth gate (op-batcher espresso_active.go)
// switches at plain activation time, a full grace period earlier.
func isEspressoAuthEnforced(cfg *rollup.Config, l1OriginTime uint64) bool {
return cfg.IsEspresso(l1OriginTime) && l1OriginTime >= *cfg.EspressoTime+BatchAuthEnforcementDelaySecs
}

var (
// BatchInfoAuthenticatedABI is the event signature for
// BatchInfoAuthenticated(bytes32 commitment, address indexed caller).
Expand Down
18 changes: 9 additions & 9 deletions op-node/rollup/derive/blob_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,21 +119,21 @@ func (ds *BlobDataSource) open(ctx context.Context) ([]blobOrCalldata, error) {
// creates a placeholder blobOrCalldata element for each returned blob hash that must be populated
// by fillBlobPointers after blob bodies are retrieved.
//
// Pre-Espresso (the L1 origin time of `ref` is < *EspressoTime, or unset),
// this runs upstream Optimism semantics: filter by batch inbox + sender ==
// batcher.
// Before Espresso event-auth is enforced (Espresso inactive at the L1 origin time of
// `ref`, or within BatchAuthEnforcementDelay of activation), this runs upstream
// Optimism semantics: filter by batch inbox + sender == batcher.
//
// Post-Espresso, it collects all authenticated batch hashes from a lookback
// Once enforced, it collects all authenticated batch hashes from a lookback
// window once and rejects any batch whose commitment hash is not in the
// authenticated set. For blob transactions, the batch hash is computed from
// the concatenated blob versioned hashes.
func dataAndHashesFromTxs(ctx context.Context, txs types.Transactions, config *DataSourceConfig, batcherAddr common.Address, fetcher L1Fetcher, ref eth.L1BlockRef, logger log.Logger) ([]blobOrCalldata, []common.Hash, error) {
// Only collect authenticated batch commitments when the Espresso fork is
// active at the L1 origin time of the block we're scanning. Pre-fork, the
// upstream sender-based authorization path is used and authenticatedHashes
// is unused.
// Only collect authenticated batch commitments once event-based authentication is
// enforced at the L1 origin time of the block we're scanning (Espresso active plus
// the enforcement grace period). Before that, the upstream sender-based
// authorization path is used and authenticatedHashes is unused.
var authenticatedHashes map[common.Hash]common.Address
if config.rollupCfg.IsEspresso(ref.Time) {
if isEspressoAuthEnforced(config.rollupCfg, ref.Time) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Accept authenticated Espresso batches during grace

For chains that switch the BatchAuthenticator to a non-SystemConfig Espresso/TEE batcher at EspressoTime, this gate leaves authenticatedHashes nil for the whole grace window; isBatchTxAuthorized then takes the sender-only pre-enforcement branch and rejects otherwise valid authenticated batches from the Espresso batcher until EspressoTime + BatchAuthEnforcementDelaySecs. That turns the grace period into a 20-minute delay before the new authenticated batcher can derive, likely stalling the safe head during cutover; the grace window should allow authenticated batches while also allowing legacy sender-auth batches.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this as a major issue, the espresso hardfork is a one off event and it's easy for us to co-ordinate when to enable the espresso batcher.

var err error
authenticatedHashes, err = CollectAuthenticatedBatches(
ctx, fetcher, ref, config.rollupCfg.BatchAuthenticatorAddress, config.batchAuthCaches, logger,
Expand Down
10 changes: 6 additions & 4 deletions op-node/rollup/derive/data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,13 @@ func isAuthorizedBatchSender(tx *types.Transaction, l1Signer types.Signer, batch
// block (passed as l1OriginTime), mirroring the data-source layer's ecotoneTime
// treatment.
//
// Pre-Espresso (l1OriginTime < *EspressoTime, or unset):
// Before enforcement (Espresso inactive, or within BatchAuthEnforcementDelay of
// activation):
//
// upstream behavior — the L1 sender of the transaction must match the configured
// batcher address. The authenticatedHashes map is unused.
//
// Post-Espresso:
// Once enforced:
//
// the batch's commitment hash must appear in authenticatedHashes (i.e. a
// BatchInfoAuthenticated event was emitted for this commitment within the
Expand All @@ -188,8 +189,9 @@ func isBatchTxAuthorized(
l1OriginTime uint64,
logger log.Logger,
) bool {
if !dsCfg.rollupCfg.IsEspresso(l1OriginTime) {
// Pre-fork: upstream sender-based authorization.
if !isEspressoAuthEnforced(dsCfg.rollupCfg, l1OriginTime) {
// Pre-enforcement (pre-fork or within the grace period): upstream
// sender-based authorization.
return isAuthorizedBatchSender(tx, dsCfg.l1Signer, batcherAddr, logger)
}
// Post-fork: the commitment must have been authenticated within the lookback window.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is now not fully correct

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!
317aec3

Expand Down
Loading