config.go 5.64 KB
Newer Older
1 2
package config

3
import (
4
	"encoding/json"
5
	"errors"
6 7
	"fmt"
	"os"
8 9 10

	opnode "github.com/ethereum-optimism/optimism/op-node"
	"github.com/ethereum-optimism/optimism/op-node/rollup"
11
	"github.com/ethereum-optimism/optimism/op-node/sources"
12
	"github.com/ethereum-optimism/optimism/op-program/host/flags"
13
	"github.com/ethereum/go-ethereum/common"
14 15
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/params"
16 17 18 19 20
	"github.com/urfave/cli"
)

var (
	ErrMissingRollupConfig = errors.New("missing rollup config")
21
	ErrMissingL2Genesis    = errors.New("missing l2 genesis")
22
	ErrInvalidL1Head       = errors.New("invalid l1 head")
23
	ErrInvalidL2Head       = errors.New("invalid l2 head")
24
	ErrL1AndL2Inconsistent = errors.New("l1 and l2 options must be specified together or both omitted")
25
	ErrInvalidL2Claim      = errors.New("invalid l2 claim")
26
	ErrInvalidL2ClaimBlock = errors.New("invalid l2 claim block number")
27
	ErrDataDirRequired     = errors.New("datadir must be specified when in non-fetching mode")
28
	ErrNoExecInServerMode  = errors.New("exec command must not be set when in server mode")
29
)
30 31

type Config struct {
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
	Rollup *rollup.Config
	// DataDir is the directory to read/write pre-image data from/to.
	//If not set, an in-memory key-value store is used and fetching data must be enabled
	DataDir string

	// L1Head is the block has of the L1 chain head block
	L1Head     common.Hash
	L1URL      string
	L1TrustRPC bool
	L1RPCKind  sources.RPCProviderKind

	// L2Head is the agreed L2 block to start derivation from
	L2Head common.Hash
	L2URL  string
	// L2Claim is the claimed L2 output root to verify
	L2Claim common.Hash
48 49 50
	// L2ClaimBlockNumber is the block number the claimed L2 output root is from
	// Must be above 0 and to be a valid claim needs to be above the L2Head block.
	L2ClaimBlockNumber uint64
51 52
	// L2ChainConfig is the op-geth chain config for the L2 execution engine
	L2ChainConfig *params.ChainConfig
53 54 55
	// ExecCmd specifies the client program to execute in a separate process.
	// If unset, the fault proof client is run in the same process.
	ExecCmd string
56 57 58 59

	// ServerMode indicates that the program should run in pre-image server mode and wait for requests.
	// No client program is run.
	ServerMode bool
60 61
}

62 63 64 65 66 67 68
func (c *Config) Check() error {
	if c.Rollup == nil {
		return ErrMissingRollupConfig
	}
	if err := c.Rollup.Check(); err != nil {
		return err
	}
69 70
	if c.L1Head == (common.Hash{}) {
		return ErrInvalidL1Head
71 72 73 74
	}
	if c.L2Head == (common.Hash{}) {
		return ErrInvalidL2Head
	}
75 76 77
	if c.L2Claim == (common.Hash{}) {
		return ErrInvalidL2Claim
	}
78 79 80
	if c.L2ClaimBlockNumber == 0 {
		return ErrInvalidL2ClaimBlock
	}
81
	if c.L2ChainConfig == nil {
82 83
		return ErrMissingL2Genesis
	}
84 85 86
	if (c.L1URL != "") != (c.L2URL != "") {
		return ErrL1AndL2Inconsistent
	}
87 88 89
	if !c.FetchingEnabled() && c.DataDir == "" {
		return ErrDataDirRequired
	}
90 91 92
	if c.ServerMode && c.ExecCmd != "" {
		return ErrNoExecInServerMode
	}
93 94 95
	return nil
}

96
func (c *Config) FetchingEnabled() bool {
97
	return c.L1URL != "" && c.L2URL != ""
98 99
}

