Commit be455ca4 authored by protolambda's avatar protolambda Committed by GitHub

op-node: disable finality based on local-safe when interop is active (#12690)

* op-node: disable finality based on local-safe when interop is active

* op-e2e: fix interop action-test, relies on op-supervisor finality signal now
parent bf1b4d97
...@@ -191,6 +191,10 @@ func TestInteropVerifier(gt *testing.T) { ...@@ -191,6 +191,10 @@ func TestInteropVerifier(gt *testing.T) {
require.Equal(t, l1Head, finalized) require.Equal(t, l1Head, finalized)
return nil return nil
} }
// Allow the supervisor to promote the cross-safe L2 block to finalized.
seqMockBackend.FinalizedFn = func(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) {
return seq.SyncStatus().SafeL2.ID(), nil
}
// signal that L1 finalized; the cross-safe block we have should get finalized too // signal that L1 finalized; the cross-safe block we have should get finalized too
l1Miner.ActL1SafeNext(t) l1Miner.ActL1SafeNext(t)
l1Miner.ActL1FinalizeNext(t) l1Miner.ActL1FinalizeNext(t)
......
...@@ -73,6 +73,8 @@ type Finalizer struct { ...@@ -73,6 +73,8 @@ type Finalizer struct {
ctx context.Context ctx context.Context
cfg *rollup.Config
emitter event.Emitter emitter event.Emitter
// finalizedL1 is the currently perceived finalized L1 block. // finalizedL1 is the currently perceived finalized L1 block.
...@@ -98,6 +100,7 @@ func NewFinalizer(ctx context.Context, log log.Logger, cfg *rollup.Config, l1Fet ...@@ -98,6 +100,7 @@ func NewFinalizer(ctx context.Context, log log.Logger, cfg *rollup.Config, l1Fet
lookback := calcFinalityLookback(cfg) lookback := calcFinalityLookback(cfg)
return &Finalizer{ return &Finalizer{
ctx: ctx, ctx: ctx,
cfg: cfg,
log: log, log: log,
finalizedL1: eth.L1BlockRef{}, finalizedL1: eth.L1BlockRef{},
triedFinalizeAt: 0, triedFinalizeAt: 0,
...@@ -253,6 +256,14 @@ func (fi *Finalizer) tryFinalize() { ...@@ -253,6 +256,14 @@ func (fi *Finalizer) tryFinalize() {
func (fi *Finalizer) onDerivedSafeBlock(l2Safe eth.L2BlockRef, derivedFrom eth.L1BlockRef) { func (fi *Finalizer) onDerivedSafeBlock(l2Safe eth.L2BlockRef, derivedFrom eth.L1BlockRef) {
fi.mu.Lock() fi.mu.Lock()
defer fi.mu.Unlock() defer fi.mu.Unlock()
// Stop registering blocks after interop.
// Finality in interop is determined by the superchain backend,
// i.e. the op-supervisor RPC identifies which L2 block may be finalized.
if fi.cfg.IsInterop(l2Safe.Time) {
return
}
// remember the last L2 block that we fully derived from the given finality data // remember the last L2 block that we fully derived from the given finality data
if len(fi.finalityData) == 0 || fi.finalityData[len(fi.finalityData)-1].L1Block.Number < derivedFrom.Number { if len(fi.finalityData) == 0 || fi.finalityData[len(fi.finalityData)-1].L1Block.Number < derivedFrom.Number {
// prune finality data if necessary, before appending any data. // prune finality data if necessary, before appending any data.
......
...@@ -472,4 +472,35 @@ func TestEngineQueue_Finalize(t *testing.T) { ...@@ -472,4 +472,35 @@ func TestEngineQueue_Finalize(t *testing.T) {
fi.OnEvent(TryFinalizeEvent{}) fi.OnEvent(TryFinalizeEvent{})
emitter.AssertExpectations(t) emitter.AssertExpectations(t)
}) })
// The Finalizer does not promote any blocks to finalized status after interop.
// Blocks after interop are finalized with the interop deriver and interop backend.
t.Run("disable-after-interop", func(t *testing.T) {
logger := testlog.Logger(t, log.LevelInfo)
l1F := &testutils.MockL1Source{}
defer l1F.AssertExpectations(t)
l1F.ExpectL1BlockRefByNumber(refD.Number, refD, nil)
l1F.ExpectL1BlockRefByNumber(refD.Number, refD, nil)
emitter := &testutils.MockEmitter{}
fi := NewFinalizer(context.Background(), logger, &rollup.Config{
InteropTime: &refC1.Time,
}, l1F)
fi.AttachEmitter(emitter)
// now say C0 and C1 were included in D and became the new safe head
fi.OnEvent(engine.SafeDerivedEvent{Safe: refC0, DerivedFrom: refD})
fi.OnEvent(engine.SafeDerivedEvent{Safe: refC1, DerivedFrom: refD})
fi.OnEvent(derive.DeriverIdleEvent{Origin: refD})
emitter.AssertExpectations(t)
emitter.ExpectOnce(TryFinalizeEvent{})
fi.OnEvent(FinalizeL1Event{FinalizedL1: refD})
emitter.AssertExpectations(t)
// C1 was Interop, C0 was not yet interop and can be finalized
emitter.ExpectOnce(engine.PromoteFinalizedEvent{Ref: refC0})
fi.OnEvent(TryFinalizeEvent{})
emitter.AssertExpectations(t)
})
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment