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
1 change: 1 addition & 0 deletions op-test-sequencer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin
32 changes: 32 additions & 0 deletions op-test-sequencer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# op-test-sequencer

This is a test service for block sequencing.
This service is in active development.

## Usage

### Build from source

```bash
# from op-test-sequencer dir:
just op-test-sequencer
./bin/op-test-sequencer --help
```

### Run from source

```bash
# from op-test-sequencer dir:
go run ./cmd --help
```

### Build docker image

Not available yet.

## Overview

This service is in active development.

See [design doc](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/test-sequencing.md)
for design considerations.
60 changes: 60 additions & 0 deletions op-test-sequencer/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"context"
"io"
"os"

"github.com/urfave/cli/v2"

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

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-test-sequencer/config"
"github.com/ethereum-optimism/optimism/op-test-sequencer/flags"
"github.com/ethereum-optimism/optimism/op-test-sequencer/metrics"
"github.com/ethereum-optimism/optimism/op-test-sequencer/sequencer"
)

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

func main() {
ctx := ctxinterrupt.WithSignalWaiterMain(context.Background())
err := run(ctx, os.Stdout, os.Stderr, os.Args, fromConfig)
if err != nil {
log.Crit("Application failed", "message", err)
}
}

func run(ctx context.Context, w io.Writer, ew io.Writer, args []string, fn sequencer.MainFn) error {
oplog.SetupDefaults()

app := cli.NewApp()
app.Writer = w
app.ErrWriter = ew
app.Flags = cliapp.ProtectFlags(flags.Flags)
app.Version = opservice.FormatVersion(Version, GitCommit, GitDate, "")
app.Name = "op-test-sequencer"
app.Usage = "op-test-sequencer sequences blocks"
app.Description = "op-test-sequencer sequences blocks"
app.Action = cliapp.LifecycleCmd(sequencer.Main(app.Version, fn))
app.Commands = []*cli.Command{
{
Name: "doc",
Subcommands: doc.NewSubcommands(metrics.NewMetrics("default")),
},
}
return app.RunContext(ctx, args)
}

func fromConfig(ctx context.Context, cfg *config.Config, logger log.Logger) (cliapp.Lifecycle, error) {
return sequencer.FromConfig(ctx, cfg, logger)
}
86 changes: 86 additions & 0 deletions op-test-sequencer/cmd/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package main

import (
"context"
"errors"
"fmt"
"io"
"testing"

"github.com/stretchr/testify/require"

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

"github.com/ethereum-optimism/optimism/op-service/cliapp"
"github.com/ethereum-optimism/optimism/op-test-sequencer/config"
)

func TestLogLevel(t *testing.T) {
t.Run("RejectInvalid", func(t *testing.T) {
verifyArgsInvalid(t, "unknown level: foo", addRequiredArgs("--log.level=foo"))
})

for _, lvl := range []string{"trace", "debug", "info", "error", "crit"} {
lvl := lvl
t.Run("AcceptValid_"+lvl, func(t *testing.T) {
logger, _, err := dryRunWithArgs(addRequiredArgs("--log.level", lvl))
require.NoError(t, err)
require.NotNil(t, logger)
})
}
}

func TestMockRun(t *testing.T) {
t.Run("Valid", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs("--mock-run"))
require.Equal(t, true, cfg.MockRun)
})
}

func verifyArgsInvalid(t *testing.T, messageContains string, cliArgs []string) {
_, _, err := dryRunWithArgs(cliArgs)
require.ErrorContains(t, err, messageContains)
}

func configForArgs(t *testing.T, cliArgs []string) *config.Config {
_, cfg, err := dryRunWithArgs(cliArgs)
require.NoError(t, err)
return cfg
}