100
// NewConfig creates a Config with all optional values set to the CLI default value
101
func NewConfig(rollupCfg *rollup.Config, l2Genesis *params.ChainConfig, l1Head common.Hash, l2Head common.Hash, l2Claim common.Hash, l2ClaimBlockNum uint64) *Config {
102
	return &Config{
103 104 105 106 107 108 109
		Rollup:             rollupCfg,
		L2ChainConfig:      l2Genesis,
		L1Head:             l1Head,
		L2Head:             l2Head,
		L2Claim:            l2Claim,
		L2ClaimBlockNumber: l2ClaimBlockNum,
		L1RPCKind:          sources.RPCKindBasic,
110
	}
111 112
}

113 114 115 116 117 118 119 120
func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
	if err := flags.CheckRequired(ctx); err != nil {
		return nil, err
	}
	rollupCfg, err := opnode.NewRollupConfig(ctx)
	if err != nil {
		return nil, err
	}
121 122 123 124
	l2Head := common.HexToHash(ctx.GlobalString(flags.L2Head.Name))
	if l2Head == (common.Hash{}) {
		return nil, ErrInvalidL2Head
	}
125 126 127 128
	l2Claim := common.HexToHash(ctx.GlobalString(flags.L2Claim.Name))
	if l2Claim == (common.Hash{}) {
		return nil, ErrInvalidL2Claim
	}
129
	l2ClaimBlockNum := ctx.GlobalUint64(flags.L2BlockNumber.Name)
130 131 132 133
	l1Head := common.HexToHash(ctx.GlobalString(flags.L1Head.Name))
	if l1Head == (common.Hash{}) {
		return nil, ErrInvalidL1Head
	}
134
	l2GenesisPath := ctx.GlobalString(flags.L2GenesisPath.Name)
135 136 137 138 139 140 141 142 143 144
	var l2ChainConfig *params.ChainConfig
	if l2GenesisPath == "" {
		networkName := ctx.GlobalString(flags.Network.Name)
		l2ChainConfig = L2ChainConfigsByName[networkName]
		if l2ChainConfig == nil {
			return nil, fmt.Errorf("flag %s is required for network %s", flags.L2GenesisPath.Name, networkName)
		}
	} else {
		l2ChainConfig, err = loadChainConfigFromGenesis(l2GenesisPath)
	}
145 146 147
	if err != nil {
		return nil, fmt.Errorf("invalid genesis: %w", err)
	}
148
	return &Config{
149 150 151 152 153 154 155 156 157 158 159
		Rollup:             rollupCfg,
		DataDir:            ctx.GlobalString(flags.DataDir.Name),
		L2URL:              ctx.GlobalString(flags.L2NodeAddr.Name),
		L2ChainConfig:      l2ChainConfig,
		L2Head:             l2Head,
		L2Claim:            l2Claim,
		L2ClaimBlockNumber: l2ClaimBlockNum,
		L1Head:             l1Head,
		L1URL:              ctx.GlobalString(flags.L1NodeAddr.Name),
		L1TrustRPC:         ctx.GlobalBool(flags.L1TrustRPC.Name),
		L1RPCKind:          sources.RPCProviderKind(ctx.GlobalString(flags.L1RPCProviderKind.Name)),
160 161
		ExecCmd:            ctx.GlobalString(flags.Exec.Name),
		ServerMode:         ctx.GlobalBool(flags.Server.Name),
162
	}, nil
163
}
164 165 166 167 168 169 170 171 172 173 174 175 176

func loadChainConfigFromGenesis(path string) (*params.ChainConfig, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("read l2 genesis file: %w", err)
	}
	var genesis core.Genesis
	err = json.Unmarshal(data, &genesis)
	if err != nil {
		return nil, fmt.Errorf("parse l2 genesis file: %w", err)
	}
	return genesis.Config, nil
}