Skip to content
Open
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
36 changes: 36 additions & 0 deletions op-devstack/dsl/interop_filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package dsl

import (
"github.com/ethereum-optimism/optimism/op-devstack/stack"
)

type InteropFilter struct {
commonImpl
inner stack.InteropFilter
}

// NewInteropFilter creates a new InteropFilter DSL wrapper
func NewInteropFilter(inner stack.InteropFilter) *InteropFilter {
return &InteropFilter{
commonImpl: commonFromT(inner.T()),
inner: inner,
}
}

// Escape returns the underlying stack.InteropFilter
func (f *InteropFilter) Escape() stack.InteropFilter {
return f.inner
}

// GetFailsafeEnabled returns whether failsafe is enabled
func (f *InteropFilter) GetFailsafeEnabled() bool {
enabled, err := f.inner.AdminAPI().GetFailsafeEnabled(f.ctx)
f.require.NoError(err, "failed to get failsafe enabled")
return enabled
}

// CheckAccessList validates interop executing messages
func (f *InteropFilter) CheckAccessList(inboxEntries [][]byte) error {
// TODO: implement when needed for tests
return nil
}
32 changes: 32 additions & 0 deletions op-devstack/presets/minimal_with_interop_filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package presets

import (
"github.com/ethereum-optimism/optimism/op-devstack/devtest"
"github.com/ethereum-optimism/optimism/op-devstack/dsl"
"github.com/ethereum-optimism/optimism/op-devstack/shim"
"github.com/ethereum-optimism/optimism/op-devstack/stack"
"github.com/ethereum-optimism/optimism/op-devstack/stack/match"
"github.com/ethereum-optimism/optimism/op-devstack/sysgo"
)

type MinimalWithInteropFilter struct {
Minimal

InteropFilter *dsl.InteropFilter
}

func WithMinimalWithInteropFilter() stack.CommonOption {
return stack.MakeCommon(sysgo.DefaultMinimalSystemWithInteropFilter(&sysgo.DefaultMinimalSystemWithInteropFilterIDs{}))
}

func NewMinimalWithInteropFilter(t devtest.T) *MinimalWithInteropFilter {
system := shim.NewSystem(t)
orch := Orchestrator()
orch.Hydrate(system)
minimal := minimalFromSystem(t, system, orch)
interopFilter := system.InteropFilter(match.Assume(t, match.FirstInteropFilter))
return &MinimalWithInteropFilter{
Minimal: *minimal,
InteropFilter: dsl.NewInteropFilter(interopFilter),
}
}
46 changes: 46 additions & 0 deletions op-devstack/shim/interop_filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package shim

import (
"github.com/ethereum-optimism/optimism/op-devstack/stack"
"github.com/ethereum-optimism/optimism/op-service/apis"
"github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum-optimism/optimism/op-service/sources"
)

type InteropFilterConfig struct {
CommonConfig
ID stack.InteropFilterID
Client client.RPC
}

type rpcInteropFilter struct {
commonImpl
id stack.InteropFilterID

client client.RPC
api apis.InteropFilterAPI
}

var _ stack.InteropFilter = (*rpcInteropFilter)(nil)

func NewInteropFilter(cfg InteropFilterConfig) stack.InteropFilter {
cfg.T = cfg.T.WithCtx(stack.ContextWithID(cfg.T.Ctx(), cfg.ID))
return &rpcInteropFilter{
commonImpl: newCommon(cfg.CommonConfig),
id: cfg.ID,
client: cfg.Client,
api: sources.NewInteropFilterClient(cfg.Client),
}
}

func (r *rpcInteropFilter) ID() stack.InteropFilterID {
return r.id
}

func (r *rpcInteropFilter) AdminAPI() apis.InteropFilterAdminAPI {
return r.api
}

func (r *rpcInteropFilter) QueryAPI() apis.InteropFilterQueryAPI {
return r.api
}
25 changes: 22 additions & 3 deletions op-devstack/shim/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ type presetSystem struct {
// tracks all networks, and ensures there are no networks with the same eth.ChainID
networks locks.RWMap[eth.ChainID, stack.Network]

supervisors locks.RWMap[stack.SupervisorID, stack.Supervisor]
sequencers locks.RWMap[stack.TestSequencerID, stack.TestSequencer]
syncTesters locks.RWMap[stack.SyncTesterID, stack.SyncTester]
supervisors locks.RWMap[stack.SupervisorID, stack.Supervisor]
sequencers locks.RWMap[stack.TestSequencerID, stack.TestSequencer]
syncTesters locks.RWMap[stack.SyncTesterID, stack.SyncTester]
interopFilters locks.RWMap[stack.InteropFilterID, stack.InteropFilter]
}

