forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[op-conductor] Initial setup (ethereum-optimism#8642)
* Initial setup for op-conductor * Rework based on feedback * Update README * Update README * Rework flags structure * Add tests * Add CI configs * Add dockerfile * Remove TODO --------- Co-authored-by: Matthew Slipper <[email protected]>
- Loading branch information
1 parent
7e57109
commit f3da73d
Showing
19 changed files
with
590 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
bin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
ARG OP_STACK_GO_BUILDER=us-docker.pkg.dev/oplabs-tools-artifacts/images/op-stack-go:latest | ||
FROM $OP_STACK_GO_BUILDER as builder | ||
# See "make golang-docker" and /ops/docker/op-stack-go | ||
|
||
FROM alpine:3.18 | ||
|
||
COPY --from=builder /usr/local/bin/op-conductor /usr/local/bin/op-conductor | ||
|
||
CMD ["op-conductor"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
GITCOMMIT ?= $(shell git rev-parse HEAD) | ||
GITDATE ?= $(shell git show -s --format='%ct') | ||
VERSION := v0.0.0 | ||
|
||
LDFLAGSSTRING +=-X main.GitCommit=$(GITCOMMIT) | ||
LDFLAGSSTRING +=-X main.GitDate=$(GITDATE) | ||
LDFLAGSSTRING +=-X main.Version=$(VERSION) | ||
LDFLAGS := -ldflags "$(LDFLAGSSTRING)" | ||
|
||
op-conductor: | ||
env GO111MODULE=on GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -v $(LDFLAGS) -o ./bin/op-conductor ./cmd | ||
|
||
clean: | ||
rm bin/op-conductor | ||
|
||
test: | ||
go test -v ./... | ||
|
||
.PHONY: \ | ||
clean \ | ||
op-conductor \ | ||
test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# op-conductor | ||
|
||
op-conductor is an auxiliary service designed to enhance the reliability and availability of a sequencer in | ||
high-availability setups, thereby minimizing the risks associated with single point of failure. | ||
It is important to note, however, that this design does not incorporate Byzantine fault tolerance. | ||
This means it operates under the assumption that all participating nodes are honest. | ||
|
||
## Summary | ||
|
||
The design will provide below guarantees: | ||
|
||
1. No unsafe reorgs | ||
2. No unsafe head stall during network partition | ||
3. 100% uptime with no more than 1 node failure (for a standard 3 node setup) | ||
|
||
## Design | ||
|
||
 | ||
On a high level, op-conductor serves the following functions: | ||
|
||
1. serves as a (raft) consensus layer participant to determine | ||
1. leader of the sequencers | ||
2. store latest unsafe block within its state machine. | ||
2. serves rpc requests for | ||
1. admin rpc for manual recovery scenarios such as stop leadership vote, remove itself from cluster, etc | ||
2. health rpc for op-node to determine if it should allow publish txs / unsafe blocks | ||
3. monitor sequencer (op-node) health | ||
4. control loop => control sequencer (op-node) status (start / stop) based on different scenarios | ||
|
||
This is initial version of README, more details will be added later. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/ethereum/go-ethereum/log" | ||
"github.com/urfave/cli/v2" | ||
|
||
"github.com/ethereum-optimism/optimism/op-conductor/conductor" | ||
"github.com/ethereum-optimism/optimism/op-conductor/flags" | ||
opservice "github.com/ethereum-optimism/optimism/op-service" | ||
"github.com/ethereum-optimism/optimism/op-service/cliapp" | ||
oplog "github.com/ethereum-optimism/optimism/op-service/log" | ||
"github.com/ethereum-optimism/optimism/op-service/opio" | ||
) | ||
|
||
var ( | ||
Version = "v0.0.1" | ||
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-conductor" | ||
app.Usage = "Optimism Sequencer Conductor Service" | ||
app.Description = "op-conductor help sequencer to run in highly available mode" | ||
app.Action = cliapp.LifecycleCmd(OpConductorMain) | ||
app.Commands = []*cli.Command{} | ||
|
||
ctx := opio.WithInterruptBlocker(context.Background()) | ||
err := app.RunContext(ctx, os.Args) | ||
if err != nil { | ||
log.Crit("Application failed", "message", err) | ||
} | ||
} | ||
|
||
func OpConductorMain(ctx *cli.Context, closeApp context.CancelCauseFunc) (cliapp.Lifecycle, error) { | ||
logCfg := oplog.ReadCLIConfig(ctx) | ||
log := oplog.NewLogger(oplog.AppOut(ctx), logCfg) | ||
oplog.SetGlobalLogHandler(log.GetHandler()) | ||
opservice.ValidateEnvVars(flags.EnvVarPrefix, flags.Flags, log) | ||
|
||
cfg, err := conductor.NewConfig(ctx, log) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to read config: %w", err) | ||
} | ||
|
||
c, err := conductor.New(ctx.Context, cfg, log, Version) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create conductor: %w", err) | ||
} | ||
|
||
return c, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package conductor | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ethereum/go-ethereum/log" | ||
"github.com/pkg/errors" | ||
"github.com/urfave/cli/v2" | ||
|
||
"github.com/ethereum-optimism/optimism/op-conductor/flags" | ||
opnode "github.com/ethereum-optimism/optimism/op-node" | ||
"github.com/ethereum-optimism/optimism/op-node/rollup" | ||
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" | ||
) | ||
|
||
type Config struct { | ||
// ConsensusAddr is the address to listen for consensus connections. | ||
ConsensusAddr string | ||
|
||
// ConsensusPort is the port to listen for consensus connections. | ||
ConsensusPort int | ||
|
||
// RaftServerID is the unique ID for this server used by raft consensus. | ||
RaftServerID string | ||
|
||
// RaftStorageDir is the directory to store raft data. | ||
RaftStorageDir string | ||
|
||
// RaftBootstrap is true if this node should bootstrap a new raft cluster. | ||
RaftBootstrap bool | ||
|
||
// NodeRPC is the HTTP provider URL for op-node. | ||
NodeRPC string | ||
|
||
RollupCfg rollup.Config | ||
|
||
LogConfig oplog.CLIConfig | ||
MetricsConfig opmetrics.CLIConfig | ||
PprofConfig oppprof.CLIConfig | ||
RPC oprpc.CLIConfig | ||
} | ||
|
||
// Check validates the CLIConfig. | ||
func (c *Config) Check() error { | ||
if c.ConsensusAddr == "" { | ||
return fmt.Errorf("missing consensus address") | ||
} | ||
if c.ConsensusPort == 0 { | ||
return fmt.Errorf("missing consensus port") | ||
} | ||
if c.RaftServerID == "" { | ||
return fmt.Errorf("missing raft server ID") | ||
} | ||
if c.RaftStorageDir == "" { | ||
return fmt.Errorf("missing raft storage directory") | ||
} | ||
if c.NodeRPC == "" { | ||
return fmt.Errorf("missing node RPC") | ||
} | ||
if err := c.RollupCfg.Check(); err != nil { | ||
return errors.Wrap(err, "invalid rollup config") | ||
} | ||
if err := c.MetricsConfig.Check(); err != nil { | ||
return errors.Wrap(err, "invalid metrics config") | ||
} | ||
if err := c.PprofConfig.Check(); err != nil { | ||
return errors.Wrap(err, "invalid pprof config") | ||
} | ||
if err := c.RPC.Check(); err != nil { | ||
return errors.Wrap(err, "invalid rpc config") | ||
} | ||
return nil | ||
} | ||
|
||
// NewConfig parses the Config from the provided flags or environment variables. | ||
func NewConfig(ctx *cli.Context, log log.Logger) (*Config, error) { | ||
if err := flags.CheckRequired(ctx); err != nil { | ||
return nil, errors.Wrap(err, "missing required flags") | ||
} | ||
|
||
rollupCfg, err := opnode.NewRollupConfig(log, ctx) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to load rollup config") | ||
} | ||
|
||
return &Config{ | ||
ConsensusAddr: ctx.String(flags.ConsensusAddr.Name), | ||
ConsensusPort: ctx.Int(flags.ConsensusPort.Name), | ||
RaftServerID: ctx.String(flags.RaftServerID.Name), | ||
RaftStorageDir: ctx.String(flags.RaftStorageDir.Name), | ||
NodeRPC: ctx.String(flags.NodeRPC.Name), | ||
RollupCfg: *rollupCfg, | ||
LogConfig: oplog.ReadCLIConfig(ctx), | ||
MetricsConfig: opmetrics.ReadCLIConfig(ctx), | ||
PprofConfig: oppprof.ReadCLIConfig(ctx), | ||
RPC: oprpc.ReadCLIConfig(ctx), | ||
}, nil | ||
} |
Oops, something went wrong.