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
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ op-supernode: ## Builds op-supernode binary
just $(JUSTFLAGS) ./op-supernode/op-supernode
.PHONY: op-supernode

op-interop-filter: ## Builds op-interop-filter binary
just $(JUSTFLAGS) ./op-interop-filter/op-interop-filter
.PHONY: op-interop-filter

op-program: ## Builds op-program binary
make -C ./op-program op-program
.PHONY: op-program
Expand Down
17 changes: 17 additions & 0 deletions docker-bake.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ variable "OP_SUPERNODE_VERSION" {
default = "${GIT_VERSION}"
}

variable "OP_INTEROP_FILTER_VERSION" {
default = "${GIT_VERSION}"
}

variable "OP_TEST_SEQUENCER_VERSION" {
default = "${GIT_VERSION}"
}
Expand Down Expand Up @@ -228,6 +232,19 @@ target "op-supernode" {
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-supernode:${tag}"]
}

target "op-interop-filter" {
dockerfile = "ops/docker/op-stack-go/Dockerfile"
context = "."
args = {
GIT_COMMIT = "${GIT_COMMIT}"
GIT_DATE = "${GIT_DATE}"
OP_INTEROP_FILTER_VERSION = "${OP_INTEROP_FILTER_VERSION}"
}
target = "op-interop-filter-target"
platforms = split(",", PLATFORMS)
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-interop-filter:${tag}"]
}

target "op-test-sequencer" {
dockerfile = "ops/docker/op-stack-go/Dockerfile"
context = "."
Expand Down
3 changes: 3 additions & 0 deletions op-interop-filter/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DEPRECATED_TARGETS := op-interop-filter clean test

include ../justfiles/deprecated.mk
26 changes: 26 additions & 0 deletions op-interop-filter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# op-interop-filter

A lightweight service that validates interop executing messages for op-geth or op-reth transaction filtering.
Comment thread
pcw109550 marked this conversation as resolved.

Any reorg will trigger the failsafe which disables all interop transactions.

## Usage

### Build from source

```bash
just op-interop-filter
./bin/op-interop-filter --help
```

### Run from source

```bash
go run ./cmd --help
```

### Build docker image

```bash
docker buildx bake op-interop-filter
```
49 changes: 49 additions & 0 deletions op-interop-filter/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

import (
"context"
"os"

"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"

opservice "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/cliapp"
"github.com/ethereum-optimism/optimism/op-service/ctxinterrupt"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum-optimism/optimism/op-service/metrics/doc"

"github.com/ethereum-optimism/optimism/op-interop-filter/filter"
"github.com/ethereum-optimism/optimism/op-interop-filter/flags"
"github.com/ethereum-optimism/optimism/op-interop-filter/metrics"
)

var (
Version = "v0.0.0"
GitCommit = ""
GitDate = ""
)

func main() {
oplog.SetupDefaults()

app := cli.NewApp()
app.Flags = cliapp.ProtectFlags(flags.Flags)
app.Version = opservice.FormatVersion(Version, GitCommit, GitDate, "")
app.Name = "op-interop-filter"
app.Usage = "Interop transaction filter service"
app.Description = "Validates interop executing messages for transaction filtering"
app.Action = cliapp.LifecycleCmd(filter.Main(app.Version))
app.Commands = []*cli.Command{
{
Name: "doc",
Subcommands: doc.NewSubcommands(metrics.NewMetrics("default")),
},
}

ctx := ctxinterrupt.WithSignalWaiterMain(context.Background())
err := app.RunContext(ctx, os.Args)
if err != nil {
log.Crit("Application failed", "message", err)
}
}
56 changes: 56 additions & 0 deletions op-interop-filter/filter/backend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package filter

import (
"context"

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

"github.com/ethereum-optimism/optimism/op-interop-filter/metrics"
"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
)

// Backend coordinates chain ingesters and handles the failsafe state.
// This is a stub implementation - the actual logic will be added in a follow-up PR.
type Backend struct {
log log.Logger
metrics metrics.Metricer
cfg *Config
}

// NewBackend creates a new Backend instance
func NewBackend(ctx context.Context, logger log.Logger, m metrics.Metricer, cfg *Config) (*Backend, error) {
b := &Backend{
log: logger,
metrics: m,
cfg: cfg,
}
logger.Info("Created backend", "chains", len(cfg.L2RPCs))
return b, nil
}

// Start starts the backend
func (b *Backend) Start(ctx context.Context) error {
b.log.Info("Starting backend (stub)")
return nil
}

// Stop stops the backend
func (b *Backend) Stop(ctx context.Context) error {
b.log.Info("Stopping backend (stub)")
return nil
}

// FailsafeEnabled returns whether failsafe is enabled
func (b *Backend) FailsafeEnabled() bool {
return false
}

// CheckAccessList validates the given access list entries.
// This is a stub implementation that always returns ErrUninitialized.
func (b *Backend) CheckAccessList(ctx context.Context, inboxEntries []common.Hash,
minSafety types.SafetyLevel, execDescriptor types.ExecutingDescriptor) error {

b.metrics.RecordCheckAccessList(false)
return types.ErrUninitialized
}
62 changes: 62 additions & 0 deletions op-interop-filter/filter/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package filter

import (
"errors"
"fmt"
"time"

"github.com/urfave/cli/v2"

"github.com/ethereum-optimism/optimism/op-interop-filter/flags"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
"github.com/ethereum-optimism/optimism/op-service/oppprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
)

type Config struct {
L2RPCs []string
DataDir string
BackfillDuration time.Duration
JWTSecretPath string
Version string

LogConfig oplog.CLIConfig
MetricsConfig opmetrics.CLIConfig
PprofConfig oppprof.CLIConfig
RPC oprpc.CLIConfig
}

func (c *Config) Check() error {
var result error
if len(c.L2RPCs) == 0 {
result = errors.Join(result, errors.New("at least one L2 RPC is required"))
}
// Admin API requires JWT authentication
if c.RPC.EnableAdmin && c.JWTSecretPath == "" {
result = errors.Join(result, errors.New("admin RPC requires JWT setup, but no JWT path was specified"))
}
result = errors.Join(result, c.MetricsConfig.Check())
result = errors.Join(result, c.PprofConfig.Check())
result = errors.Join(result, c.RPC.Check())
return result
}

func NewConfig(ctx *cli.Context, version string) (*Config, error) {
backfillDuration, err := time.ParseDuration(ctx.String(flags.BackfillDurationFlag.Name))
if err != nil {
return nil, fmt.Errorf("invalid backfill-duration: %w", err)
}

return &Config{
L2RPCs: ctx.StringSlice(flags.L2RPCsFlag.Name),
DataDir: ctx.String(flags.DataDirFlag.Name),
BackfillDuration: backfillDuration,
JWTSecretPath: ctx.String(flags.JWTSecretFlag.Name),
Version: version,
LogConfig: oplog.ReadCLIConfig(ctx),
MetricsConfig: opmetrics.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx),
RPC: oprpc.ReadCLIConfig(ctx),
}, nil
}
52 changes: 52 additions & 0 deletions op-interop-filter/filter/frontend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package filter

