github.com/ethereum-optimism/optimism@v1.7.2/op-node/service.go (about)

     1  package opnode
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"strings"
    11  
    12  	"github.com/ethereum-optimism/optimism/op-node/chaincfg"
    13  	plasma "github.com/ethereum-optimism/optimism/op-plasma"
    14  	"github.com/ethereum-optimism/optimism/op-service/oppprof"
    15  	"github.com/ethereum-optimism/optimism/op-service/sources"
    16  	"github.com/ethereum/go-ethereum/common"
    17  	"github.com/ethereum/go-ethereum/common/hexutil"
    18  	"github.com/ethereum/go-ethereum/log"
    19  	"github.com/urfave/cli/v2"
    20  
    21  	"github.com/ethereum-optimism/optimism/op-node/flags"
    22  	"github.com/ethereum-optimism/optimism/op-node/node"
    23  	p2pcli "github.com/ethereum-optimism/optimism/op-node/p2p/cli"
    24  	"github.com/ethereum-optimism/optimism/op-node/rollup"
    25  	"github.com/ethereum-optimism/optimism/op-node/rollup/driver"
    26  	"github.com/ethereum-optimism/optimism/op-node/rollup/sync"
    27  	opflags "github.com/ethereum-optimism/optimism/op-service/flags"
    28  )
    29  
    30  // NewConfig creates a Config from the provided flags or environment variables.
    31  func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
    32  	if err := flags.CheckRequired(ctx); err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	rollupConfig, err := NewRollupConfigFromCLI(log, ctx)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	if !ctx.Bool(flags.RollupLoadProtocolVersions.Name) {
    42  		log.Info("Not opted in to ProtocolVersions signal loading, disabling ProtocolVersions contract now.")
    43  		rollupConfig.ProtocolVersionsAddress = common.Address{}
    44  	}
    45  
    46  	configPersistence := NewConfigPersistence(ctx)
    47  
    48  	driverConfig := NewDriverConfig(ctx)
    49  
    50  	p2pSignerSetup, err := p2pcli.LoadSignerSetup(ctx)
    51  	if err != nil {
    52  		return nil, fmt.Errorf("failed to load p2p signer: %w", err)
    53  	}
    54  
    55  	p2pConfig, err := p2pcli.NewConfig(ctx, rollupConfig)
    56  	if err != nil {
    57  		return nil, fmt.Errorf("failed to load p2p config: %w", err)
    58  	}
    59  
    60  	l1Endpoint := NewL1EndpointConfig(ctx)
    61  
    62  	l2Endpoint, err := NewL2EndpointConfig(ctx, log)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("failed to load l2 endpoints info: %w", err)
    65  	}
    66  
    67  	syncConfig, err := NewSyncConfig(ctx, log)
    68  	if err != nil {
    69  		return nil, fmt.Errorf("failed to create the sync config: %w", err)
    70  	}
    71  
    72  	haltOption := ctx.String(flags.RollupHalt.Name)
    73  	if haltOption == "none" {
    74  		haltOption = ""
    75  	}
    76  
    77  	cfg := &node.Config{
    78  		L1:     l1Endpoint,
    79  		L2:     l2Endpoint,
    80  		Rollup: *rollupConfig,
    81  		Driver: *driverConfig,
    82  		Beacon: NewBeaconEndpointConfig(ctx),
    83  		RPC: node.RPCConfig{
    84  			ListenAddr:  ctx.String(flags.RPCListenAddr.Name),
    85  			ListenPort:  ctx.Int(flags.RPCListenPort.Name),
    86  			EnableAdmin: ctx.Bool(flags.RPCEnableAdmin.Name),
    87  		},
    88  		Metrics: node.MetricsConfig{
    89  			Enabled:    ctx.Bool(flags.MetricsEnabledFlag.Name),
    90  			ListenAddr: ctx.String(flags.MetricsAddrFlag.Name),
    91  			ListenPort: ctx.Int(flags.MetricsPortFlag.Name),
    92  		},
    93  		Pprof:                       oppprof.ReadCLIConfig(ctx),
    94  		P2P:                         p2pConfig,
    95  		P2PSigner:                   p2pSignerSetup,
    96  		L1EpochPollInterval:         ctx.Duration(flags.L1EpochPollIntervalFlag.Name),
    97  		RuntimeConfigReloadInterval: ctx.Duration(flags.RuntimeConfigReloadIntervalFlag.Name),
    98  		Heartbeat: node.HeartbeatConfig{
    99  			Enabled: ctx.Bool(flags.HeartbeatEnabledFlag.Name),
   100  			Moniker: ctx.String(flags.HeartbeatMonikerFlag.Name),
   101  			URL:     ctx.String(flags.HeartbeatURLFlag.Name),
   102  		},
   103  		ConfigPersistence: configPersistence,
   104  		SafeDBPath:        ctx.String(flags.SafeDBPath.Name),
   105  		Sync:              *syncConfig,
   106  		RollupHalt:        haltOption,
   107  		RethDBPath:        ctx.String(flags.L1RethDBPath.Name),
   108  
   109  		ConductorEnabled:    ctx.Bool(flags.ConductorEnabledFlag.Name),
   110  		ConductorRpc:        ctx.String(flags.ConductorRpcFlag.Name),
   111  		ConductorRpcTimeout: ctx.Duration(flags.ConductorRpcTimeoutFlag.Name),
   112  
   113  		Plasma: plasma.ReadCLIConfig(ctx),
   114  	}
   115  
   116  	if err := cfg.LoadPersisted(log); err != nil {
   117  		return nil, fmt.Errorf("failed to load driver config: %w", err)
   118  	}
   119  
   120  	// conductor controls the sequencer state
   121  	if cfg.ConductorEnabled {
   122  		cfg.Driver.SequencerStopped = true
   123  	}
   124  
   125  	if err := cfg.Check(); err != nil {
   126  		return nil, err
   127  	}
   128  	return cfg, nil
   129  }
   130  
   131  func NewBeaconEndpointConfig(ctx *cli.Context) node.L1BeaconEndpointSetup {
   132  	return &node.L1BeaconEndpointConfig{
   133  		BeaconAddr:             ctx.String(flags.BeaconAddr.Name),
   134  		BeaconHeader:           ctx.String(flags.BeaconHeader.Name),
   135  		BeaconArchiverAddr:     ctx.String(flags.BeaconArchiverAddr.Name),
   136  		BeaconCheckIgnore:      ctx.Bool(flags.BeaconCheckIgnore.Name),
   137  		BeaconFetchAllSidecars: ctx.Bool(flags.BeaconFetchAllSidecars.Name),
   138  	}
   139  }
   140  
   141  func NewL1EndpointConfig(ctx *cli.Context) *node.L1EndpointConfig {
   142  	return &node.L1EndpointConfig{
   143  		L1NodeAddr:       ctx.String(flags.L1NodeAddr.Name),
   144  		L1TrustRPC:       ctx.Bool(flags.L1TrustRPC.Name),
   145  		L1RPCKind:        sources.RPCProviderKind(strings.ToLower(ctx.String(flags.L1RPCProviderKind.Name))),
   146  		RateLimit:        ctx.Float64(flags.L1RPCRateLimit.Name),
   147  		BatchSize:        ctx.Int(flags.L1RPCMaxBatchSize.Name),
   148  		HttpPollInterval: ctx.Duration(flags.L1HTTPPollInterval.Name),
   149  		MaxConcurrency:   ctx.Int(flags.L1RPCMaxConcurrency.Name),
   150  	}
   151  }
   152  
   153  func NewL2EndpointConfig(ctx *cli.Context, log log.Logger) (*node.L2EndpointConfig, error) {
   154  	l2Addr := ctx.String(flags.L2EngineAddr.Name)
   155  	fileName := ctx.String(flags.L2EngineJWTSecret.Name)
   156  	var secret [32]byte
   157  	fileName = strings.TrimSpace(fileName)
   158  	if fileName == "" {
   159  		return nil, fmt.Errorf("file-name of jwt secret is empty")
   160  	}
   161  	if data, err := os.ReadFile(fileName); err == nil {
   162  		jwtSecret := common.FromHex(strings.TrimSpace(string(data)))
   163  		if len(jwtSecret) != 32 {
   164  			return nil, fmt.Errorf("invalid jwt secret in path %s, not 32 hex-formatted bytes", fileName)
   165  		}
   166  		copy(secret[:], jwtSecret)
   167  	} else {
   168  		log.Warn("Failed to read JWT secret from file, generating a new one now. Configure L2 geth with --authrpc.jwt-secret=" + fmt.Sprintf("%q", fileName))
   169  		if _, err := io.ReadFull(rand.Reader, secret[:]); err != nil {
   170  			return nil, fmt.Errorf("failed to generate jwt secret: %w", err)
   171  		}
   172  		if err := os.WriteFile(fileName, []byte(hexutil.Encode(secret[:])), 0o600); err != nil {
   173  			return nil, err
   174  		}
   175  	}
   176  
   177  	return &node.L2EndpointConfig{
   178  		L2EngineAddr:      l2Addr,
   179  		L2EngineJWTSecret: secret,
   180  	}, nil
   181  }
   182  
   183  func NewConfigPersistence(ctx *cli.Context) node.ConfigPersistence {
   184  	stateFile := ctx.String(flags.RPCAdminPersistence.Name)
   185  	if stateFile == "" {
   186  		return node.DisabledConfigPersistence{}
   187  	}
   188  	return node.NewConfigPersistence(stateFile)
   189  }
   190  
   191  func NewDriverConfig(ctx *cli.Context) *driver.Config {
   192  	return &driver.Config{
   193  		VerifierConfDepth:   ctx.Uint64(flags.VerifierL1Confs.Name),
   194  		SequencerConfDepth:  ctx.Uint64(flags.SequencerL1Confs.Name),
   195  		SequencerEnabled:    ctx.Bool(flags.SequencerEnabledFlag.Name),
   196  		SequencerStopped:    ctx.Bool(flags.SequencerStoppedFlag.Name),
   197  		SequencerMaxSafeLag: ctx.Uint64(flags.SequencerMaxSafeLagFlag.Name),
   198  	}
   199  }
   200  
   201  func NewRollupConfigFromCLI(log log.Logger, ctx *cli.Context) (*rollup.Config, error) {
   202  	network := ctx.String(opflags.NetworkFlagName)
   203  	rollupConfigPath := ctx.String(opflags.RollupConfigFlagName)
   204  	if ctx.Bool(flags.BetaExtraNetworks.Name) {
   205  		log.Warn("The beta.extra-networks flag is deprecated and can be omitted safely.")
   206  	}
   207  	rollupConfig, err := NewRollupConfig(log, network, rollupConfigPath)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	applyOverrides(ctx, rollupConfig)
   212  	return rollupConfig, nil
   213  }
   214  
   215  func NewRollupConfig(log log.Logger, network string, rollupConfigPath string) (*rollup.Config, error) {
   216  	if network != "" {
   217  		if rollupConfigPath != "" {
   218  			log.Error(`Cannot configure network and rollup-config at the same time.
   219  Startup will proceed to use the network-parameter and ignore the rollup config.
   220  Conflicting configuration is deprecated, and will stop the op-node from starting in the future.
   221  `, "network", network, "rollup_config", rollupConfigPath)
   222  		}
   223  		rollupConfig, err := chaincfg.GetRollupConfig(network)
   224  		if err != nil {
   225  			return nil, err
   226  		}
   227  		return rollupConfig, nil
   228  	}
   229  
   230  	file, err := os.Open(rollupConfigPath)
   231  	if err != nil {
   232  		return nil, fmt.Errorf("failed to read rollup config: %w", err)
   233  	}
   234  	defer file.Close()
   235  
   236  	var rollupConfig rollup.Config
   237  	if err := json.NewDecoder(file).Decode(&rollupConfig); err != nil {
   238  		return nil, fmt.Errorf("failed to decode rollup config: %w", err)
   239  	}
   240  	return &rollupConfig, nil
   241  }
   242  
   243  func applyOverrides(ctx *cli.Context, rollupConfig *rollup.Config) {
   244  	if ctx.IsSet(opflags.CanyonOverrideFlagName) {
   245  		canyon := ctx.Uint64(opflags.CanyonOverrideFlagName)
   246  		rollupConfig.CanyonTime = &canyon
   247  	}
   248  	if ctx.IsSet(opflags.DeltaOverrideFlagName) {
   249  		delta := ctx.Uint64(opflags.DeltaOverrideFlagName)
   250  		rollupConfig.DeltaTime = &delta
   251  	}
   252  	if ctx.IsSet(opflags.EcotoneOverrideFlagName) {
   253  		ecotone := ctx.Uint64(opflags.EcotoneOverrideFlagName)
   254  		rollupConfig.EcotoneTime = &ecotone
   255  	}
   256  }
   257  
   258  func NewSnapshotLogger(ctx *cli.Context) (log.Logger, error) {
   259  	snapshotFile := ctx.String(flags.SnapshotLog.Name)
   260  	if snapshotFile == "" {
   261  		return log.NewLogger(log.DiscardHandler()), nil
   262  	}
   263  
   264  	sf, err := os.OpenFile(snapshotFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
   265  	if err != nil {
   266  		return nil, err
   267  	}
   268  	handler := log.JSONHandler(sf)
   269  	return log.NewLogger(handler), nil
   270  }
   271  
   272  func NewSyncConfig(ctx *cli.Context, log log.Logger) (*sync.Config, error) {
   273  	if ctx.IsSet(flags.L2EngineSyncEnabled.Name) && ctx.IsSet(flags.SyncModeFlag.Name) {
   274  		return nil, errors.New("cannot set both --l2.engine-sync and --syncmode at the same time.")
   275  	} else if ctx.IsSet(flags.L2EngineSyncEnabled.Name) {
   276  		log.Error("l2.engine-sync is deprecated and will be removed in a future release. Use --syncmode=execution-layer instead.")
   277  	}
   278  	mode, err := sync.StringToMode(ctx.String(flags.SyncModeFlag.Name))
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  	cfg := &sync.Config{
   283  		SyncMode:           mode,
   284  		SkipSyncStartCheck: ctx.Bool(flags.SkipSyncStartCheck.Name),
   285  	}
   286  	if ctx.Bool(flags.L2EngineSyncEnabled.Name) {
   287  		cfg.SyncMode = sync.ELSync
   288  	}
   289  
   290  	return cfg, nil
   291  }