diff --git a/op-node/rollup/clsync/clsync.go b/op-node/rollup/clsync/clsync.go index 3286f4c1afd1..0a412b9794a1 100644 --- a/op-node/rollup/clsync/clsync.go +++ b/op-node/rollup/clsync/clsync.go @@ -39,6 +39,7 @@ type L1OriginSelector interface { type CLSync struct { log log.Logger cfg *rollup.Config + spec *rollup.ChainSpec metrics Metrics ec Engine n Network @@ -52,6 +53,7 @@ func NewCLSync(log log.Logger, cfg *rollup.Config, metrics Metrics, ec Engine, n return &CLSync{ log: log, cfg: cfg, + spec: rollup.NewChainSpec(cfg), metrics: metrics, ec: ec, n: n, @@ -162,6 +164,12 @@ func (eq *CLSync) PublishAttributes(ctx context.Context, l2head eth.L2BlockRef) return fmt.Errorf("error preparing payload attributes: %w", err) } + derive.SetNoTxPool(eq.cfg, eq.spec, attrs, l1Origin, l2head) + + eq.log.Debug("prepared attributes for new block", + "num", l2head.Number+1, "time", uint64(attrs.Timestamp), + "origin", l1Origin, "origin_time", l1Origin.Time, "noTxPool", attrs.NoTxPool) + withParent := &derive.AttributesWithParent{ Attributes: attrs, Parent: l2head, diff --git a/op-node/rollup/derive/attributes.go b/op-node/rollup/derive/attributes.go index c65198bcec73..2dd447575b48 100644 --- a/op-node/rollup/derive/attributes.go +++ b/op-node/rollup/derive/attributes.go @@ -150,3 +150,22 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex ParentBeaconBlockRoot: parentBeaconRoot, }, nil } + +// Sets NoTxPool according to config and spec. +func SetNoTxPool(config *rollup.Config, spec *rollup.ChainSpec, attrs *eth.PayloadAttributes, l1Origin eth.L1BlockRef, l2head eth.L2BlockRef) { + // If our next L2 block timestamp is beyond the Sequencer drift threshold, then we must produce + // empty blocks (other than the L1 info deposit and any user deposits). We handle this by + // setting NoTxPool to true, which will cause the Sequencer to not include any transactions + // from the transaction pool. + attrs.NoTxPool = uint64(attrs.Timestamp) > l1Origin.Time+spec.MaxSequencerDrift(l1Origin.Time) + + // For the Ecotone activation block we shouldn't include any sequencer transactions. + if config.IsEcotoneActivationBlock(uint64(attrs.Timestamp)) { + attrs.NoTxPool = true + } + + // For the Fjord activation block we shouldn't include any sequencer transactions. + if config.IsFjordActivationBlock(uint64(attrs.Timestamp)) { + attrs.NoTxPool = true + } +} diff --git a/op-node/rollup/driver/driver.go b/op-node/rollup/driver/driver.go index dc65a1d75ba6..0d21786b0e9b 100644 --- a/op-node/rollup/driver/driver.go +++ b/op-node/rollup/driver/driver.go @@ -190,6 +190,7 @@ func NewDriver( sequencerActive: make(chan chan bool, 10), sequencerNotifs: sequencerStateListener, config: cfg, + spec: rollup.NewChainSpec(cfg), syncCfg: syncCfg, driverConfig: driverCfg, driverCtx: driverCtx, diff --git a/op-node/rollup/driver/state.go b/op-node/rollup/driver/state.go index b9b5c4f5e514..7c00877838f8 100644 --- a/op-node/rollup/driver/state.go +++ b/op-node/rollup/driver/state.go @@ -73,6 +73,7 @@ type Driver struct { // Rollup config: rollup chain configuration config *rollup.Config + spec *rollup.ChainSpec sequencerConductor conductor.SequencerConductor @@ -493,6 +494,12 @@ func (d *Driver) PublishL2Attributes(ctx context.Context, l2head eth.L2BlockRef) return err } + derive.SetNoTxPool(d.config, d.spec, attrs, l1Origin, l2head) + + d.log.Debug("prepared attributes for new block", + "num", l2head.Number+1, "time", uint64(attrs.Timestamp), + "origin", l1Origin, "origin_time", l1Origin.Time, "noTxPool", attrs.NoTxPool) + withParent := &derive.AttributesWithParent{ Attributes: attrs, Parent: l2head,