import (
"context"
"errors"

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

"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
)

// QueryFrontend handles supervisor query RPC methods
type QueryFrontend struct {
backend *Backend
}

// CheckAccessList validates interop executing messages
func (f *QueryFrontend) CheckAccessList(ctx context.Context, inboxEntries []common.Hash,
minSafety types.SafetyLevel, executingDescriptor types.ExecutingDescriptor) error {

err := f.backend.CheckAccessList(ctx, inboxEntries, minSafety, executingDescriptor)
if err != nil {
return &rpc.JsonError{
Code: types.GetErrorCode(err),
Message: err.Error(),
}
}
return nil
}

// AdminFrontend handles admin RPC methods
type AdminFrontend struct {
backend *Backend
}

// GetFailsafeEnabled returns whether failsafe is enabled
func (a *AdminFrontend) GetFailsafeEnabled(ctx context.Context) (bool, error) {
return a.backend.FailsafeEnabled(), nil
}

// SetFailsafeEnabled enables or disables failsafe mode (TODO: implement)
func (a *AdminFrontend) SetFailsafeEnabled(ctx context.Context, enabled bool) error {
Comment thread
pcw109550 marked this conversation as resolved.
return errors.New("SetFailsafeEnabled not yet implemented")
}

// Rewind rewinds chain state to a specific block (TODO: implement)
// This can be used to recover from reorg-induced stuck states.
func (a *AdminFrontend) Rewind(ctx context.Context, chain eth.ChainID, block eth.BlockID) error {
return errors.New("Rewind not yet implemented")
}
Loading