Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interop: Update Inputs (rebased) #12204

Merged
merged 7 commits into from
Oct 8, 2024
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
94 changes: 78 additions & 16 deletions op-e2e/actions/interop/interop_test.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
package interop

import (
"context"
"testing"

"github.com/ethereum-optimism/optimism/op-e2e/actions/helpers"
"github.com/stretchr/testify/require"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"

"github.com/ethereum-optimism/optimism/op-e2e/actions/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup/interop"
"github.com/ethereum-optimism/optimism/op-node/rollup/sync"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum-optimism/optimism/op-service/testutils"
"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
)

var _ interop.InteropBackend = (*testutils.MockInteropBackend)(nil)
var _ interop.InteropBackend = (*testutils.FakeInteropBackend)(nil)

func TestInteropVerifier(gt *testing.T) {
t := helpers.NewDefaultTesting(gt)
Expand All @@ -26,14 +29,14 @@ func TestInteropVerifier(gt *testing.T) {
// The state genesis in this test is pre-interop however.
sd.RollupCfg.InteropTime = new(uint64)
logger := testlog.Logger(t, log.LevelDebug)
seqMockBackend := &testutils.MockInteropBackend{}
seqMockBackend := &testutils.FakeInteropBackend{}
l1Miner, seqEng, seq := helpers.SetupSequencerTest(t, sd, logger,
helpers.WithVerifierOpts(helpers.WithInteropBackend(seqMockBackend)))

batcher := helpers.NewL2Batcher(logger, sd.RollupCfg, helpers.DefaultBatcherCfg(dp),
seq.RollupClient(), l1Miner.EthClient(), seqEng.EthClient(), seqEng.EngineClient(t, sd.RollupCfg))

verMockBackend := &testutils.MockInteropBackend{}
verMockBackend := &testutils.FakeInteropBackend{}
_, ver := helpers.SetupVerifier(t, sd, logger,
l1Miner.L1Client(t, sd.RollupCfg), l1Miner.BlobStore(), &sync.Config{},
helpers.WithInteropBackend(verMockBackend))
Expand All @@ -42,12 +45,21 @@ func TestInteropVerifier(gt *testing.T) {
ver.ActL2PipelineFull(t)

l2ChainID := types.ChainIDFromBig(sd.RollupCfg.L2ChainID)
seqMockBackend.ExpectCheckBlock(l2ChainID, 1, types.LocalUnsafe, nil)
seqMockBackend.UpdateLocalUnsafeFn = func(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error {
require.Equal(t, chainID, l2ChainID)
require.Equal(t, uint64(1), head.Number)
return nil
}
seqMockBackend.UnsafeViewFn = func(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) {
require.Equal(t, chainID, l2ChainID)
require.Equal(t, uint64(1), unsafe.Local.Number)
require.Equal(t, uint64(0), unsafe.Cross.Number)
return unsafe, nil
}
// create an unsafe L2 block
seq.ActL2StartBlock(t)
seq.ActL2EndBlock(t)
seq.ActL2PipelineFull(t)
seqMockBackend.AssertExpectations(t)
status := seq.SyncStatus()
require.Equal(t, uint64(1), status.UnsafeL2.Number)
require.Equal(t, uint64(0), status.CrossUnsafeL2.Number)
Expand All @@ -56,10 +68,16 @@ func TestInteropVerifier(gt *testing.T) {

// promote it to cross-unsafe in the backend
// and see if the node picks up on it
seqMockBackend.ExpectCheckBlock(l2ChainID, 1, types.CrossUnsafe, nil)
seqMockBackend.UnsafeViewFn = func(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) {
require.Equal(t, chainID, l2ChainID)
require.Equal(t, uint64(1), unsafe.Local.Number)
require.Equal(t, uint64(0), unsafe.Cross.Number)
out := unsafe
out.Cross = unsafe.Local
return out, nil
}
seq.ActInteropBackendCheck(t)
seq.ActL2PipelineFull(t)
seqMockBackend.AssertExpectations(t)
status = seq.SyncStatus()
require.Equal(t, uint64(1), status.UnsafeL2.Number)
require.Equal(t, uint64(1), status.CrossUnsafeL2.Number, "cross unsafe now")
Expand All @@ -74,10 +92,20 @@ func TestInteropVerifier(gt *testing.T) {
l1Miner.ActL1EndBlock(t)

// Sync the L1 block, to verify the L2 block as local-safe.
seqMockBackend.ExpectCheckBlock(l2ChainID, 1, types.CrossUnsafe, nil) // not cross-safe yet
seqMockBackend.UpdateLocalUnsafeFn = nil
seqMockBackend.UpdateLocalSafeFn = func(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error {
require.Equal(t, uint64(1), lastDerived.Number)
return nil
}
seqMockBackend.SafeViewFn = func(ctx context.Context, chainID types.ChainID, safe types.ReferenceView) (types.ReferenceView, error) {
require.Equal(t, chainID, l2ChainID)
require.Equal(t, uint64(1), safe.Local.Number)
require.Equal(t, uint64(0), safe.Cross.Number)
return safe, nil
}
seq.ActL1HeadSignal(t)
l1Head := seq.SyncStatus().HeadL1
seq.ActL2PipelineFull(t)
seqMockBackend.AssertExpectations(t)

status = seq.SyncStatus()
require.Equal(t, uint64(1), status.UnsafeL2.Number)
Expand All @@ -86,10 +114,23 @@ func TestInteropVerifier(gt *testing.T) {
require.Equal(t, uint64(0), status.SafeL2.Number)

// Now mark it as cross-safe
seqMockBackend.ExpectCheckBlock(l2ChainID, 1, types.CrossSafe, nil)
seqMockBackend.SafeViewFn = func(ctx context.Context, chainID types.ChainID, request types.ReferenceView) (types.ReferenceView, error) {
require.Equal(t, chainID, l2ChainID)
require.Equal(t, uint64(1), request.Local.Number)
require.Equal(t, uint64(0), request.Cross.Number)
out := request
out.Cross = request.Local
return out, nil
}
seqMockBackend.DerivedFromFn = func(ctx context.Context, chainID types.ChainID, blockHash common.Hash, blockNumber uint64) (eth.L1BlockRef, error) {
require.Equal(t, uint64(1), blockNumber)
return l1Head, nil
}
seqMockBackend.FinalizedFn = func(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) {
return seq.RollupCfg.Genesis.L1, nil
}
seq.ActInteropBackendCheck(t)
seq.ActL2PipelineFull(t)
seqMockBackend.AssertExpectations(t)

status = seq.SyncStatus()
require.Equal(t, uint64(1), status.UnsafeL2.Number)
Expand All @@ -98,26 +139,47 @@ func TestInteropVerifier(gt *testing.T) {
require.Equal(t, uint64(1), status.SafeL2.Number, "cross-safe reached")
require.Equal(t, uint64(0), status.FinalizedL2.Number)

verMockBackend.UpdateLocalUnsafeFn = func(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error {
require.Equal(t, uint64(1), head.Number)
return nil
}
verMockBackend.UpdateLocalSafeFn = func(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error {
require.Equal(t, uint64(1), lastDerived.Number)
require.Equal(t, l1Head.ID(), derivedFrom.ID())
return nil
}
// The verifier might not see the L2 block that was just derived from L1 as cross-verified yet.
verMockBackend.ExpectCheckBlock(l2ChainID, 1, types.LocalUnsafe, nil) // for the local unsafe check
verMockBackend.ExpectCheckBlock(l2ChainID, 1, types.LocalUnsafe, nil) // for the local safe check
verMockBackend.UnsafeViewFn = func(ctx context.Context, chainID types.ChainID, request types.ReferenceView) (types.ReferenceView, error) {
require.Equal(t, uint64(1), request.Local.Number)
require.Equal(t, uint64(0), request.Cross.Number)
// Don't promote the Cross value yet
return request, nil
}
verMockBackend.SafeViewFn = func(ctx context.Context, chainID types.ChainID, request types.ReferenceView) (types.ReferenceView, error) {
require.Equal(t, uint64(1), request.Local.Number)
require.Equal(t, uint64(0), request.Cross.Number)
// Don't promote the Cross value yet
return request, nil
}
ver.ActL1HeadSignal(t)
ver.ActL2PipelineFull(t)
verMockBackend.AssertExpectations(t)
status = ver.SyncStatus()
require.Equal(t, uint64(1), status.UnsafeL2.Number, "synced the block")
require.Equal(t, uint64(0), status.CrossUnsafeL2.Number, "not cross-verified yet")
require.Equal(t, uint64(1), status.LocalSafeL2.Number, "derived from L1, thus local-safe")
require.Equal(t, uint64(0), status.SafeL2.Number, "not yet cross-safe")
require.Equal(t, uint64(0), status.FinalizedL2.Number)

seqMockBackend.UpdateFinalizedL1Fn = func(ctx context.Context, chainID types.ChainID, finalized eth.L1BlockRef) error {
require.Equal(t, l1Head, finalized)
return nil
}
// signal that L1 finalized; the cross-safe block we have should get finalized too
l1Miner.ActL1SafeNext(t)
l1Miner.ActL1FinalizeNext(t)
seq.ActL1SafeSignal(t)
seq.ActL1FinalizedSignal(t)
seq.ActL2PipelineFull(t)
seqMockBackend.AssertExpectations(t)

status = seq.SyncStatus()
require.Equal(t, uint64(1), status.FinalizedL2.Number, "finalized the block")
Expand Down
19 changes: 19 additions & 0 deletions op-node/rollup/engine/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,22 @@ func (ev PromoteFinalizedEvent) String() string {
return "promote-finalized"
}

// FinalizedUpdateEvent signals that a block has been marked as finalized.
type FinalizedUpdateEvent struct {
Ref eth.L2BlockRef
}

func (ev FinalizedUpdateEvent) String() string {
return "finalized-update"
}

// RequestFinalizedUpdateEvent signals that a FinalizedUpdateEvent is needed.
type RequestFinalizedUpdateEvent struct{}

func (ev RequestFinalizedUpdateEvent) String() string {
return "request-finalized-update"
}

// CrossUpdateRequestEvent triggers update events to be emitted, repeating the current state.
type CrossUpdateRequestEvent struct {
CrossUnsafe bool
Expand Down Expand Up @@ -419,8 +435,11 @@ func (d *EngDeriver) OnEvent(ev event.Event) bool {
return true
}
d.ec.SetFinalizedHead(x.Ref)
d.emitter.Emit(FinalizedUpdateEvent(x))
// Try to apply the forkchoice changes
d.emitter.Emit(TryUpdateEngineEvent{})
case RequestFinalizedUpdateEvent:
d.emitter.Emit(FinalizedUpdateEvent{Ref: d.ec.Finalized()})
case CrossUpdateRequestEvent:
if x.CrossUnsafe {
d.emitter.Emit(CrossUnsafeUpdateEvent{
Expand Down
Loading