func dryRunWithArgs(cliArgs []string) (log.Logger, *config.Config, error) {
cfg := new(config.Config)
var logger log.Logger
fullArgs := append([]string{"op-test-sequencer"}, cliArgs...)
testErr := errors.New("dry-run")
err := run(context.Background(), io.Discard, io.Discard, fullArgs, func(ctx context.Context, config *config.Config, log log.Logger) (cliapp.Lifecycle, error) {
logger = log
cfg = config
return nil, testErr
})
if errors.Is(err, testErr) { // expected error
err = nil
}
return logger, cfg, err
}

func addRequiredArgs(args ...string) []string {
req := requiredArgs()
combined := toArgList(req)
return append(combined, args...)
}

func toArgList(req map[string]string) []string {
var combined []string
for name, value := range req {
combined = append(combined, fmt.Sprintf("%s=%s", name, value))
}
return combined
}

func requiredArgs() map[string]string {
args := map[string]string{
//"--example": "todo",
}
return args
}
41 changes: 41 additions & 0 deletions op-test-sequencer/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package config

import (
"errors"

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 {
Version string

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

JWTSecretPath string

MockRun bool
}

func (c *Config) Check() error {
var result error
result = errors.Join(result, c.MetricsConfig.Check())
result = errors.Join(result, c.PprofConfig.Check())
result = errors.Join(result, c.RPC.Check())
return result
}

func DefaultCLIConfig() *Config {
return &Config{
Version: "dev",
LogConfig: oplog.DefaultCLIConfig(),
MetricsConfig: opmetrics.DefaultCLIConfig(),
PprofConfig: oppprof.DefaultCLIConfig(),
RPC: oprpc.DefaultCLIConfig(),
}
}
12 changes: 12 additions & 0 deletions op-test-sequencer/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package config

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestDefaultConfig(t *testing.T) {
cfg := DefaultCLIConfig()
require.NoError(t, cfg.Check())
}
76 changes: 76 additions & 0 deletions op-test-sequencer/flags/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package flags

import (
"fmt"

"github.com/urfave/cli/v2"

opservice "github.com/ethereum-optimism/optimism/op-service"
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"
"github.com/ethereum-optimism/optimism/op-test-sequencer/config"
)

const EnvVarPrefix = "OP_TEST_SEQUENCER"

func prefixEnvVars(name string) []string {
return opservice.PrefixEnvVar(EnvVarPrefix, name)
}

var (
RPCJWTSecret = &cli.StringFlag{
Name: "rpc.jwt-secret",
Usage: "Path to JWT secret key for sequencer admin RPC.",
EnvVars: prefixEnvVars("RPC_JWT_SECRET"),
TakesFile: true,
}
MockRunFlag = &cli.BoolFlag{
Name: "mock-run",
Usage: "Mock run, no actual backend used, just presenting the service",
EnvVars: prefixEnvVars("MOCK_RUN"),
Hidden: true, // this is for testing only
}
)

var requiredFlags = []cli.Flag{}

var optionalFlags = []cli.Flag{
RPCJWTSecret,
MockRunFlag,
}

func init() {
optionalFlags = append(optionalFlags, oprpc.CLIFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, oplog.CLIFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, opmetrics.CLIFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, oppprof.CLIFlags(EnvVarPrefix)...)

Flags = append(Flags, requiredFlags...)
Flags = append(Flags, optionalFlags...)
}

// Flags contains the list of configuration options available to the binary.
var Flags []cli.Flag

func CheckRequired(ctx *cli.Context) error {
for _, f := range requiredFlags {
if !ctx.IsSet(f.Names()[0]) {
return fmt.Errorf("flag %s is required", f.Names()[0])
}
}
return nil
}

func ConfigFromCLI(ctx *cli.Context, version string) *config.Config {
return &config.Config{
Version: version,
LogConfig: oplog.ReadCLIConfig(ctx),
MetricsConfig: opmetrics.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx),
RPC: oprpc.ReadCLIConfig(ctx),
MockRun: ctx.Bool(MockRunFlag.Name),
JWTSecretPath: ctx.Path(RPCJWTSecret.Name),
}
}
Loading