var _ stack.ExtensibleSystem = (*presetSystem)(nil)
Expand Down Expand Up @@ -125,6 +126,24 @@ func (p *presetSystem) AddSyncTester(v stack.SyncTester) {
p.require().True(p.syncTesters.SetIfMissing(v.ID(), v), "sync tester %s must not already exist", v.ID())
}

func (p *presetSystem) InteropFilter(m stack.InteropFilterMatcher) stack.InteropFilter {
v, ok := findMatch(m, p.interopFilters.Get, p.InteropFilters)
p.require().True(ok, "must find interop filter %s", m)
return v
}

func (p *presetSystem) AddInteropFilter(v stack.InteropFilter) {
p.require().True(p.interopFilters.SetIfMissing(v.ID(), v), "interop filter %s must not already exist", v.ID())
}

func (p *presetSystem) InteropFilterIDs() []stack.InteropFilterID {
return stack.SortInteropFilterIDs(p.interopFilters.Keys())
}

func (p *presetSystem) InteropFilters() []stack.InteropFilter {
return stack.SortInteropFilters(p.interopFilters.Values())
}

func (p *presetSystem) SuperchainIDs() []stack.SuperchainID {
return stack.SortSuperchainIDs(p.superchains.Keys())
}
Expand Down
58 changes: 58 additions & 0 deletions op-devstack/stack/interop_filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package stack

import (
"log/slog"

"github.com/ethereum-optimism/optimism/op-service/apis"
)

// InteropFilterID identifies an InteropFilter by name, is type-safe, and can be value-copied and used as map key.
type InteropFilterID genericID

var _ GenericID = (*InteropFilterID)(nil)

const InteropFilterKind Kind = "InteropFilter"

func (id InteropFilterID) String() string {
return genericID(id).string(InteropFilterKind)
}

func (id InteropFilterID) Kind() Kind {
return InteropFilterKind
}

func (id InteropFilterID) LogValue() slog.Value {
return slog.StringValue(id.String())
}

func (id InteropFilterID) MarshalText() ([]byte, error) {
return genericID(id).marshalText(InteropFilterKind)
}

func (id *InteropFilterID) UnmarshalText(data []byte) error {
return (*genericID)(id).unmarshalText(InteropFilterKind, data)
}

func SortInteropFilterIDs(ids []InteropFilterID) []InteropFilterID {
return copyAndSortCmp(ids)
}

func SortInteropFilters(elems []InteropFilter) []InteropFilter {
return copyAndSort(elems, lessElemOrdered[InteropFilterID, InteropFilter])
}

var _ InteropFilterMatcher = InteropFilterID("")

func (id InteropFilterID) Match(elems []InteropFilter) []InteropFilter {
return findByID(id, elems)
}

// InteropFilter is a lightweight service that validates interop executing messages.
// It provides a subset of supervisor functionality focused on transaction filtering.
type InteropFilter interface {
Common
ID() InteropFilterID

AdminAPI() apis.InteropFilterAdminAPI
QueryAPI() apis.InteropFilterQueryAPI
}
1 change: 1 addition & 0 deletions op-devstack/stack/match/first.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ var FirstCluster = First[stack.ClusterID, stack.Cluster]()

var FirstFaucet = First[stack.FaucetID, stack.Faucet]()
var FirstSyncTester = First[stack.SyncTesterID, stack.SyncTester]()
var FirstInteropFilter = First[stack.InteropFilterID, stack.InteropFilter]()
2 changes: 2 additions & 0 deletions op-devstack/stack/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ type L2ELMatcher = Matcher[L2ELNodeID, L2ELNode]
type FaucetMatcher = Matcher[FaucetID, Faucet]

type SyncTesterMatcher = Matcher[SyncTesterID, SyncTester]

type InteropFilterMatcher = Matcher[InteropFilterID, InteropFilter]
4 changes: 4 additions & 0 deletions op-devstack/stack/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,22 @@ type System interface {

Supervisor(m SupervisorMatcher) Supervisor
TestSequencer(id TestSequencerMatcher) TestSequencer
InteropFilter(m InteropFilterMatcher) InteropFilter

SuperchainIDs() []SuperchainID
ClusterIDs() []ClusterID
L1NetworkIDs() []L1NetworkID
L2NetworkIDs() []L2NetworkID
SupervisorIDs() []SupervisorID
InteropFilterIDs() []InteropFilterID

Superchains() []Superchain
Clusters() []Cluster
L1Networks() []L1Network
L2Networks() []L2Network
Supervisors() []Supervisor
TestSequencers() []TestSequencer
InteropFilters() []InteropFilter
}

// ExtensibleSystem is an extension-interface to add new components to the system.
Expand All @@ -46,6 +49,7 @@ type ExtensibleSystem interface {
AddSupervisor(v Supervisor)
AddTestSequencer(v TestSequencer)
AddSyncTester(v SyncTester)
AddInteropFilter(v InteropFilter)
}

type TimeTravelClock interface {
Expand Down
Loading