Skip to content

Commit

Permalink
op-batcher op-proposer op-service: Introduce op-service (ethereum-opt…
Browse files Browse the repository at this point in the history
…imism#3202)

* op-batcher op-proposer op-service: Introduce op-service

op-service is a utilities library that automates much of the boilerplate setup we've been duplicating across different daemons. This PR adds the following to op-batcher:

- Common setup utilities for logging, metrics, pprof, and RPC.
- For each of the above functions, a set of CLI flags and configs that can be used to parse + validate CLI configuration for that module.
- A base RPC server that implementers can extend.
- HTTP metrics utilities.

* update dockerfiles

* code review updates

* op-service: temporary replace, until op-service go module is canonical and can be resolved

Co-authored-by: protolambda <proto@protolambda.com>
  • Loading branch information
mslipper and protolambda committed Aug 10, 2022
1 parent bd30275 commit 8ed8d4e
Show file tree
Hide file tree
Showing 41 changed files with 2,172 additions and 497 deletions.
10 changes: 10 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ jobs:
command: |
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell ./...
working_directory: op-e2e
- run:
name: lint op-service
command: |
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell ./...
working_directory: op-service
- run:
name: prep results dir
command: mkdir -p /test-results
Expand All @@ -267,6 +272,11 @@ jobs:
command: |
gotestsum --junitfile /test-results/op-e2e.xml -- -coverpkg=github.com/ethereum-optimism/optimism/... -coverprofile=coverage.out -covermode=atomic ./...
working_directory: op-e2e
- run:
name: test op-service
command: |
gotestsum --junitfile /test-results/op-service.xml -- -coverpkg=github.com/ethereum-optimism/optimism/... -coverprofile=coverage.out -covermode=atomic ./...
working_directory: op-service
- store_test_results:
path: /test-results
- run:
Expand Down
3 changes: 2 additions & 1 deletion go.work
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ use (
./op-exporter
./op-node
./op-proposer
./op-service
./proxyd
./teleportr
./state-surgery
./teleportr
)

replace github.com/ethereum/go-ethereum v1.10.21 => github.com/ethereum-optimism/reference-optimistic-geth v0.0.0-20220803173305-1c9d4cc76a6e
Expand Down
1 change: 1 addition & 0 deletions op-batcher/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ COPY ./op-batcher/docker.go.work /app/go.work
COPY ./op-bindings /app/op-bindings
COPY ./op-node /app/op-node
COPY ./op-proposer /app/op-proposer
COPY ./op-service /app/op-service
COPY ./op-batcher /app/op-batcher

WORKDIR /app/op-batcher
Expand Down
79 changes: 42 additions & 37 deletions op-batcher/batch_submitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"fmt"
"io"
"math/big"
"net"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
Expand All @@ -18,6 +16,12 @@ import (
"syscall"
"time"

oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
"github.com/ethereum/go-ethereum/rpc"

"github.com/ethereum-optimism/optimism/op-batcher/sequencer"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
Expand All @@ -30,7 +34,6 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
"github.com/urfave/cli"
)
Expand All @@ -45,26 +48,14 @@ const (
// closure that executes the service and blocks until the service exits. The use
// of a closure allows the parameters bound to the top-level main package, e.g.
// GitVersion, to be captured and used once the function is executed.
func Main(version string) func(ctx *cli.Context) error {
return func(ctx *cli.Context) error {
cfg := NewConfig(ctx)

// Set up our logging to stdout.
var logHandler log.Handler
if cfg.LogTerminal {
logHandler = log.StreamHandler(os.Stdout, log.TerminalFormat(true))
} else {
logHandler = log.StreamHandler(os.Stdout, log.JSONFormat())
func Main(version string) func(cliCtx *cli.Context) error {
return func(cliCtx *cli.Context) error {
cfg := NewConfig(cliCtx)
if err := cfg.Check(); err != nil {
return fmt.Errorf("invalid CLI flags: %w", err)
}

logLevel, err := log.LvlFromString(cfg.LogLevel)
if err != nil {
return err
}

l := log.New()
l.SetHandler(log.LvlFilterHandler(logLevel, logHandler))

l := oplog.NewLogger(cfg.LogConfig)
l.Info("Initializing Batch Submitter")

batchSubmitter, err := NewBatchSubmitter(cfg, l)
Expand All @@ -81,28 +72,41 @@ func Main(version string) func(ctx *cli.Context) error {
}
defer batchSubmitter.Stop()

ctx, cancel := context.WithCancel(context.Background())

l.Info("Batch Submitter started")
if cfg.PprofEnabled {
var srv http.Server
srv.Addr = net.JoinHostPort(cfg.PprofAddr, cfg.PprofPort)
// Start pprof server + register it's shutdown
pprofConfig := cfg.PprofConfig
if pprofConfig.Enabled {
l.Info("starting pprof", "addr", pprofConfig.ListenAddr, "port", pprofConfig.ListenPort)
go func() {
l.Info("pprof server started", "addr", srv.Addr)
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
l.Error("error in pprof server", "err", err)
} else {
l.Info("pprof server shutting down")
if err := oppprof.ListenAndServe(ctx, pprofConfig.ListenAddr, pprofConfig.ListenPort); err != nil {
l.Error("error starting pprof", "err", err)
}

}()
defer func() {
shutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := srv.Shutdown(shutCtx)
l.Info("pprof server shut down", "err", err)
}

registry := opmetrics.NewRegistry()
metricsCfg := cfg.MetricsConfig
if metricsCfg.Enabled {
l.Info("starting metrics server", "addr", metricsCfg.ListenAddr, "port", metricsCfg.ListenPort)
go func() {
if err := opmetrics.ListenAndServe(ctx, registry, metricsCfg.ListenAddr, metricsCfg.ListenPort); err != nil {
l.Error("error starting metrics server", err)
}
}()
}

rpcCfg := cfg.RPCConfig
server := oprpc.NewServer(
rpcCfg.ListenAddr,
rpcCfg.ListenPort,
version,
)
if err := server.Start(); err != nil {
cancel()
return fmt.Errorf("error starting RPC server: %w", err)
}

interruptChannel := make(chan os.Signal, 1)
signal.Notify(interruptChannel, []os.Signal{
os.Interrupt,
Expand All @@ -111,7 +115,8 @@ func Main(version string) func(ctx *cli.Context) error {
syscall.SIGQUIT,
}...)
<-interruptChannel

cancel()
_ = server.Stop()
return nil
}
}
Expand Down
11 changes: 3 additions & 8 deletions op-batcher/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"os"

oplog "github.com/ethereum-optimism/optimism/op-service/log"

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

Expand All @@ -18,14 +20,7 @@ var (
)

func main() {
// Set up logger with a default INFO level in case we fail to parse flags,
// otherwise the final critical log won't show what the parsing error was.
log.Root().SetHandler(
log.LvlFilterHandler(
log.LvlInfo,
log.StreamHandler(os.Stdout, log.TerminalFormat(true)),
),
)
oplog.SetupDefaults()

app := cli.NewApp()
app.Flags = flags.Flags
Expand Down
47 changes: 32 additions & 15 deletions op-batcher/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ package op_batcher
import (
"time"

oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"

opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"

oplog "github.com/ethereum-optimism/optimism/op-service/log"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"

"github.com/urfave/cli"

"github.com/ethereum-optimism/optimism/op-batcher/flags"
Expand Down Expand Up @@ -63,19 +70,31 @@ type Config struct {
// transactions.
SequencerBatchInboxAddress string

RPCConfig oprpc.CLIConfig

/* Optional Params */

// LogLevel is the lowest log level that will be output.
LogLevel string
LogConfig oplog.CLIConfig

MetricsConfig opmetrics.CLIConfig

// LogTerminal if true, will log to stdout in terminal format. Otherwise the
// output will be in JSON format.
LogTerminal bool
PprofConfig oppprof.CLIConfig
}

// Flags for the pprof server
PprofEnabled bool
PprofAddr string
PprofPort string
func (c Config) Check() error {
if err := c.RPCConfig.Check(); err != nil {
return err
}
if err := c.LogConfig.Check(); err != nil {
return err
}
if err := c.MetricsConfig.Check(); err != nil {
return err
}
if err := c.PprofConfig.Check(); err != nil {
return err
}
return nil
}

// NewConfig parses the Config from the provided flags or environment variables.
Expand All @@ -96,11 +115,9 @@ func NewConfig(ctx *cli.Context) Config {
SequencerHDPath: ctx.GlobalString(flags.SequencerHDPathFlag.Name),
PrivateKey: ctx.GlobalString(flags.PrivateKeyFlag.Name),
SequencerBatchInboxAddress: ctx.GlobalString(flags.SequencerBatchInboxAddressFlag.Name),
/* Optional Flags */
LogLevel: ctx.GlobalString(flags.LogLevelFlag.Name),
LogTerminal: ctx.GlobalBool(flags.LogTerminalFlag.Name),
PprofEnabled: ctx.GlobalBool(flags.PprofEnabledFlag.Name),
PprofAddr: ctx.GlobalString(flags.PprofAddrFlag.Name),
PprofPort: ctx.GlobalString(flags.PprofPortFlag.Name),
RPCConfig: oprpc.ReadCLIConfig(ctx),
LogConfig: oplog.ReadCLIConfig(ctx),
MetricsConfig: opmetrics.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx),
}
}
1 change: 1 addition & 0 deletions op-batcher/docker.go.work
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ use (
./op-bindings
./op-node
./op-proposer
./op-service
)
Loading

0 comments on commit 8ed8d4e

Please sign in to comment.