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
18 changes: 18 additions & 0 deletions devnet-sdk/system/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"github.com/ethereum-optimism/optimism/devnet-sdk/types"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/sources"
supervisorTypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
coreTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/params"
Expand Down Expand Up @@ -114,9 +116,25 @@ type RawTransaction interface {
type InteropSystem interface {
System
InteropSet() InteropSet
Supervisor(context.Context) (Supervisor, error)
}

// InteropSet provides access to L2 chains in an interop environment
type InteropSet interface {
L2s() []Chain
}

// Supervisor provides access to the query interface of the supervisor
type Supervisor interface {
CheckMessage(context.Context, supervisorTypes.Identifier, common.Hash, supervisorTypes.ExecutingDescriptor) (supervisorTypes.SafetyLevel, error)
LocalUnsafe(context.Context, eth.ChainID) (eth.BlockID, error)
CrossSafe(context.Context, eth.ChainID) (supervisorTypes.DerivedIDPair, error)
Finalized(context.Context, eth.ChainID) (eth.BlockID, error)
FinalizedL1(context.Context) (eth.BlockRef, error)
CrossDerivedFrom(context.Context, eth.ChainID, eth.BlockID) (eth.BlockRef, error)
UpdateLocalUnsafe(context.Context, eth.ChainID, eth.BlockRef) error
UpdateLocalSafe(context.Context, eth.ChainID, eth.L1BlockRef, eth.BlockRef) error
SuperRootAtTimestamp(context.Context, hexutil.Uint64) (eth.SuperRootResponse, error)
AllSafeDerivedAt(context.Context, eth.BlockID) (derived map[eth.ChainID]eth.BlockID, err error)
SyncStatus(context.Context) (eth.SupervisorSyncStatus, error)
}
33 changes: 32 additions & 1 deletion devnet-sdk/system/system.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package system

import (
"context"
"fmt"
"slices"
"sync"

"github.com/ethereum-optimism/optimism/devnet-sdk/descriptors"
"github.com/ethereum-optimism/optimism/devnet-sdk/shell/env"
"github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum-optimism/optimism/op-service/sources"
)

type system struct {
Expand Down Expand Up @@ -69,13 +73,23 @@ func systemFromDevnet(dn descriptors.DevnetEnvironment, identifier string) (Syst
}

if slices.Contains(dn.Features, "interop") {
return &interopSystem{system: sys}, nil
// TODO(14849): this will break as soon as we have a dependency set that
// doesn't include all L2s.
supervisorRPC := dn.L2[0].Services["supervisor"].Endpoints["rpc"]
return &interopSystem{
system: sys,
supervisorRPC: fmt.Sprintf("http://%s:%d", supervisorRPC.Host, supervisorRPC.Port),
}, nil
}
return sys, nil
}

type interopSystem struct {
*system

supervisorRPC string
supervisor Supervisor
mu sync.Mutex
}

// interopSystem implements InteropSystem
Expand All @@ -84,3 +98,20 @@ var _ InteropSystem = (*interopSystem)(nil)
func (i *interopSystem) InteropSet() InteropSet {
return i.system // TODO: the interop set might not contain all L2s
}

func (i *interopSystem) Supervisor(ctx context.Context) (Supervisor, error) {
i.mu.Lock()
defer i.mu.Unlock()

if i.supervisor != nil {
return i.supervisor, nil
}

cl, err := client.NewRPC(ctx, nil, i.supervisorRPC)
if err != nil {
return nil, fmt.Errorf("failed to dial supervisor RPC: %w", err)
}
supervisor := sources.NewSupervisorClient(cl)
i.supervisor = supervisor
return supervisor, nil
}
55 changes: 55 additions & 0 deletions devnet-sdk/testing/systest/testing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import (
"github.com/ethereum-optimism/optimism/devnet-sdk/shell/env"
"github.com/ethereum-optimism/optimism/devnet-sdk/system"
"github.com/ethereum-optimism/optimism/devnet-sdk/types"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/sources"
supervisorTypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -122,13 +125,65 @@ type mockInteropSet struct{}

func (m *mockInteropSet) L2s() []system.Chain { return []system.Chain{&mockChain{}} }

// mockSupervisor implements the system.Supervisor interface for testing
type mockSupervisor struct{}

func (m *mockSupervisor) CheckMessage(ctx context.Context, id supervisorTypes.Identifier, hash common.Hash, desc supervisorTypes.ExecutingDescriptor) (supervisorTypes.SafetyLevel, error) {
return supervisorTypes.Invalid, nil
}

func (m *mockSupervisor) LocalUnsafe(ctx context.Context, chainID eth.ChainID) (eth.BlockID, error) {
return eth.BlockID{}, nil
}

func (m *mockSupervisor) CrossSafe(ctx context.Context, chainID eth.ChainID) (supervisorTypes.DerivedIDPair, error) {
return supervisorTypes.DerivedIDPair{}, nil
}

func (m *mockSupervisor) Finalized(ctx context.Context, chainID eth.ChainID) (eth.BlockID, error) {
return eth.BlockID{}, nil
}

func (m *mockSupervisor) FinalizedL1(ctx context.Context) (eth.BlockRef, error) {
return eth.BlockRef{}, nil
}

func (m *mockSupervisor) CrossDerivedFrom(ctx context.Context, chainID eth.ChainID, blockID eth.BlockID) (eth.BlockRef, error) {
return eth.BlockRef{}, nil
}

func (m *mockSupervisor) UpdateLocalUnsafe(ctx context.Context, chainID eth.ChainID, blockRef eth.BlockRef) error {
return nil
}

func (m *mockSupervisor) UpdateLocalSafe(ctx context.Context, chainID eth.ChainID, l1BlockRef eth.L1BlockRef, blockRef eth.BlockRef) error {
return nil
}

func (m *mockSupervisor) SuperRootAtTimestamp(ctx context.Context, timestamp hexutil.Uint64) (eth.SuperRootResponse, error) {
return eth.SuperRootResponse{}, nil
}

func (m *mockSupervisor) AllSafeDerivedAt(ctx context.Context, blockID eth.BlockID) (map[eth.ChainID]eth.BlockID, error) {
return nil, nil
}

func (m *mockSupervisor) SyncStatus(ctx context.Context) (eth.SupervisorSyncStatus, error) {
return eth.SupervisorSyncStatus{}, nil
}

// mockInteropSystem implements a minimal system.InteropSystem for testing
type mockInteropSystem struct {
mockSystem
}

func (m *mockInteropSystem) InteropSet() system.InteropSet { return &mockInteropSet{} }

// Supervisor implements the system.InteropSystem interface
func (m *mockInteropSystem) Supervisor(ctx context.Context) (system.Supervisor, error) {
return &mockSupervisor{}, nil
}

// newMockSystem creates a new mock system for testing
func newMockSystem() system.System {
return &mockSystem{}
Expand Down
7 changes: 7 additions & 0 deletions kurtosis-devnet/pkg/kurtosis/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ func (f *ServiceFinder) FindL2Services(network string) ([]descriptors.Node, desc
tag, idx := f.serviceTag(strings.TrimPrefix(name, f.l2ServicePrefix))
return tag, idx, true
}

// Some services don't have a network suffix, as they span multiple chains
// TODO(14849): ideally we'd need to handle *partial* chain coverage.
if strings.HasPrefix(serviceName, f.l2ServicePrefix) {
tag, idx := f.serviceTag(strings.TrimPrefix(serviceName, f.l2ServicePrefix))
return tag, idx, true
}
return "", 0, false
})
}
Expand Down
12 changes: 12 additions & 0 deletions op-acceptance-tests/tests/interop/interop_smoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ func TestInteropSystemNoop(t *testing.T) {
})
}

func TestInteropSystemSupervisor(t *testing.T) {
systest.InteropSystemTest(t, func(t systest.T, sys system.InteropSystem) {
ctx := t.Context()
supervisor, err := sys.Supervisor(ctx)
require.NoError(t, err)
block, err := supervisor.FinalizedL1(ctx)
require.NoError(t, err)
require.NotNil(t, block)
testlog.Logger(t, log.LevelInfo).Info("finalized l1 block", "block", block)
})
}

func TestSmokeTestFailure(t *testing.T) {
// Create mock failing system
mockAddr := common.HexToAddress("0x1234567890123456789012345678901234567890")
Expand Down