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
3 changes: 3 additions & 0 deletions op-e2e/actions/helpers/l2_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ func NewL2Verifier(t Testing, log log.Logger, l1 derive.L1Fetcher,
syncStatusTracker := status.NewStatusTracker(log, metrics)
sys.Register("status", syncStatusTracker, opts)

// TODO(#17115): Refactor dependency cycles
ec.SetCrossUpdateHandler(syncStatusTracker)

stepDeriver := NewTestingStepSchedulingDeriver()
stepDeriver.AttachEmitter(testActionEmitter)

Expand Down
2 changes: 2 additions & 0 deletions op-node/rollup/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ func NewDriver(
verifConfDepth := confdepth.NewConfDepth(driverCfg.VerifierConfDepth, statusTracker.L1Head, l1)

ec := engine.NewEngineController(driverCtx, l2, log, metrics, cfg, syncCfg, sys.Register("engine-controller", nil))
// TODO(#17115): Refactor dependency cycles
ec.SetCrossUpdateHandler(statusTracker)

sys.Register("engine-reset",
engine.NewEngineResetDeriver(driverCtx, log, cfg, l1, l2, syncCfg))
Expand Down
5 changes: 0 additions & 5 deletions op-node/rollup/driver/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,6 @@ func (s *SyncDeriver) SyncStep() {
// to generate new attributes, if no attributes are known already.
s.Emitter.Emit(s.Ctx, engine.PendingSafeRequestEvent{})

// If interop is configured, we have to run the engine events,
// to ensure cross-L2 safety is continuously verified against the interop-backend.
if s.Config.InteropTime != nil && !s.ManagedBySupervisor {
s.Emitter.Emit(s.Ctx, engine.CrossUpdateRequestEvent{})
}
}

// ResetDerivationPipeline forces a reset of the derivation pipeline.
Expand Down
58 changes: 32 additions & 26 deletions op-node/rollup/engine/engine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ type SyncDeriver interface {
OnELSyncStarted()
}

// CrossUpdateHandler handles both cross-unsafe and cross-safe L2 head changes.
// Nil check required because op-program omits this handler.
type CrossUpdateHandler interface {
OnCrossUnsafeUpdate(ctx context.Context, crossUnsafe eth.L2BlockRef, localUnsafe eth.L2BlockRef)
OnCrossSafeUpdate(ctx context.Context, crossSafe eth.L2BlockRef, localSafe eth.L2BlockRef)
}

type EngineController struct {
engine ExecEngine // Underlying execution engine RPC
log log.Logger
Expand Down Expand Up @@ -102,6 +109,9 @@ type EngineController struct {
// EngineController is first initialized and used to initialize SyncDeriver.
// Embed SyncDeriver into EngineController after initializing SyncDeriver
SyncDeriver SyncDeriver

// Handler for cross-unsafe and cross-safe updates
crossUpdateHandler CrossUpdateHandler
}

func NewEngineController(ctx context.Context, engine ExecEngine, log log.Logger, m opmetrics.Metricer,
Expand Down Expand Up @@ -224,6 +234,24 @@ func (e *EngineController) SetBackupUnsafeL2Head(r eth.L2BlockRef, triggerReorg
e.needFCUCallForBackupUnsafeReorg = triggerReorg
}

func (e *EngineController) SetCrossUpdateHandler(handler CrossUpdateHandler) {
e.crossUpdateHandler = handler
}

func (e *EngineController) onUnsafeUpdate(ctx context.Context, crossUnsafe, localUnsafe eth.L2BlockRef) {
// Nil check required because op-program omits this handler.
if e.crossUpdateHandler != nil {
e.crossUpdateHandler.OnCrossUnsafeUpdate(ctx, crossUnsafe, localUnsafe)
}
}

func (e *EngineController) onSafeUpdate(ctx context.Context, crossSafe, localSafe eth.L2BlockRef) {
// Nil check required because op-program omits this handler.
if e.crossUpdateHandler != nil {
e.crossUpdateHandler.OnCrossSafeUpdate(ctx, crossSafe, localSafe)
}
}

// logSyncProgressMaybe helps log forkchoice state-changes when applicable.
// First, the pre-state is registered.
// A callback is returned to then log the changes to the pre-state, if any.
Expand Down Expand Up @@ -449,7 +477,7 @@ func (e *EngineController) InsertUnsafePayload(ctx context.Context, envelope *et
e.emitter.Emit(ctx, UnsafeUpdateEvent{Ref: ref})
e.SetLocalSafeHead(ref)
e.SetSafeHead(ref)
e.emitter.Emit(ctx, CrossSafeUpdateEvent{LocalSafe: ref, CrossSafe: ref})
e.onSafeUpdate(ctx, ref, ref)
e.SetFinalizedHead(ref)
}
logFn := e.logSyncProgressMaybe()
Expand Down Expand Up @@ -671,10 +699,7 @@ func (d *EngineController) OnEvent(ctx context.Context, ev event.Event) bool {
d.TryUpdateEngine(ctx)
case PromoteCrossUnsafeEvent:
d.SetCrossUnsafeHead(x.Ref)
d.emitter.Emit(ctx, CrossUnsafeUpdateEvent{
CrossUnsafe: x.Ref,
LocalUnsafe: d.UnsafeL2Head(),
})
d.onUnsafeUpdate(ctx, x.Ref, d.UnsafeL2Head())
case PendingSafeRequestEvent:
d.emitter.Emit(ctx, PendingSafeUpdateEvent{
PendingSafe: d.PendingSafeL2Head(),
Expand All @@ -691,17 +716,11 @@ func (d *EngineController) OnEvent(ctx context.Context, ev event.Event) bool {
d.SetSafeHead(x.Ref)
// Finalizer can pick up this safe cross-block now
d.emitter.Emit(ctx, SafeDerivedEvent{Safe: x.Ref, Source: x.Source})
d.emitter.Emit(ctx, CrossSafeUpdateEvent{
CrossSafe: d.SafeL2Head(),
LocalSafe: d.LocalSafeL2Head(),
})
d.onSafeUpdate(ctx, d.SafeL2Head(), d.LocalSafeL2Head())
if x.Ref.Number > d.crossUnsafeHead.Number {
d.log.Debug("Cross Unsafe Head is stale, updating to match cross safe", "cross_unsafe", d.crossUnsafeHead, "cross_safe", x.Ref)
d.SetCrossUnsafeHead(x.Ref)
d.emitter.Emit(ctx, CrossUnsafeUpdateEvent{
CrossUnsafe: x.Ref,
LocalUnsafe: d.UnsafeL2Head(),
})
d.onUnsafeUpdate(ctx, x.Ref, d.UnsafeL2Head())
}
// Try to apply the forkchoice changes
d.TryUpdateEngine(ctx)
Expand All @@ -718,19 +737,6 @@ func (d *EngineController) OnEvent(ctx context.Context, ev event.Event) bool {
d.emitter.Emit(ctx, FinalizedUpdateEvent(x))
// Try to apply the forkchoice changes
d.TryUpdateEngine(ctx)
case CrossUpdateRequestEvent:
if x.CrossUnsafe {
d.emitter.Emit(ctx, CrossUnsafeUpdateEvent{
CrossUnsafe: d.CrossUnsafeL2Head(),
LocalUnsafe: d.UnsafeL2Head(),
})
}
if x.CrossSafe {
d.emitter.Emit(ctx, CrossSafeUpdateEvent{
CrossSafe: d.SafeL2Head(),
LocalSafe: d.LocalSafeL2Head(),
})
}
case InteropInvalidateBlockEvent:
d.emitter.Emit(ctx, BuildStartEvent{Attributes: x.Attributes})
case BuildStartEvent:
Expand Down
29 changes: 0 additions & 29 deletions op-node/rollup/engine/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,6 @@ func (ev PromoteCrossUnsafeEvent) String() string {
return "promote-cross-unsafe"
}

// CrossUnsafeUpdateEvent signals that the given block is now considered cross-unsafe.
type CrossUnsafeUpdateEvent struct {
CrossUnsafe eth.L2BlockRef
LocalUnsafe eth.L2BlockRef
}

func (ev CrossUnsafeUpdateEvent) String() string {
return "cross-unsafe-update"
}

type PendingSafeUpdateEvent struct {
PendingSafe eth.L2BlockRef
Unsafe eth.L2BlockRef // tip, added to the signal, to determine if there are existing blocks to consolidate
Expand All @@ -66,15 +56,6 @@ func (ev PendingSafeUpdateEvent) String() string {
return "pending-safe-update"
}

type CrossSafeUpdateEvent struct {
CrossSafe eth.L2BlockRef
LocalSafe eth.L2BlockRef
}

func (ev CrossSafeUpdateEvent) String() string {
return "cross-safe-update"
}

// LocalSafeUpdateEvent signals that a block is now considered to be local-safe.
type LocalSafeUpdateEvent struct {
Ref eth.L2BlockRef
Expand Down Expand Up @@ -151,16 +132,6 @@ func (ev FinalizedUpdateEvent) String() string {
return "finalized-update"
}

// CrossUpdateRequestEvent triggers update events to be emitted, repeating the current state.
type CrossUpdateRequestEvent struct {
CrossUnsafe bool
CrossSafe bool
}

func (ev CrossUpdateRequestEvent) String() string {
return "cross-update-request"
}

// InteropInvalidateBlockEvent is emitted when a block needs to be invalidated, and a replacement is needed.
type InteropInvalidateBlockEvent struct {
Invalidated eth.BlockRef
Expand Down
33 changes: 25 additions & 8 deletions op-node/rollup/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
"github.com/ethereum-optimism/optimism/op-service/event"
)

// Compile-time interface compliance check
var _ engine.CrossUpdateHandler = (*StatusTracker)(nil)

type Metrics interface {
RecordL1ReorgDepth(d uint64)
RecordL1Ref(name string, ref eth.L1BlockRef)
Expand Down Expand Up @@ -60,17 +63,9 @@ func (st *StatusTracker) OnEvent(ctx context.Context, ev event.Event) bool {
case engine.PendingSafeUpdateEvent:
st.data.UnsafeL2 = x.Unsafe
st.data.PendingSafeL2 = x.PendingSafe
case engine.CrossUnsafeUpdateEvent:
st.log.Debug("Cross unsafe head updated", "cross_unsafe", x.CrossUnsafe, "local_unsafe", x.LocalUnsafe)
st.data.CrossUnsafeL2 = x.CrossUnsafe
st.data.UnsafeL2 = x.LocalUnsafe
case engine.LocalSafeUpdateEvent:
st.log.Debug("Local safe head updated", "local_safe", x.Ref)
st.data.LocalSafeL2 = x.Ref
case engine.CrossSafeUpdateEvent:
st.log.Debug("Cross safe head updated", "cross_safe", x.CrossSafe, "local_safe", x.LocalSafe)
st.data.SafeL2 = x.CrossSafe
st.data.LocalSafeL2 = x.LocalSafe
case derive.DeriverL1StatusEvent:
st.data.CurrentL1 = x.Origin
case rollup.ResetEvent:
Expand Down Expand Up @@ -151,3 +146,25 @@ func (st *StatusTracker) SyncStatus() *eth.SyncStatus {
func (st *StatusTracker) L1Head() eth.L1BlockRef {
return st.SyncStatus().HeadL1
}

func (st *StatusTracker) OnCrossUnsafeUpdate(ctx context.Context, crossUnsafe eth.L2BlockRef, localUnsafe eth.L2BlockRef) {
st.mu.Lock()
defer st.mu.Unlock()

st.log.Debug("Cross unsafe head updated", "cross_unsafe", crossUnsafe, "local_unsafe", localUnsafe)
st.data.CrossUnsafeL2 = crossUnsafe
st.data.UnsafeL2 = localUnsafe

st.UpdateSyncStatus()
}

func (st *StatusTracker) OnCrossSafeUpdate(ctx context.Context, crossSafe eth.L2BlockRef, localSafe eth.L2BlockRef) {
st.mu.Lock()
defer st.mu.Unlock()

st.log.Debug("Cross safe head updated", "cross_safe", crossSafe, "local_safe", localSafe)
st.data.SafeL2 = crossSafe
st.data.LocalSafeL2 = localSafe

st.UpdateSyncStatus()
}