Commit 4352684f authored by Adrian Sutton's avatar Adrian Sutton

op-node: Add CLI flag to persist changes made via RPC Admin APIs.

parent 449321bd
......@@ -170,6 +170,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
EnableAdmin: true,
},
L1EpochPollInterval: time.Second * 4,
ConfigPersistence: &rollupNode.DisabledConfigPersistence{},
},
"verifier": {
Driver: driver.Config{
......@@ -178,6 +179,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
SequencerEnabled: false,
},
L1EpochPollInterval: time.Second * 4,
ConfigPersistence: &rollupNode.DisabledConfigPersistence{},
},
},
Loggers: map[string]log.Logger{
......
......@@ -59,6 +59,11 @@ var (
Usage: "Enable the admin API (experimental)",
EnvVars: prefixEnvVars("RPC_ENABLE_ADMIN"),
}
RPCAdminPersistence = &cli.StringFlag{
Name: "rpc.admin-state",
Usage: "File path used to persist state changes made via the admin API so they persist across restarts",
EnvVars: prefixEnvVars("RPC_ADMIN_STATE"),
}
/* Optional Flags */
L1TrustRPC = &cli.BoolFlag{
......@@ -233,6 +238,7 @@ var optionalFlags = []cli.Flag{
SequencerL1Confs,
L1EpochPollIntervalFlag,
RPCEnableAdmin,
RPCAdminPersistence,
MetricsEnabledFlag,
MetricsAddrFlag,
MetricsPortFlag,
......
......@@ -36,6 +36,8 @@ type Config struct {
// Used to poll the L1 for new finalized or safe blocks
L1EpochPollInterval time.Duration
ConfigPersistence ConfigPersistence
// Optional
Tracer Tracer
Heartbeat HeartbeatConfig
......
......@@ -12,9 +12,9 @@ import (
type RunningState int
const (
Unset RunningState = iota
Started
Stopped
StateUnset RunningState = iota
StateStarted
StateStopped
)
type persistedState struct {
......@@ -35,8 +35,8 @@ type ActiveConfigPersistence struct {
file string
}
func NewConfigPersistence(file string) (*ActiveConfigPersistence, error) {
return &ActiveConfigPersistence{file: file}, nil
func NewConfigPersistence(file string) *ActiveConfigPersistence {
return &ActiveConfigPersistence{file: file}
}
func (p *ActiveConfigPersistence) SequencerStarted() error {
......@@ -88,15 +88,15 @@ func (p *ActiveConfigPersistence) persist(sequencerStarted bool) error {
func (p *ActiveConfigPersistence) SequencerState() (RunningState, error) {
config, err := p.read()
if err != nil {
return Unset, err
return StateUnset, err
}
if config.SequencerStarted == nil {
return Unset, nil
return StateUnset, nil
} else if *config.SequencerStarted {
return Started, nil
return StateStarted, nil
} else {
return Stopped, nil
return StateStopped, nil
}
}
......@@ -122,7 +122,7 @@ type DisabledConfigPersistence struct {
}
func (d DisabledConfigPersistence) SequencerState() (RunningState, error) {
return Unset, nil
return StateUnset, nil
}
func (d DisabledConfigPersistence) SequencerStarted() error {
......
......@@ -9,8 +9,7 @@ import (
func TestActive(t *testing.T) {
create := func() *ActiveConfigPersistence {
dir := t.TempDir()
config, err := NewConfigPersistence(dir + "/state")
require.NoError(t, err)
config := NewConfigPersistence(dir + "/state")
return config
}
......@@ -18,7 +17,7 @@ func TestActive(t *testing.T) {
config := create()
state, err := config.SequencerState()
require.NoError(t, err)
require.Equal(t, Unset, state)
require.Equal(t, StateUnset, state)
})
t.Run("PersistSequencerStarted", func(t *testing.T) {
......@@ -26,13 +25,12 @@ func TestActive(t *testing.T) {
require.NoError(t, config1.SequencerStarted())
state, err := config1.SequencerState()
require.NoError(t, err)
require.Equal(t, Started, state)
require.Equal(t, StateStarted, state)
config2, err := NewConfigPersistence(config1.file)
require.NoError(t, err)
config2 := NewConfigPersistence(config1.file)
state, err = config2.SequencerState()
require.NoError(t, err)
require.Equal(t, Started, state)
require.Equal(t, StateStarted, state)
})
t.Run("PersistSequencerStopped", func(t *testing.T) {
......@@ -40,13 +38,12 @@ func TestActive(t *testing.T) {
require.NoError(t, config1.SequencerStopped())
state, err := config1.SequencerState()
require.NoError(t, err)
require.Equal(t, Stopped, state)
require.Equal(t, StateStopped, state)
config2, err := NewConfigPersistence(config1.file)
require.NoError(t, err)
config2 := NewConfigPersistence(config1.file)
state, err = config2.SequencerState()
require.NoError(t, err)
require.Equal(t, Stopped, state)
require.Equal(t, StateStopped, state)
})
t.Run("PersistMultipleChanges", func(t *testing.T) {
......@@ -54,23 +51,22 @@ func TestActive(t *testing.T) {
require.NoError(t, config.SequencerStarted())
state, err := config.SequencerState()
require.NoError(t, err)
require.Equal(t, Started, state)
require.Equal(t, StateStarted, state)
require.NoError(t, config.SequencerStopped())
state, err = config.SequencerState()
require.NoError(t, err)
require.Equal(t, Stopped, state)
require.Equal(t, StateStopped, state)
})
t.Run("CreateParentDirs", func(t *testing.T) {
dir := t.TempDir()
config, err := NewConfigPersistence(dir + "/some/dir/state")
require.NoError(t, err)
config := NewConfigPersistence(dir + "/some/dir/state")
// Should be unset before file exists
state, err := config.SequencerState()
require.NoError(t, err)
require.Equal(t, Unset, state)
require.Equal(t, StateUnset, state)
require.NoFileExists(t, config.file)
// Should create directories when updating
......@@ -78,7 +74,7 @@ func TestActive(t *testing.T) {
require.FileExists(t, config.file)
state, err = config.SequencerState()
require.NoError(t, err)
require.Equal(t, Started, state)
require.Equal(t, StateStarted, state)
})
}
......@@ -86,15 +82,15 @@ func TestDisabledConfigPersistence_AlwaysUnset(t *testing.T) {
config := DisabledConfigPersistence{}
state, err := config.SequencerState()
require.NoError(t, err)
require.Equal(t, Unset, state)
require.Equal(t, StateUnset, state)
require.NoError(t, config.SequencerStarted())
state, err = config.SequencerState()
require.NoError(t, err)
require.Equal(t, Unset, state)
require.Equal(t, StateUnset, state)
require.NoError(t, config.SequencerStopped())
state, err = config.SequencerState()
require.NoError(t, err)
require.Equal(t, Unset, state)
require.Equal(t, StateUnset, state)
}
......@@ -199,7 +199,7 @@ func (n *OpNode) initL2(ctx context.Context, cfg *Config, snapshotLog log.Logger
return err
}
n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.l2Source, n.l1Source, n, n, n.log, snapshotLog, n.metrics, DisabledConfigPersistence{})
n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.l2Source, n.l1Source, n, n, n.log, snapshotLog, n.metrics, cfg.ConfigPersistence)
return nil
}
......
......@@ -91,6 +91,8 @@ type Driver struct {
func (s *Driver) Start() error {
s.derivation.Reset()
log.Info("Starting driver", "sequencerEnabled", s.driverConfig.SequencerEnabled, "sequencerStopped", s.driverConfig.SequencerStopped)
s.wg.Add(1)
go s.eventLoop()
......
......@@ -11,7 +11,6 @@ import (
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/sources"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/common"
......@@ -36,7 +35,12 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
return nil, err
}
driverConfig := NewDriverConfig(ctx)
configPersistence := NewConfigPersistence(ctx)
driverConfig, err := NewDriverConfig(ctx, configPersistence)
if err != nil {
return nil, fmt.Errorf("failed to load driver config: %w", err)
}
p2pSignerSetup, err := p2pcli.LoadSignerSetup(ctx)
if err != nil {
......@@ -86,6 +90,7 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
Moniker: ctx.String(flags.HeartbeatMonikerFlag.Name),
URL: ctx.String(flags.HeartbeatURLFlag.Name),
},
ConfigPersistence: configPersistence,
}
if err := cfg.Check(); err != nil {
return nil, err
......@@ -143,14 +148,29 @@ func NewL2SyncEndpointConfig(ctx *cli.Context) *node.L2SyncEndpointConfig {
}
}
func NewDriverConfig(ctx *cli.Context) *driver.Config {
func NewConfigPersistence(ctx *cli.Context) node.ConfigPersistence {
stateFile := ctx.String(flags.RPCAdminPersistence.Name)
if stateFile == "" {
return node.DisabledConfigPersistence{}
}
return node.NewConfigPersistence(stateFile)
}
func NewDriverConfig(ctx *cli.Context, config node.ConfigPersistence) (*driver.Config, error) {
sequencerStopped := ctx.Bool(flags.SequencerStoppedFlag.Name)
if state, err := config.SequencerState(); err != nil {
return nil, err
} else if state != node.StateUnset {
sequencerStopped = state == node.StateStopped
}
return &driver.Config{
VerifierConfDepth: ctx.Uint64(flags.VerifierL1Confs.Name),
SequencerConfDepth: ctx.Uint64(flags.SequencerL1Confs.Name),
SequencerEnabled: ctx.Bool(flags.SequencerEnabledFlag.Name),
SequencerStopped: ctx.Bool(flags.SequencerStoppedFlag.Name),
SequencerStopped: sequencerStopped,
SequencerMaxSafeLag: ctx.Uint64(flags.SequencerMaxSafeLagFlag.Name),
}
}, nil
}
func NewRollupConfig(ctx *cli.Context) (*rollup.Config, error) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment