Commit 6818a0c6 authored by Adrian Sutton's avatar Adrian Sutton

op-program: Specify l2 block number to stop derivation at

parent d7a4b366
...@@ -27,15 +27,17 @@ type Driver struct { ...@@ -27,15 +27,17 @@ type Driver struct {
logger log.Logger logger log.Logger
pipeline Derivation pipeline Derivation
l2OutputRoot func() (eth.Bytes32, error) l2OutputRoot func() (eth.Bytes32, error)
targetBlockNum uint64
} }
func NewDriver(logger log.Logger, cfg *rollup.Config, l1Source derive.L1Fetcher, l2Source L2Source) *Driver { func NewDriver(logger log.Logger, cfg *rollup.Config, l1Source derive.L1Fetcher, l2Source L2Source, targetBlockNum uint64) *Driver {
pipeline := derive.NewDerivationPipeline(logger, cfg, l1Source, l2Source, metrics.NoopMetrics) pipeline := derive.NewDerivationPipeline(logger, cfg, l1Source, l2Source, metrics.NoopMetrics)
pipeline.Reset() pipeline.Reset()
return &Driver{ return &Driver{
logger: logger, logger: logger,
pipeline: pipeline, pipeline: pipeline,
l2OutputRoot: l2Source.L2OutputRoot, l2OutputRoot: l2Source.L2OutputRoot,
targetBlockNum: targetBlockNum,
} }
} }
...@@ -47,6 +49,11 @@ func (d *Driver) Step(ctx context.Context) error { ...@@ -47,6 +49,11 @@ func (d *Driver) Step(ctx context.Context) error {
if err := d.pipeline.Step(ctx); errors.Is(err, io.EOF) { if err := d.pipeline.Step(ctx); errors.Is(err, io.EOF) {
return io.EOF return io.EOF
} else if errors.Is(err, derive.NotEnoughData) { } else if errors.Is(err, derive.NotEnoughData) {
head := d.pipeline.SafeL2Head()
if head.Number >= d.targetBlockNum {
d.logger.Info("Target L2 block reached", "head", head)
return io.EOF
}
d.logger.Debug("Data is lacking") d.logger.Debug("Data is lacking")
return nil return nil
} else if err != nil { } else if err != nil {
......
...@@ -39,6 +39,30 @@ func TestGenericError(t *testing.T) { ...@@ -39,6 +39,30 @@ func TestGenericError(t *testing.T) {
require.ErrorIs(t, err, expected) require.ErrorIs(t, err, expected)
} }
func TestTargetBlock(t *testing.T) {
t.Run("Reached", func(t *testing.T) {
driver := createDriverWithNextBlock(t, derive.NotEnoughData, 1000)
driver.targetBlockNum = 1000
err := driver.Step(context.Background())
require.ErrorIs(t, err, io.EOF)
})
t.Run("Exceeded", func(t *testing.T) {
driver := createDriverWithNextBlock(t, derive.NotEnoughData, 1000)
driver.targetBlockNum = 500
err := driver.Step(context.Background())
require.ErrorIs(t, err, io.EOF)
})
t.Run("NotYetReached", func(t *testing.T) {
driver := createDriverWithNextBlock(t, derive.NotEnoughData, 1000)
driver.targetBlockNum = 1001
err := driver.Step(context.Background())
// No error to indicate derivation should continue
require.NoError(t, err)
})
}
func TestNoError(t *testing.T) { func TestNoError(t *testing.T) {
driver := createDriver(t, nil) driver := createDriver(t, nil)
err := driver.Step(context.Background()) err := driver.Step(context.Background())
...@@ -76,15 +100,21 @@ func TestValidateClaim(t *testing.T) { ...@@ -76,15 +100,21 @@ func TestValidateClaim(t *testing.T) {
} }
func createDriver(t *testing.T, derivationResult error) *Driver { func createDriver(t *testing.T, derivationResult error) *Driver {
derivation := &stubDerivation{nextErr: derivationResult} return createDriverWithNextBlock(t, derivationResult, 0)
}
func createDriverWithNextBlock(t *testing.T, derivationResult error, nextBlockNum uint64) *Driver {
derivation := &stubDerivation{nextErr: derivationResult, nextBlockNum: nextBlockNum}
return &Driver{ return &Driver{
logger: testlog.Logger(t, log.LvlDebug), logger: testlog.Logger(t, log.LvlDebug),
pipeline: derivation, pipeline: derivation,
targetBlockNum: 1_000_000,
} }
} }
type stubDerivation struct { type stubDerivation struct {
nextErr error nextErr error
nextBlockNum uint64
} }
func (s stubDerivation) Step(ctx context.Context) error { func (s stubDerivation) Step(ctx context.Context) error {
...@@ -92,5 +122,7 @@ func (s stubDerivation) Step(ctx context.Context) error { ...@@ -92,5 +122,7 @@ func (s stubDerivation) Step(ctx context.Context) error {
} }
func (s stubDerivation) SafeL2Head() eth.L2BlockRef { func (s stubDerivation) SafeL2Head() eth.L2BlockRef {
return eth.L2BlockRef{} return eth.L2BlockRef{
Number: s.nextBlockNum,
}
} }
...@@ -173,7 +173,7 @@ func FaultProofProgram(logger log.Logger, cfg *config.Config) error { ...@@ -173,7 +173,7 @@ func FaultProofProgram(logger log.Logger, cfg *config.Config) error {
} }
logger.Info("Starting derivation") logger.Info("Starting derivation")
d := cldr.NewDriver(logger, cfg.Rollup, l1Source, l2Source) d := cldr.NewDriver(logger, cfg.Rollup, l1Source, l2Source, cfg.L2ClaimBlockNumber)
for { for {
if err = d.Step(ctx); errors.Is(err, io.EOF) { if err = d.Step(ctx); errors.Is(err, io.EOF) {
break break
......
...@@ -3,6 +3,7 @@ package main ...@@ -3,6 +3,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"os" "os"
"strconv"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
...@@ -14,15 +15,17 @@ import ( ...@@ -14,15 +15,17 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// Use HexToHash(...).Hex() to ensure the strings are the correct length for a hash var (
var l1HeadValue = common.HexToHash("0x111111").Hex() // Use HexToHash(...).Hex() to ensure the strings are the correct length for a hash
var l2HeadValue = common.HexToHash("0x222222").Hex() l1HeadValue = common.HexToHash("0x111111").Hex()
var l2ClaimValue = common.HexToHash("0x333333").Hex() l2HeadValue = common.HexToHash("0x222222").Hex()
var l2Genesis = core.DefaultGoerliGenesisBlock() l2ClaimValue = common.HexToHash("0x333333").Hex()
var l2GenesisConfig = l2Genesis.Config l2ClaimBlockNumber = uint64(1203)
l2Genesis = core.DefaultGoerliGenesisBlock()
l2GenesisConfig = l2Genesis.Config
)
func TestLogLevel(t *testing.T) { func TestLogLevel(t *testing.T) {
t.Parallel()
t.Run("RejectInvalid", func(t *testing.T) { t.Run("RejectInvalid", func(t *testing.T) {
verifyArgsInvalid(t, "unknown level: foo", addRequiredArgs(t, "--log.level=foo")) verifyArgsInvalid(t, "unknown level: foo", addRequiredArgs(t, "--log.level=foo"))
}) })
...@@ -38,19 +41,18 @@ func TestLogLevel(t *testing.T) { ...@@ -38,19 +41,18 @@ func TestLogLevel(t *testing.T) {
} }
func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) { func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
t.Parallel()
cfg := configForArgs(t, addRequiredArgs(t)) cfg := configForArgs(t, addRequiredArgs(t))
defaultCfg := config.NewConfig( defaultCfg := config.NewConfig(
&chaincfg.Goerli, &chaincfg.Goerli,
l2GenesisConfig, l2GenesisConfig,
common.HexToHash(l1HeadValue), common.HexToHash(l1HeadValue),
common.HexToHash(l2HeadValue), common.HexToHash(l2HeadValue),
common.HexToHash(l2ClaimValue)) common.HexToHash(l2ClaimValue),
l2ClaimBlockNumber)
require.Equal(t, defaultCfg, cfg) require.Equal(t, defaultCfg, cfg)
} }
func TestNetwork(t *testing.T) { func TestNetwork(t *testing.T) {
t.Parallel()
t.Run("Unknown", func(t *testing.T) { t.Run("Unknown", func(t *testing.T) {
verifyArgsInvalid(t, "invalid network bar", replaceRequiredArg(t, "--network", "bar")) verifyArgsInvalid(t, "invalid network bar", replaceRequiredArg(t, "--network", "bar"))
}) })
...@@ -86,21 +88,18 @@ func TestNetwork(t *testing.T) { ...@@ -86,21 +88,18 @@ func TestNetwork(t *testing.T) {
} }
func TestDataDir(t *testing.T) { func TestDataDir(t *testing.T) {
t.Parallel()
expected := "/tmp/mainTestDataDir" expected := "/tmp/mainTestDataDir"
cfg := configForArgs(t, addRequiredArgs(t, "--datadir", expected)) cfg := configForArgs(t, addRequiredArgs(t, "--datadir", expected))
require.Equal(t, expected, cfg.DataDir) require.Equal(t, expected, cfg.DataDir)
} }
func TestL2(t *testing.T) { func TestL2(t *testing.T) {
t.Parallel()
expected := "https://example.com:8545" expected := "https://example.com:8545"
cfg := configForArgs(t, addRequiredArgs(t, "--l2", expected)) cfg := configForArgs(t, addRequiredArgs(t, "--l2", expected))
require.Equal(t, expected, cfg.L2URL) require.Equal(t, expected, cfg.L2URL)
} }
func TestL2Genesis(t *testing.T) { func TestL2Genesis(t *testing.T) {
t.Parallel()
t.Run("Required", func(t *testing.T) { t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag l2.genesis is required", addRequiredArgsExcept(t, "--l2.genesis")) verifyArgsInvalid(t, "flag l2.genesis is required", addRequiredArgsExcept(t, "--l2.genesis"))
}) })
...@@ -112,7 +111,6 @@ func TestL2Genesis(t *testing.T) { ...@@ -112,7 +111,6 @@ func TestL2Genesis(t *testing.T) {
} }
func TestL2Head(t *testing.T) { func TestL2Head(t *testing.T) {
t.Parallel()
t.Run("Required", func(t *testing.T) { t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag l2.head is required", addRequiredArgsExcept(t, "--l2.head")) verifyArgsInvalid(t, "flag l2.head is required", addRequiredArgsExcept(t, "--l2.head"))
}) })
...@@ -128,7 +126,6 @@ func TestL2Head(t *testing.T) { ...@@ -128,7 +126,6 @@ func TestL2Head(t *testing.T) {
} }
func TestL1Head(t *testing.T) { func TestL1Head(t *testing.T) {
t.Parallel()
t.Run("Required", func(t *testing.T) { t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag l1.head is required", addRequiredArgsExcept(t, "--l1.head")) verifyArgsInvalid(t, "flag l1.head is required", addRequiredArgsExcept(t, "--l1.head"))
}) })
...@@ -144,14 +141,12 @@ func TestL1Head(t *testing.T) { ...@@ -144,14 +141,12 @@ func TestL1Head(t *testing.T) {
} }
func TestL1(t *testing.T) { func TestL1(t *testing.T) {
t.Parallel()
expected := "https://example.com:8545" expected := "https://example.com:8545"
cfg := configForArgs(t, addRequiredArgs(t, "--l1", expected)) cfg := configForArgs(t, addRequiredArgs(t, "--l1", expected))
require.Equal(t, expected, cfg.L1URL) require.Equal(t, expected, cfg.L1URL)
} }
func TestL1TrustRPC(t *testing.T) { func TestL1TrustRPC(t *testing.T) {
t.Parallel()
t.Run("DefaultFalse", func(t *testing.T) { t.Run("DefaultFalse", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs(t)) cfg := configForArgs(t, addRequiredArgs(t))
require.False(t, cfg.L1TrustRPC) require.False(t, cfg.L1TrustRPC)
...@@ -171,7 +166,6 @@ func TestL1TrustRPC(t *testing.T) { ...@@ -171,7 +166,6 @@ func TestL1TrustRPC(t *testing.T) {
} }
func TestL1RPCKind(t *testing.T) { func TestL1RPCKind(t *testing.T) {
t.Parallel()
t.Run("DefaultBasic", func(t *testing.T) { t.Run("DefaultBasic", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs(t)) cfg := configForArgs(t, addRequiredArgs(t))
require.Equal(t, sources.RPCKindBasic, cfg.L1RPCKind) require.Equal(t, sources.RPCKindBasic, cfg.L1RPCKind)
...@@ -191,7 +185,6 @@ func TestL1RPCKind(t *testing.T) { ...@@ -191,7 +185,6 @@ func TestL1RPCKind(t *testing.T) {
} }
func TestL2Claim(t *testing.T) { func TestL2Claim(t *testing.T) {
t.Parallel()
t.Run("Required", func(t *testing.T) { t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag l2.claim is required", addRequiredArgsExcept(t, "--l2.claim")) verifyArgsInvalid(t, "flag l2.claim is required", addRequiredArgsExcept(t, "--l2.claim"))
}) })
...@@ -206,6 +199,21 @@ func TestL2Claim(t *testing.T) { ...@@ -206,6 +199,21 @@ func TestL2Claim(t *testing.T) {
}) })
} }
func TestL2BlockNumber(t *testing.T) {
t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag l2.blocknumber is required", addRequiredArgsExcept(t, "--l2.blocknumber"))
})
t.Run("Valid", func(t *testing.T) {
cfg := configForArgs(t, replaceRequiredArg(t, "--l2.blocknumber", strconv.FormatUint(l2ClaimBlockNumber, 10)))
require.EqualValues(t, l2ClaimBlockNumber, cfg.L2ClaimBlockNumber)
})
t.Run("Invalid", func(t *testing.T) {
verifyArgsInvalid(t, "invalid value \"something\" for flag -l2.blocknumber", replaceRequiredArg(t, "--l2.blocknumber", "something"))
})
}
func verifyArgsInvalid(t *testing.T, messageContains string, cliArgs []string) { func verifyArgsInvalid(t *testing.T, messageContains string, cliArgs []string) {
_, _, err := runWithArgs(cliArgs) _, _, err := runWithArgs(cliArgs)
require.ErrorContains(t, err, messageContains) require.ErrorContains(t, err, messageContains)
...@@ -218,7 +226,7 @@ func configForArgs(t *testing.T, cliArgs []string) *config.Config { ...@@ -218,7 +226,7 @@ func configForArgs(t *testing.T, cliArgs []string) *config.Config {
} }
func runWithArgs(cliArgs []string) (log.Logger, *config.Config, error) { func runWithArgs(cliArgs []string) (log.Logger, *config.Config, error) {
var cfg *config.Config cfg := new(config.Config)
var logger log.Logger var logger log.Logger
fullArgs := append([]string{"op-program"}, cliArgs...) fullArgs := append([]string{"op-program"}, cliArgs...)
err := run(fullArgs, func(log log.Logger, config *config.Config) error { err := run(fullArgs, func(log log.Logger, config *config.Config) error {
...@@ -256,6 +264,7 @@ func requiredArgs(t *testing.T) map[string]string { ...@@ -256,6 +264,7 @@ func requiredArgs(t *testing.T) map[string]string {
"--l1.head": l1HeadValue, "--l1.head": l1HeadValue,
"--l2.head": l2HeadValue, "--l2.head": l2HeadValue,
"--l2.claim": l2ClaimValue, "--l2.claim": l2ClaimValue,
"--l2.blocknumber": strconv.FormatUint(l2ClaimBlockNumber, 10),
"--l2.genesis": genesisFile, "--l2.genesis": genesisFile,
} }
} }
......
...@@ -23,6 +23,7 @@ var ( ...@@ -23,6 +23,7 @@ var (
ErrInvalidL2Head = errors.New("invalid l2 head") ErrInvalidL2Head = errors.New("invalid l2 head")
ErrL1AndL2Inconsistent = errors.New("l1 and l2 options must be specified together or both omitted") ErrL1AndL2Inconsistent = errors.New("l1 and l2 options must be specified together or both omitted")
ErrInvalidL2Claim = errors.New("invalid l2 claim") ErrInvalidL2Claim = errors.New("invalid l2 claim")
ErrInvalidL2ClaimBlock = errors.New("invalid l2 claim block number")
ErrDataDirRequired = errors.New("datadir must be specified when in non-fetching mode") ErrDataDirRequired = errors.New("datadir must be specified when in non-fetching mode")
) )
...@@ -43,6 +44,9 @@ type Config struct { ...@@ -43,6 +44,9 @@ type Config struct {
L2URL string L2URL string
// L2Claim is the claimed L2 output root to verify // L2Claim is the claimed L2 output root to verify
L2Claim common.Hash L2Claim common.Hash
// 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
// L2ChainConfig is the op-geth chain config for the L2 execution engine // L2ChainConfig is the op-geth chain config for the L2 execution engine
L2ChainConfig *params.ChainConfig L2ChainConfig *params.ChainConfig
} }
...@@ -63,6 +67,9 @@ func (c *Config) Check() error { ...@@ -63,6 +67,9 @@ func (c *Config) Check() error {
if c.L2Claim == (common.Hash{}) { if c.L2Claim == (common.Hash{}) {
return ErrInvalidL2Claim return ErrInvalidL2Claim
} }
if c.L2ClaimBlockNumber == 0 {
return ErrInvalidL2ClaimBlock
}
if c.L2ChainConfig == nil { if c.L2ChainConfig == nil {
return ErrMissingL2Genesis return ErrMissingL2Genesis
} }
...@@ -80,13 +87,14 @@ func (c *Config) FetchingEnabled() bool { ...@@ -80,13 +87,14 @@ func (c *Config) FetchingEnabled() bool {
} }
// NewConfig creates a Config with all optional values set to the CLI default value // NewConfig creates a Config with all optional values set to the CLI default value
func NewConfig(rollupCfg *rollup.Config, l2Genesis *params.ChainConfig, l1Head common.Hash, l2Head common.Hash, l2Claim common.Hash) *Config { func NewConfig(rollupCfg *rollup.Config, l2Genesis *params.ChainConfig, l1Head common.Hash, l2Head common.Hash, l2Claim common.Hash, l2ClaimBlockNum uint64) *Config {
return &Config{ return &Config{
Rollup: rollupCfg, Rollup: rollupCfg,
L2ChainConfig: l2Genesis, L2ChainConfig: l2Genesis,
L1Head: l1Head, L1Head: l1Head,
L2Head: l2Head, L2Head: l2Head,
L2Claim: l2Claim, L2Claim: l2Claim,
L2ClaimBlockNumber: l2ClaimBlockNum,
L1RPCKind: sources.RPCKindBasic, L1RPCKind: sources.RPCKindBasic,
} }
} }
...@@ -107,6 +115,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) { ...@@ -107,6 +115,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
if l2Claim == (common.Hash{}) { if l2Claim == (common.Hash{}) {
return nil, ErrInvalidL2Claim return nil, ErrInvalidL2Claim
} }
l2ClaimBlockNum := ctx.GlobalUint64(flags.L2BlockNumber.Name)
l1Head := common.HexToHash(ctx.GlobalString(flags.L1Head.Name)) l1Head := common.HexToHash(ctx.GlobalString(flags.L1Head.Name))
if l1Head == (common.Hash{}) { if l1Head == (common.Hash{}) {
return nil, ErrInvalidL1Head return nil, ErrInvalidL1Head
...@@ -123,6 +132,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) { ...@@ -123,6 +132,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
L2ChainConfig: l2ChainConfig, L2ChainConfig: l2ChainConfig,
L2Head: l2Head, L2Head: l2Head,
L2Claim: l2Claim, L2Claim: l2Claim,
L2ClaimBlockNumber: l2ClaimBlockNum,
L1Head: l1Head, L1Head: l1Head,
L1URL: ctx.GlobalString(flags.L1NodeAddr.Name), L1URL: ctx.GlobalString(flags.L1NodeAddr.Name),
L1TrustRPC: ctx.GlobalBool(flags.L1TrustRPC.Name), L1TrustRPC: ctx.GlobalBool(flags.L1TrustRPC.Name),
......
...@@ -10,11 +10,14 @@ import ( ...@@ -10,11 +10,14 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
var validRollupConfig = &chaincfg.Goerli var (
var validL2Genesis = params.GoerliChainConfig validRollupConfig = &chaincfg.Goerli
var validL1Head = common.Hash{0xaa} validL2Genesis = params.GoerliChainConfig
var validL2Head = common.Hash{0xbb} validL1Head = common.Hash{0xaa}
var validL2Claim = common.Hash{0xcc} validL2Head = common.Hash{0xbb}
validL2Claim = common.Hash{0xcc}
validL2ClaimBlockNum = uint64(15)
)
// TestValidConfigIsValid checks that the config provided by validConfig is actually valid // TestValidConfigIsValid checks that the config provided by validConfig is actually valid
func TestValidConfigIsValid(t *testing.T) { func TestValidConfigIsValid(t *testing.T) {
...@@ -59,6 +62,13 @@ func TestL2ClaimRequired(t *testing.T) { ...@@ -59,6 +62,13 @@ func TestL2ClaimRequired(t *testing.T) {
require.ErrorIs(t, err, ErrInvalidL2Claim) require.ErrorIs(t, err, ErrInvalidL2Claim)
} }
func TestL2ClaimBlockNumberRequired(t *testing.T) {
config := validConfig()
config.L2ClaimBlockNumber = 0
err := config.Check()
require.ErrorIs(t, err, ErrInvalidL2ClaimBlock)
}
func TestL2GenesisRequired(t *testing.T) { func TestL2GenesisRequired(t *testing.T) {
config := validConfig() config := validConfig()
config.L2ChainConfig = nil config.L2ChainConfig = nil
...@@ -133,7 +143,7 @@ func TestRequireDataDirInNonFetchingMode(t *testing.T) { ...@@ -133,7 +143,7 @@ func TestRequireDataDirInNonFetchingMode(t *testing.T) {
} }
func validConfig() *Config { func validConfig() *Config {
cfg := NewConfig(validRollupConfig, validL2Genesis, validL1Head, validL2Head, validL2Claim) cfg := NewConfig(validRollupConfig, validL2Genesis, validL1Head, validL2Head, validL2Claim, validL2ClaimBlockNum)
cfg.DataDir = "/tmp/configTest" cfg.DataDir = "/tmp/configTest"
return cfg return cfg
} }
...@@ -51,6 +51,11 @@ var ( ...@@ -51,6 +51,11 @@ var (
Usage: "Claimed L2 output root to validate", Usage: "Claimed L2 output root to validate",
EnvVar: service.PrefixEnvVar(envVarPrefix, "L2_CLAIM"), EnvVar: service.PrefixEnvVar(envVarPrefix, "L2_CLAIM"),
} }
L2BlockNumber = cli.Uint64Flag{
Name: "l2.blocknumber",
Usage: "Number of the L2 block that the claim is from",
EnvVar: service.PrefixEnvVar(envVarPrefix, "L2_BLOCK_NUM"),
}
L2GenesisPath = cli.StringFlag{ L2GenesisPath = cli.StringFlag{
Name: "l2.genesis", Name: "l2.genesis",
Usage: "Path to the op-geth genesis file", Usage: "Path to the op-geth genesis file",
...@@ -85,6 +90,7 @@ var requiredFlags = []cli.Flag{ ...@@ -85,6 +90,7 @@ var requiredFlags = []cli.Flag{
L1Head, L1Head,
L2Head, L2Head,
L2Claim, L2Claim,
L2BlockNumber,
L2GenesisPath, L2GenesisPath,
} }
var programFlags = []cli.Flag{ var programFlags = []cli.Flag{
...@@ -113,7 +119,7 @@ func CheckRequired(ctx *cli.Context) error { ...@@ -113,7 +119,7 @@ func CheckRequired(ctx *cli.Context) error {
return fmt.Errorf("cannot specify both %s and %s", RollupConfig.Name, Network.Name) return fmt.Errorf("cannot specify both %s and %s", RollupConfig.Name, Network.Name)
} }
for _, flag := range requiredFlags { for _, flag := range requiredFlags {
if ctx.GlobalString(flag.GetName()) == "" { if !ctx.IsSet(flag.GetName()) {
return fmt.Errorf("flag %s is required", flag.GetName()) return fmt.Errorf("flag %s is required", flag.GetName())
} }
} }
......
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