diff --git a/cmd/caplin/caplincli/config.go b/cmd/caplin/caplincli/config.go new file mode 100644 index 000000000..a3c167c34 --- /dev/null +++ b/cmd/caplin/caplincli/config.go @@ -0,0 +1,124 @@ +package caplincli + +import ( + "errors" + "fmt" + "os" + "strings" + "time" + + "github.com/ledgerwatch/erigon-lib/common/datadir" + "github.com/ledgerwatch/erigon/cl/clparams" + "github.com/ledgerwatch/erigon/cl/phase1/core/state" + "github.com/ledgerwatch/erigon/cmd/caplin/caplinflags" + "github.com/ledgerwatch/erigon/cmd/sentinel/sentinelcli" + "github.com/ledgerwatch/erigon/cmd/sentinel/sentinelflags" + "github.com/ledgerwatch/erigon/cmd/utils" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/log/v3" + "github.com/urfave/cli/v2" +) + +type CaplinCliCfg struct { + *sentinelcli.SentinelCliCfg + + CheckpointUri string `json:"checkpoint_uri"` + Chaindata string `json:"chaindata"` + ErigonPrivateApi string `json:"erigon_private_api"` + TransitionChain bool `json:"transition_chain"` + InitialSync bool `json:"initial_sync"` + NoBeaconApi bool `json:"no_beacon_api"` + BeaconApiReadTimeout time.Duration `json:"beacon_api_read_timeout"` + BeaconApiWriteTimeout time.Duration `json:"beacon_api_write_timeout"` + BeaconAddr string `json:"beacon_addr"` + BeaconProtocol string `json:"beacon_protocol"` + RecordMode bool `json:"record_mode"` + RecordDir string `json:"record_dir"` + DataDir string `json:"data_dir"` + RunEngineAPI bool `json:"run_engine_api"` + EngineAPIAddr string `json:"engine_api_addr"` + EngineAPIPort int `json:"engine_api_port"` + JwtSecret []byte + + InitalState *state.CachingBeaconState + Dirs datadir.Dirs +} + +func SetupCaplinCli(ctx *cli.Context) (cfg *CaplinCliCfg, err error) { + cfg = &CaplinCliCfg{} + cfg.SentinelCliCfg, err = sentinelcli.SetupSentinelCli(ctx) + if err != nil { + return nil, err + } + + cfg.ErigonPrivateApi = ctx.String(caplinflags.ErigonPrivateApiFlag.Name) + + if ctx.String(sentinelflags.BeaconConfigFlag.Name) != "" { + var stateByte []byte + // Now parse genesis time and genesis fork + if *cfg.GenesisCfg, stateByte, err = clparams.ParseGenesisSSZToGenesisConfig( + ctx.String(sentinelflags.GenesisSSZFlag.Name), + cfg.BeaconCfg.GetCurrentStateVersion(0)); err != nil { + return nil, err + } + + cfg.InitalState = state.New(cfg.BeaconCfg) + if cfg.InitalState.DecodeSSZ(stateByte, int(cfg.BeaconCfg.GetCurrentStateVersion(0))); err != nil { + return nil, err + } + } + + cfg.NoBeaconApi = ctx.Bool(caplinflags.NoBeaconApi.Name) + cfg.BeaconApiReadTimeout = time.Duration(ctx.Uint64(caplinflags.BeaconApiReadTimeout.Name)) * time.Second + cfg.BeaconApiWriteTimeout = time.Duration(ctx.Uint(caplinflags.BeaconApiWriteTimeout.Name)) * time.Second + cfg.BeaconAddr = fmt.Sprintf("%s:%d", ctx.String(caplinflags.BeaconApiAddr.Name), ctx.Int(caplinflags.BeaconApiPort.Name)) + cfg.BeaconProtocol = "tcp" + cfg.RecordMode = ctx.Bool(caplinflags.RecordModeFlag.Name) + cfg.RecordDir = ctx.String(caplinflags.RecordModeDir.Name) + cfg.DataDir = ctx.String(utils.DataDirFlag.Name) + cfg.Dirs = datadir.New(cfg.DataDir) + + cfg.RunEngineAPI = ctx.Bool(caplinflags.RunEngineAPI.Name) + cfg.EngineAPIAddr = ctx.String(caplinflags.EngineApiHostFlag.Name) + cfg.EngineAPIPort = ctx.Int(caplinflags.EngineApiPortFlag.Name) + if cfg.RunEngineAPI { + secret, err := ObtainJwtSecret(ctx) + if err != nil { + log.Error("Failed to obtain jwt secret", "err", err) + cfg.RunEngineAPI = false + } else { + cfg.JwtSecret = secret + } + } + + if ctx.String(caplinflags.CheckpointSyncUrlFlag.Name) != "" { + cfg.CheckpointUri = ctx.String(caplinflags.CheckpointSyncUrlFlag.Name) + } else { + cfg.CheckpointUri = clparams.GetCheckpointSyncEndpoint(cfg.NetworkType) + } + + cfg.Chaindata = ctx.String(caplinflags.ChaindataFlag.Name) + + cfg.TransitionChain = ctx.Bool(caplinflags.TransitionChainFlag.Name) + cfg.InitialSync = ctx.Bool(caplinflags.InitSyncFlag.Name) + + return nil, err +} + +func ObtainJwtSecret(ctx *cli.Context) ([]byte, error) { + path := ctx.String(caplinflags.JwtSecret.Name) + if len(strings.TrimSpace(path)) == 0 { + return nil, errors.New("Missing jwt secret path") + } + + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + jwtSecret := common.FromHex(strings.TrimSpace(string(data))) + if len(jwtSecret) == 32 { + return jwtSecret, nil + } + + return nil, fmt.Errorf("Invalid JWT secret at %s, invalid size", path) +} diff --git a/cmd/sentinel/cli/flags/flags.go b/cmd/caplin/caplinflags/flags.go similarity index 59% rename from cmd/sentinel/cli/flags/flags.go rename to cmd/caplin/caplinflags/flags.go index efd275f48..2d3d9361f 100644 --- a/cmd/sentinel/cli/flags/flags.go +++ b/cmd/caplin/caplinflags/flags.go @@ -1,34 +1,35 @@ -package flags +package caplinflags import ( + "github.com/ledgerwatch/erigon/cmd/utils" "github.com/urfave/cli/v2" ) +var CliFlags = []cli.Flag{ + &NoBeaconApi, + &BeaconApiReadTimeout, + &BeaconApiWriteTimeout, + &BeaconApiPort, + &BeaconApiAddr, + &ChaindataFlag, + &BeaconDBModeFlag, + &CheckpointSyncUrlFlag, + &TransitionChainFlag, + &InitSyncFlag, + &RecordModeDir, + &RecordModeFlag, + &RunEngineAPI, + &EngineApiHostFlag, + &EngineApiPortFlag, + &JwtSecret, + &utils.DataDirFlag, +} + var ( - SentinelDiscoveryPort = cli.IntFlag{ - Name: "discovery.port", - Usage: "sets the lightclient port", - Value: 4000, - } - SentinelDiscoveryAddr = cli.StringFlag{ - Name: "discovery.addr", - Usage: "sets the lightclient discovery addr", - Value: "127.0.0.1", - } - SentinelTcpPort = cli.UintFlag{ - Name: "sentinel.tcp.port", - Usage: "sets lightclient tcp port", - Value: 4001, - } - SentinelServerPort = cli.IntFlag{ - Name: "sentinel.port", - Usage: "sets the lightclient server port", - Value: 7777, - } - SentinelServerAddr = cli.StringFlag{ - Name: "sentinel.addr", - Usage: "sets the lightclient server host addr", - Value: "localhost", + ChaindataFlag = cli.StringFlag{ + Name: "chaindata", + Usage: "chaindata of database", + Value: "", } NoBeaconApi = cli.BoolFlag{ Name: "no-beacon-api", @@ -55,41 +56,7 @@ var ( Usage: "sets the port to listen for beacon api requests", Value: 5555, } - BootnodesFlag = cli.StringFlag{ - Name: "sentinel.bootnodes", - Usage: "Comma separated enode URLs for P2P discovery bootstrap", - Value: "", - } - BeaconConfigFlag = cli.StringFlag{ - Name: "beacon-config", - Usage: "Path to beacon config", - Value: "", - } - GenesisSSZFlag = cli.StringFlag{ - Name: "genesis-ssz", - Usage: "Path to genesis ssz", - Value: "", - } - Chain = cli.StringFlag{ - Name: "chain", - Usage: "sets the chain specs for the lightclient", - Value: "mainnet", - } - NoDiscovery = cli.BoolFlag{ - Name: "no-discovery", - Usage: "turn off or on the lightclient finding peers", - Value: false, - } - LocalDiscovery = cli.BoolFlag{ - Name: "local-discovery", - Usage: "enable to also attempt to find peers over private ips. turning this on may cause issues with hosts such as hetzner", - Value: false, - } - ChaindataFlag = cli.StringFlag{ - Name: "chaindata", - Usage: "chaindata of database", - Value: "", - } + BeaconDBModeFlag = cli.StringFlag{ Name: "beacon-db-mode", Usage: "level of storing on beacon chain, minimal(only 500k blocks stored), full (all blocks stored), light (no blocks stored)", @@ -100,6 +67,25 @@ var ( Usage: "checkpoint sync endpoint", Value: "", } + TransitionChainFlag = cli.BoolFlag{ + Name: "transition-chain", + Usage: "enable chain transition", + } + InitSyncFlag = cli.BoolFlag{ + Value: false, + Name: "initial-sync", + Usage: "use initial-sync", + } + RecordModeFlag = cli.BoolFlag{ + Value: false, + Name: "record-mode", + Usage: "enable/disable record mode", + } + RecordModeDir = cli.StringFlag{ + Value: "caplin-recordings", + Name: "record-dir", + Usage: "directory for states and block recordings", + } ErigonPrivateApiFlag = cli.StringFlag{ Name: "private.api.addr", Usage: "connect to existing erigon instance", @@ -125,28 +111,4 @@ var ( Usage: "Path to the token that ensures safe connection between CL and EL", Value: "", } - SentinelStaticPeersFlag = cli.StringFlag{ - Name: "sentinel.staticpeers", - Usage: "connect to comma-separated Consensus static peers", - Value: "", - } - TransitionChainFlag = cli.BoolFlag{ - Name: "transition-chain", - Usage: "enable chain transition", - } - InitSyncFlag = cli.BoolFlag{ - Value: false, - Name: "initial-sync", - Usage: "use initial-sync", - } - RecordModeFlag = cli.BoolFlag{ - Value: false, - Name: "record-mode", - Usage: "enable/disable record mode", - } - RecordModeDir = cli.StringFlag{ - Value: "caplin-recordings", - Name: "record-dir", - Usage: "directory for states and block recordings", - } ) diff --git a/cmd/caplin/main.go b/cmd/caplin/main.go index 7a6c3b6dc..744abaf87 100644 --- a/cmd/caplin/main.go +++ b/cmd/caplin/main.go @@ -1,15 +1,13 @@ -/* - Copyright 2022 Erigon-Lightclient contributors - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +// Copyright 2022 Erigon-Lightclient contributors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package main @@ -32,14 +30,16 @@ import ( "github.com/urfave/cli/v2" "github.com/ledgerwatch/erigon/cmd/caplin/caplin1" - lcCli "github.com/ledgerwatch/erigon/cmd/sentinel/cli" - "github.com/ledgerwatch/erigon/cmd/sentinel/cli/flags" + "github.com/ledgerwatch/erigon/cmd/caplin/caplincli" + "github.com/ledgerwatch/erigon/cmd/caplin/caplinflags" + "github.com/ledgerwatch/erigon/cmd/sentinel/sentinelflags" + "github.com/ledgerwatch/erigon/cmd/utils" "github.com/ledgerwatch/erigon/turbo/app" "github.com/ledgerwatch/erigon/turbo/debug" ) func main() { - app := app.MakeApp("caplin", runCaplinNode, flags.CLDefaultFlags) + app := app.MakeApp("caplin", runCaplinNode, append(caplinflags.CliFlags, sentinelflags.CliFlags...)) if err := app.Run(os.Args); err != nil { _, printErr := fmt.Fprintln(os.Stderr, err) if printErr != nil { @@ -50,10 +50,7 @@ func main() { } func runCaplinNode(cliCtx *cli.Context) error { - ctx, cn := context.WithCancel(context.Background()) - defer cn() - - cfg, err := lcCli.SetupConsensusClientCfg(cliCtx) + cfg, err := caplincli.SetupCaplinCli(cliCtx) if err != nil { log.Error("[Phase1] Could not initialize caplin", "err", err) } @@ -61,9 +58,11 @@ func runCaplinNode(cliCtx *cli.Context) error { return err } log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(cfg.LogLvl), log.StderrHandler)) - log.Info("[Phase1]", "chain", cliCtx.String(flags.Chain.Name)) + log.Info("[Phase1]", "chain", cliCtx.String(utils.ChainFlag.Name)) log.Info("[Phase1] Running Caplin") // Either start from genesis or a checkpoint + ctx, cn := context.WithCancel(context.Background()) + defer cn() var state *state.CachingBeaconState if cfg.InitialSync { state = cfg.InitalState diff --git a/cmd/erigon/main.go b/cmd/erigon/main.go index 0b97c0554..b3dd55dcd 100644 --- a/cmd/erigon/main.go +++ b/cmd/erigon/main.go @@ -1,23 +1,16 @@ package main import ( - "errors" "fmt" "net/http" "os" - "path/filepath" - "reflect" - "strings" "github.com/ledgerwatch/log/v3" - "github.com/pelletier/go-toml" "github.com/urfave/cli/v2" - "gopkg.in/yaml.v2" "github.com/ledgerwatch/erigon-lib/common/datadir" "github.com/ledgerwatch/erigon-lib/common/dbg" "github.com/ledgerwatch/erigon-lib/metrics" - "github.com/ledgerwatch/erigon/cmd/utils" "github.com/ledgerwatch/erigon/diagnostics" "github.com/ledgerwatch/erigon/params" erigonapp "github.com/ledgerwatch/erigon/turbo/app" @@ -48,14 +41,6 @@ func main() { } func runErigon(cliCtx *cli.Context) error { - configFilePath := cliCtx.String(utils.ConfigFlag.Name) - if configFilePath != "" { - if err := setFlagsFromConfigFile(cliCtx, configFilePath); err != nil { - log.Error("failed setting config flags from yaml/toml file", "err", err) - return err - } - } - var logger log.Logger var err error var metricsMux *http.ServeMux @@ -93,55 +78,3 @@ func runErigon(cliCtx *cli.Context) error { } return err } - -func setFlagsFromConfigFile(ctx *cli.Context, filePath string) error { - fileExtension := filepath.Ext(filePath) - - fileConfig := make(map[string]interface{}) - - if fileExtension == ".yaml" { - yamlFile, err := os.ReadFile(filePath) - if err != nil { - return err - } - err = yaml.Unmarshal(yamlFile, fileConfig) - if err != nil { - return err - } - } else if fileExtension == ".toml" { - tomlFile, err := os.ReadFile(filePath) - if err != nil { - return err - } - err = toml.Unmarshal(tomlFile, &fileConfig) - if err != nil { - return err - } - } else { - return errors.New("config files only accepted are .yaml and .toml") - } - // sets global flags to value in yaml/toml file - for key, value := range fileConfig { - if !ctx.IsSet(key) { - if reflect.ValueOf(value).Kind() == reflect.Slice { - sliceInterface := value.([]interface{}) - s := make([]string, len(sliceInterface)) - for i, v := range sliceInterface { - s[i] = fmt.Sprintf("%v", v) - } - err := ctx.Set(key, strings.Join(s, ",")) - if err != nil { - return fmt.Errorf("failed setting %s flag with values=%s error=%s", key, s, err) - } - } else { - err := ctx.Set(key, fmt.Sprintf("%v", value)) - if err != nil { - return fmt.Errorf("failed setting %s flag with value=%v error=%s", key, value, err) - - } - } - } - } - - return nil -} diff --git a/cmd/sentinel/cli/cliSettings.go b/cmd/sentinel/cli/cliSettings.go deleted file mode 100644 index fc0c076fb..000000000 --- a/cmd/sentinel/cli/cliSettings.go +++ /dev/null @@ -1,161 +0,0 @@ -package cli - -import ( - "errors" - "fmt" - "os" - "strings" - "time" - - "github.com/ledgerwatch/erigon/cl/clparams" - "github.com/ledgerwatch/erigon/cl/phase1/core/state" - - common2 "github.com/ledgerwatch/erigon-lib/common" - - "github.com/ledgerwatch/erigon-lib/common/datadir" - "github.com/ledgerwatch/erigon/common" - - "github.com/ledgerwatch/erigon/cmd/utils" - "github.com/urfave/cli/v2" - - "github.com/ledgerwatch/erigon/cmd/sentinel/cli/flags" - "github.com/ledgerwatch/erigon/turbo/logging" - - "github.com/ledgerwatch/log/v3" -) - -type ConsensusClientCliCfg struct { - GenesisCfg *clparams.GenesisConfig - BeaconCfg *clparams.BeaconChainConfig - NetworkCfg *clparams.NetworkConfig - Port uint `json:"port"` - Addr string `json:"address"` - ServerAddr string `json:"server_addr"` - ServerProtocol string `json:"server_protocol"` - ServerTcpPort uint `json:"server_tcp_port"` - LogLvl uint `json:"log_level"` - NoDiscovery bool `json:"no_discovery"` - LocalDiscovery bool `json:"local_discovery"` - CheckpointUri string `json:"checkpoint_uri"` - Chaindata string `json:"chaindata"` - ErigonPrivateApi string `json:"erigon_private_api"` - TransitionChain bool `json:"transition_chain"` - NetworkType clparams.NetworkType - InitialSync bool `json:"initial_sync"` - NoBeaconApi bool `json:"no_beacon_api"` - BeaconApiReadTimeout time.Duration `json:"beacon_api_read_timeout"` - BeaconApiWriteTimeout time.Duration `json:"beacon_api_write_timeout"` - BeaconAddr string `json:"beacon_addr"` - BeaconProtocol string `json:"beacon_protocol"` - RecordMode bool `json:"record_mode"` - RecordDir string `json:"record_dir"` - DataDir string `json:"data_dir"` - RunEngineAPI bool `json:"run_engine_api"` - EngineAPIAddr string `json:"engine_api_addr"` - EngineAPIPort int `json:"engine_api_port"` - JwtSecret []byte - - InitalState *state.CachingBeaconState - Dirs datadir.Dirs -} - -func SetupConsensusClientCfg(ctx *cli.Context) (*ConsensusClientCliCfg, error) { - cfg := &ConsensusClientCliCfg{} - chainName := ctx.String(flags.Chain.Name) - var err error - cfg.GenesisCfg, cfg.NetworkCfg, cfg.BeaconCfg, cfg.NetworkType, err = clparams.GetConfigsByNetworkName(chainName) - if err != nil { - return nil, err - } - cfg.ErigonPrivateApi = ctx.String(flags.ErigonPrivateApiFlag.Name) - if ctx.String(flags.BeaconConfigFlag.Name) != "" { - cfg.BeaconCfg = new(clparams.BeaconChainConfig) - if *cfg.BeaconCfg, err = clparams.CustomConfig(ctx.String(flags.BeaconConfigFlag.Name)); err != nil { - return nil, err - } - if ctx.String(flags.GenesisSSZFlag.Name) == "" { - return nil, fmt.Errorf("no genesis file provided") - } - cfg.GenesisCfg = new(clparams.GenesisConfig) - var stateByte []byte - // Now parse genesis time and genesis fork - if *cfg.GenesisCfg, stateByte, err = clparams.ParseGenesisSSZToGenesisConfig( - ctx.String(flags.GenesisSSZFlag.Name), - cfg.BeaconCfg.GetCurrentStateVersion(0)); err != nil { - return nil, err - } - cfg.InitalState = state.New(cfg.BeaconCfg) - if cfg.InitalState.DecodeSSZ(stateByte, int(cfg.BeaconCfg.GetCurrentStateVersion(0))); err != nil { - return nil, err - } - } - cfg.ServerAddr = fmt.Sprintf("%s:%d", ctx.String(flags.SentinelServerAddr.Name), ctx.Int(flags.SentinelServerPort.Name)) - cfg.ServerProtocol = "tcp" - - cfg.NoBeaconApi = ctx.Bool(flags.NoBeaconApi.Name) - cfg.BeaconApiReadTimeout = time.Duration(ctx.Uint64(flags.BeaconApiReadTimeout.Name)) * time.Second - cfg.BeaconApiWriteTimeout = time.Duration(ctx.Uint(flags.BeaconApiWriteTimeout.Name)) * time.Second - cfg.BeaconAddr = fmt.Sprintf("%s:%d", ctx.String(flags.BeaconApiAddr.Name), ctx.Int(flags.BeaconApiPort.Name)) - cfg.BeaconProtocol = "tcp" - cfg.RecordMode = ctx.Bool(flags.RecordModeFlag.Name) - cfg.RecordDir = ctx.String(flags.RecordModeDir.Name) - cfg.DataDir = ctx.String(utils.DataDirFlag.Name) - cfg.Dirs = datadir.New(cfg.DataDir) - - cfg.RunEngineAPI = ctx.Bool(flags.RunEngineAPI.Name) - cfg.EngineAPIAddr = ctx.String(flags.EngineApiHostFlag.Name) - cfg.EngineAPIPort = ctx.Int(flags.EngineApiPortFlag.Name) - if cfg.RunEngineAPI { - secret, err := ObtainJwtSecret(ctx) - if err != nil { - log.Error("Failed to obtain jwt secret", "err", err) - cfg.RunEngineAPI = false - } else { - cfg.JwtSecret = secret - } - } - - cfg.Port = uint(ctx.Int(flags.SentinelDiscoveryPort.Name)) - cfg.Addr = ctx.String(flags.SentinelDiscoveryAddr.Name) - - cfg.LogLvl = ctx.Uint(logging.LogVerbosityFlag.Name) - if cfg.LogLvl == uint(log.LvlInfo) || cfg.LogLvl == 0 { - cfg.LogLvl = uint(log.LvlDebug) - } - cfg.NoDiscovery = ctx.Bool(flags.NoDiscovery.Name) - cfg.LocalDiscovery = ctx.Bool(flags.LocalDiscovery.Name) - if ctx.String(flags.CheckpointSyncUrlFlag.Name) != "" { - cfg.CheckpointUri = ctx.String(flags.CheckpointSyncUrlFlag.Name) - } else { - cfg.CheckpointUri = clparams.GetCheckpointSyncEndpoint(cfg.NetworkType) - } - cfg.Chaindata = ctx.String(flags.ChaindataFlag.Name) - // Process bootnodes - if ctx.String(flags.BootnodesFlag.Name) != "" { - cfg.NetworkCfg.BootNodes = common2.CliString2Array(ctx.String(flags.BootnodesFlag.Name)) - } - if ctx.String(flags.SentinelStaticPeersFlag.Name) != "" { - cfg.NetworkCfg.StaticPeers = common2.CliString2Array(ctx.String(flags.SentinelStaticPeersFlag.Name)) - } - cfg.TransitionChain = ctx.Bool(flags.TransitionChainFlag.Name) - cfg.InitialSync = ctx.Bool(flags.InitSyncFlag.Name) - return cfg, nil -} - -func ObtainJwtSecret(ctx *cli.Context) ([]byte, error) { - path := ctx.String(flags.JwtSecret.Name) - if len(strings.TrimSpace(path)) == 0 { - return nil, errors.New("Missing jwt secret path") - } - - data, err := os.ReadFile(path) - if err != nil { - return nil, err - } - jwtSecret := common.FromHex(strings.TrimSpace(string(data))) - if len(jwtSecret) == 32 { - return jwtSecret, nil - } - - return nil, fmt.Errorf("Invalid JWT secret at %s, invalid size", path) -} diff --git a/cmd/sentinel/cli/flags/defaultFlags.go b/cmd/sentinel/cli/flags/defaultFlags.go deleted file mode 100644 index a3b2560cd..000000000 --- a/cmd/sentinel/cli/flags/defaultFlags.go +++ /dev/null @@ -1,37 +0,0 @@ -package flags - -import ( - "github.com/ledgerwatch/erigon/cmd/utils" - "github.com/urfave/cli/v2" -) - -var CLDefaultFlags = []cli.Flag{ - &SentinelDiscoveryPort, - &SentinelDiscoveryAddr, - &SentinelServerPort, - &SentinelServerAddr, - &NoBeaconApi, - &BeaconApiReadTimeout, - &BeaconApiWriteTimeout, - &BeaconApiPort, - &BeaconApiAddr, - &Chain, - &SentinelTcpPort, - &NoDiscovery, - &ChaindataFlag, - &BeaconDBModeFlag, - &BootnodesFlag, - &BeaconConfigFlag, - &GenesisSSZFlag, - &CheckpointSyncUrlFlag, - &SentinelStaticPeersFlag, - &TransitionChainFlag, - &InitSyncFlag, - &RecordModeDir, - &RecordModeFlag, - &RunEngineAPI, - &EngineApiHostFlag, - &EngineApiPortFlag, - &JwtSecret, - &utils.DataDirFlag, -} diff --git a/cmd/sentinel/main.go b/cmd/sentinel/main.go index 474819176..3208d9c3e 100644 --- a/cmd/sentinel/main.go +++ b/cmd/sentinel/main.go @@ -1,35 +1,34 @@ -/* - Copyright 2022 Erigon-Lightclient contributors - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +// Copyright 2022 Erigon-Lightclient contributors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package main import ( "context" "fmt" + "os" + "github.com/ledgerwatch/erigon/cl/sentinel" "github.com/ledgerwatch/erigon/cl/sentinel/service" - "os" + "github.com/ledgerwatch/erigon/cmd/sentinel/sentinelcli" + "github.com/ledgerwatch/erigon/cmd/sentinel/sentinelflags" "github.com/ledgerwatch/log/v3" "github.com/urfave/cli/v2" - lcCli "github.com/ledgerwatch/erigon/cmd/sentinel/cli" - "github.com/ledgerwatch/erigon/cmd/sentinel/cli/flags" sentinelapp "github.com/ledgerwatch/erigon/turbo/app" ) func main() { - app := sentinelapp.MakeApp("sentinel", runSentinelNode, flags.CLDefaultFlags) + app := sentinelapp.MakeApp("sentinel", runSentinelNode, sentinelflags.CliFlags) if err := app.Run(os.Args); err != nil { _, printErr := fmt.Fprintln(os.Stderr, err) if printErr != nil { @@ -40,11 +39,13 @@ func main() { } func runSentinelNode(cliCtx *cli.Context) error { - cfg, _ := lcCli.SetupConsensusClientCfg(cliCtx) - + cfg, err := sentinelcli.SetupSentinelCli(cliCtx) + if err != nil { + return err + } log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(cfg.LogLvl), log.StderrHandler)) log.Info("[Sentinel] running sentinel with configuration", "cfg", cfg) - _, err := service.StartSentinelService(&sentinel.SentinelConfig{ + _, err = service.StartSentinelService(&sentinel.SentinelConfig{ IpAddr: cfg.Addr, Port: int(cfg.Port), TCPPort: cfg.ServerTcpPort, diff --git a/cmd/sentinel/sentinelcli/cliSettings.go b/cmd/sentinel/sentinelcli/cliSettings.go new file mode 100644 index 000000000..ce2e04909 --- /dev/null +++ b/cmd/sentinel/sentinelcli/cliSettings.go @@ -0,0 +1,74 @@ +package sentinelcli + +import ( + "fmt" + + "github.com/ledgerwatch/erigon/cl/clparams" + "github.com/ledgerwatch/erigon/cmd/sentinel/sentinelflags" + "github.com/ledgerwatch/erigon/cmd/utils" + + "github.com/ledgerwatch/erigon-lib/common" + + "github.com/urfave/cli/v2" + + "github.com/ledgerwatch/erigon/turbo/logging" + + "github.com/ledgerwatch/log/v3" +) + +type SentinelCliCfg struct { + GenesisCfg *clparams.GenesisConfig + BeaconCfg *clparams.BeaconChainConfig + NetworkCfg *clparams.NetworkConfig + NetworkType clparams.NetworkType + Port uint `json:"port"` + Addr string `json:"address"` + ServerAddr string `json:"server_addr"` + ServerProtocol string `json:"server_protocol"` + ServerTcpPort uint `json:"server_tcp_port"` + LogLvl uint `json:"log_level"` + NoDiscovery bool `json:"no_discovery"` + LocalDiscovery bool `json:"local_discovery"` +} + +func SetupSentinelCli(ctx *cli.Context) (*SentinelCliCfg, error) { + cfg := &SentinelCliCfg{} + chainName := ctx.String(utils.ChainFlag.Name) + var err error + cfg.GenesisCfg, cfg.NetworkCfg, cfg.BeaconCfg, cfg.NetworkType, err = clparams.GetConfigsByNetworkName(chainName) + if err != nil { + return nil, err + } + if ctx.String(sentinelflags.BeaconConfigFlag.Name) != "" { + cfg.BeaconCfg = new(clparams.BeaconChainConfig) + if *cfg.BeaconCfg, err = clparams.CustomConfig(ctx.String(sentinelflags.BeaconConfigFlag.Name)); err != nil { + return nil, err + } + if ctx.String(sentinelflags.GenesisSSZFlag.Name) == "" { + return nil, fmt.Errorf("no genesis file provided") + } + cfg.GenesisCfg = new(clparams.GenesisConfig) + + } + cfg.ServerAddr = fmt.Sprintf("%s:%d", ctx.String(sentinelflags.SentinelServerAddr.Name), ctx.Int(sentinelflags.SentinelServerPort.Name)) + cfg.ServerProtocol = "tcp" + + cfg.Port = uint(ctx.Int(sentinelflags.SentinelDiscoveryPort.Name)) + cfg.Addr = ctx.String(sentinelflags.SentinelDiscoveryAddr.Name) + + cfg.LogLvl = ctx.Uint(logging.LogVerbosityFlag.Name) + if cfg.LogLvl == uint(log.LvlInfo) || cfg.LogLvl == 0 { + cfg.LogLvl = uint(log.LvlDebug) + } + cfg.NoDiscovery = ctx.Bool(sentinelflags.NoDiscovery.Name) + cfg.LocalDiscovery = ctx.Bool(sentinelflags.LocalDiscovery.Name) + + // Process bootnodes + if ctx.String(sentinelflags.BootnodesFlag.Name) != "" { + cfg.NetworkCfg.BootNodes = common.CliString2Array(ctx.String(sentinelflags.BootnodesFlag.Name)) + } + if ctx.String(sentinelflags.SentinelStaticPeersFlag.Name) != "" { + cfg.NetworkCfg.StaticPeers = common.CliString2Array(ctx.String(sentinelflags.SentinelStaticPeersFlag.Name)) + } + return cfg, nil +} diff --git a/cmd/sentinel/sentinelcli/flags/defaultFlags.go b/cmd/sentinel/sentinelcli/flags/defaultFlags.go new file mode 100644 index 000000000..0cfcbd53f --- /dev/null +++ b/cmd/sentinel/sentinelcli/flags/defaultFlags.go @@ -0,0 +1 @@ +package flags diff --git a/cmd/sentinel/sentinelcli/flags/flags.go b/cmd/sentinel/sentinelcli/flags/flags.go new file mode 100644 index 000000000..0cfcbd53f --- /dev/null +++ b/cmd/sentinel/sentinelcli/flags/flags.go @@ -0,0 +1 @@ +package flags diff --git a/cmd/sentinel/sentinelflags/flags.go b/cmd/sentinel/sentinelflags/flags.go new file mode 100644 index 000000000..4a59050d2 --- /dev/null +++ b/cmd/sentinel/sentinelflags/flags.go @@ -0,0 +1,79 @@ +package sentinelflags + +import ( + "github.com/ledgerwatch/erigon/cmd/utils" + "github.com/urfave/cli/v2" +) + +var CliFlags = []cli.Flag{ + &utils.ChainFlag, + + &SentinelDiscoveryPort, + &SentinelDiscoveryAddr, + &SentinelServerPort, + &SentinelServerAddr, + &SentinelTcpPort, + &NoDiscovery, + &BootnodesFlag, + &BeaconConfigFlag, + &GenesisSSZFlag, + &SentinelStaticPeersFlag, +} + +var ( + SentinelDiscoveryPort = cli.IntFlag{ + Name: "discovery.port", + Usage: "sets the lightclient port", + Value: 4000, + } + SentinelDiscoveryAddr = cli.StringFlag{ + Name: "discovery.addr", + Usage: "sets the lightclient discovery addr", + Value: "127.0.0.1", + } + SentinelTcpPort = cli.UintFlag{ + Name: "sentinel.tcp.port", + Usage: "sets lightclient tcp port", + Value: 4001, + } + SentinelServerPort = cli.IntFlag{ + Name: "sentinel.port", + Usage: "sets the lightclient server port", + Value: 7777, + } + SentinelServerAddr = cli.StringFlag{ + Name: "sentinel.addr", + Usage: "sets the lightclient server host addr", + Value: "localhost", + } + NoDiscovery = cli.BoolFlag{ + Name: "no-discovery", + Usage: "turn off or on the lightclient finding peers", + Value: false, + } + LocalDiscovery = cli.BoolFlag{ + Name: "local-discovery", + Usage: "enable to also attempt to find peers over private ips. turning this on may cause issues with hosts such as hetzner", + Value: false, + } + BootnodesFlag = cli.StringFlag{ + Name: "sentinel.bootnodes", + Usage: "Comma separated enode URLs for P2P discovery bootstrap", + Value: "", + } + BeaconConfigFlag = cli.StringFlag{ + Name: "beacon-config", + Usage: "Path to beacon config", + Value: "", + } + GenesisSSZFlag = cli.StringFlag{ + Name: "genesis-ssz", + Usage: "Path to genesis ssz", + Value: "", + } + SentinelStaticPeersFlag = cli.StringFlag{ + Name: "sentinel.staticpeers", + Usage: "connect to comma-separated Consensus static peers", + Value: "", + } +) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 29862b36c..55759bb82 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -97,7 +97,7 @@ var ( } ChainFlag = cli.StringFlag{ Name: "chain", - Usage: "Name of the testnet to join", + Usage: "name of the network to join", Value: networkname.MainnetChainName, } IdentityFlag = cli.StringFlag{ diff --git a/turbo/app/make_app.go b/turbo/app/make_app.go index 24267f568..a591af542 100644 --- a/turbo/app/make_app.go +++ b/turbo/app/make_app.go @@ -39,12 +39,35 @@ func MakeApp(name string, action cli.ActionFunc, cliFlags []cli.Flag) *cli.App { cli.ShowAppHelpAndExit(context, 1) } + // handle case: config flag + configFilePath := context.String(utils.ConfigFlag.Name) + if configFilePath != "" { + if err := cli2.SetFlagsFromConfigFile(context, configFilePath); err != nil { + log.Error("failed setting config flags from yaml/toml file", "err", err) + return err + } + } + // run default action return action(context) } app.Flags = append(cliFlags, debug.Flags...) // debug flags are required app.Flags = append(app.Flags, utils.MetricFlags...) app.Flags = append(app.Flags, logging.Flags...) + app.Flags = append(app.Flags, &utils.ConfigFlag) + + // remove exact duplicate flags, keeping only the first one. this will allow easier composition later down the line + allFlags := app.Flags + newFlags := make([]cli.Flag, 0, len(allFlags)) + seen := map[string]struct{}{} + for _, vv := range allFlags { + v := vv + if _, ok := seen[v.String()]; ok { + continue + } + newFlags = append(newFlags, v) + } + app.Flags = newFlags app.After = func(ctx *cli.Context) error { debug.Exit() diff --git a/turbo/cli/config_file.go b/turbo/cli/config_file.go new file mode 100644 index 000000000..c0fca94bd --- /dev/null +++ b/turbo/cli/config_file.go @@ -0,0 +1,66 @@ +package cli + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "reflect" + "strings" + + "github.com/pelletier/go-toml" + "github.com/urfave/cli/v2" + "gopkg.in/yaml.v2" +) + +func SetFlagsFromConfigFile(ctx *cli.Context, filePath string) error { + fileExtension := filepath.Ext(filePath) + + fileConfig := make(map[string]interface{}) + + if fileExtension == ".yml" || fileExtension == ".yaml" { + yamlFile, err := os.ReadFile(filePath) + if err != nil { + return err + } + err = yaml.Unmarshal(yamlFile, fileConfig) + if err != nil { + return err + } + } else if fileExtension == ".toml" { + tomlFile, err := os.ReadFile(filePath) + if err != nil { + return err + } + err = toml.Unmarshal(tomlFile, &fileConfig) + if err != nil { + return err + } + } else { + return errors.New("config files only accepted are .yaml and .toml") + } + // sets global flags to value in yaml/toml file + for key, value := range fileConfig { + if !ctx.IsSet(key) { + if reflect.ValueOf(value).Kind() == reflect.Slice { + sliceInterface := value.([]interface{}) + s := make([]string, len(sliceInterface)) + for i, v := range sliceInterface { + s[i] = fmt.Sprintf("%v", v) + } + err := ctx.Set(key, strings.Join(s, ",")) + if err != nil { + return fmt.Errorf("failed setting %s flag with values=%s error=%s", key, s, err) + } + } else { + err := ctx.Set(key, fmt.Sprintf("%v", value)) + if err != nil { + return fmt.Errorf("failed setting %s flag with value=%v error=%s", key, value, err) + + } + } + } + } + + return nil +} diff --git a/turbo/cli/default_flags.go b/turbo/cli/default_flags.go index 83d503c19..c42d1bc95 100644 --- a/turbo/cli/default_flags.go +++ b/turbo/cli/default_flags.go @@ -155,8 +155,6 @@ var DefaultFlags = []cli.Flag{ &utils.EthStatsURLFlag, &utils.OverrideCancunFlag, - &utils.ConfigFlag, - &utils.LightClientDiscoveryAddrFlag, &utils.LightClientDiscoveryPortFlag, &utils.LightClientDiscoveryTCPPortFlag,