From 5a18c48c4030fff033e308a76012829296dac48b Mon Sep 17 00:00:00 2001 From: Milos Zivkovic Date: Thu, 12 Oct 2023 12:16:52 +0200 Subject: [PATCH] Add support for custom config file path --- gno.land/cmd/gnoland/start.go | 41 +++++++++++++++++++----- tm2/pkg/bft/config/config.go | 30 +++++++++++------- tm2/pkg/bft/config/toml.go | 23 ++++++++------ tm2/pkg/bft/config/toml_test.go | 56 +++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 29 deletions(-) diff --git a/gno.land/cmd/gnoland/start.go b/gno.land/cmd/gnoland/start.go index b2134d86ea9..6882a17917d 100644 --- a/gno.land/cmd/gnoland/start.go +++ b/gno.land/cmd/gnoland/start.go @@ -35,6 +35,7 @@ type startCfg struct { rootDir string genesisMaxVMCycles int64 config string + nodeConfigPath string } func newStartCmd(io *commands.IO) *commands.Command { @@ -47,8 +48,8 @@ func newStartCmd(io *commands.IO) *commands.Command { ShortHelp: "Run the full node", }, cfg, - func(_ context.Context, args []string) error { - return execStart(cfg, args, io) + func(_ context.Context, _ []string) error { + return execStart(cfg, io) }, ) } @@ -114,18 +115,42 @@ func (c *startCfg) RegisterFlags(fs *flag.FlagSet) { &c.config, "config", "", - "config file (optional)", + "the flag config file (optional)", + ) + + fs.StringVar( + &c.nodeConfigPath, + "node-config", + "", + "the node TOML config file path (optional)", ) } -func execStart(c *startCfg, args []string, io *commands.IO) error { +func execStart(c *startCfg, io *commands.IO) error { logger := log.NewTMLogger(log.NewSyncWriter(io.Out)) rootDir := c.rootDir - cfg := config.LoadOrMakeConfigWithOptions(rootDir, func(cfg *config.Config) { - cfg.Consensus.CreateEmptyBlocks = true - cfg.Consensus.CreateEmptyBlocksInterval = 0 * time.Second - }) + var ( + cfg *config.Config + loadCfgErr error + ) + + // Set the node configuration + if c.nodeConfigPath != "" { + // Load the node configuration + // from the specified path + cfg, loadCfgErr = config.LoadConfigFile(c.nodeConfigPath) + } else { + // Load the node configuration + cfg, loadCfgErr = config.LoadOrMakeConfigWithOptions(rootDir, func(cfg *config.Config) { + cfg.Consensus.CreateEmptyBlocks = true + cfg.Consensus.CreateEmptyBlocksInterval = 0 * time.Second + }) + } + + if loadCfgErr != nil { + return fmt.Errorf("unable to load node configuration, %w", loadCfgErr) + } // create priv validator first. // need it to generate genesis.json diff --git a/tm2/pkg/bft/config/config.go b/tm2/pkg/bft/config/config.go index 6f148c3b5c1..90633f60ce9 100644 --- a/tm2/pkg/bft/config/config.go +++ b/tm2/pkg/bft/config/config.go @@ -37,19 +37,22 @@ func DefaultConfig() *Config { } } -// Like LoadOrMakeConfigWithOptions() but without overriding any defaults. -func LoadOrMakeDefaultConfig(root string) (cfg *Config) { - return LoadOrMakeConfigWithOptions(root, nil) -} - type ConfigOptions func(cfg *Config) -// LoadOrMakeConfigWithOptions() loads configuration or saves one +// LoadOrMakeConfigWithOptions loads configuration or saves one // made by modifying the default config with override options -func LoadOrMakeConfigWithOptions(root string, options ConfigOptions) (cfg *Config) { +func LoadOrMakeConfigWithOptions(root string, options ConfigOptions) (*Config, error) { + var cfg *Config + configPath := join(root, defaultConfigFilePath) if osm.FileExists(configPath) { - cfg = LoadConfigFile(configPath) + var loadErr error + + // Load the configuration + if cfg, loadErr = LoadConfigFile(configPath); loadErr != nil { + return nil, loadErr + } + cfg.SetRootDir(root) cfg.EnsureDirs() } else { @@ -59,10 +62,13 @@ func LoadOrMakeConfigWithOptions(root string, options ConfigOptions) (cfg *Confi cfg.EnsureDirs() WriteConfigFile(configPath, cfg) } - if err := cfg.ValidateBasic(); err != nil { - panic(err) + + // Validate the configuration + if validateErr := cfg.ValidateBasic(); validateErr != nil { + return nil, fmt.Errorf("unable to validate config, %w", validateErr) } - return cfg + + return cfg, nil } // TestConfig returns a configuration that can be used for testing @@ -121,7 +127,7 @@ func (cfg *Config) ValidateBasic() error { return nil } -//----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // BaseConfig const ( diff --git a/tm2/pkg/bft/config/toml.go b/tm2/pkg/bft/config/toml.go index a35e5674631..0f60c041a6a 100644 --- a/tm2/pkg/bft/config/toml.go +++ b/tm2/pkg/bft/config/toml.go @@ -24,17 +24,22 @@ func init() { } } -func LoadConfigFile(configFilePath string) *Config { - bz, err := os.ReadFile(configFilePath) - if err != nil { - panic(err) +// LoadConfigFile loads the TOML node configuration from the specified path +func LoadConfigFile(path string) (*Config, error) { + // Read the config file + content, readErr := os.ReadFile(path) + if readErr != nil { + return nil, readErr } - var config Config - err = toml.Unmarshal(bz, &config) - if err != nil { - panic(err) + + // Parse the node config + var nodeConfig Config + + if unmarshalErr := toml.Unmarshal(content, &nodeConfig); unmarshalErr != nil { + return nil, unmarshalErr } - return &config + + return &nodeConfig, nil } /****** these are for production settings ***********/ diff --git a/tm2/pkg/bft/config/toml_test.go b/tm2/pkg/bft/config/toml_test.go index 0fe78285997..a8a06acbf9f 100644 --- a/tm2/pkg/bft/config/toml_test.go +++ b/tm2/pkg/bft/config/toml_test.go @@ -5,6 +5,8 @@ import ( "strings" "testing" + "github.com/gnolang/gno/tm2/pkg/testutils" + "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -95,3 +97,57 @@ func checkConfig(configFile string) bool { } return valid } + +func TestTOML_LoadConfig(t *testing.T) { + t.Parallel() + + t.Run("config does not exist", func(t *testing.T) { + t.Parallel() + + cfg, loadErr := LoadConfigFile("dummy-path") + + assert.Error(t, loadErr) + assert.Nil(t, cfg) + }) + + t.Run("config is not valid toml", func(t *testing.T) { + t.Parallel() + + // Create config file + configFile, cleanup := testutils.NewTestFile(t) + t.Cleanup(cleanup) + + // Write invalid TOML + _, writeErr := configFile.WriteString("invalid TOML") + require.NoError(t, writeErr) + + cfg, loadErr := LoadConfigFile(configFile.Name()) + + assert.Error(t, loadErr) + assert.Nil(t, cfg) + }) + + t.Run("valid config", func(t *testing.T) { + t.Parallel() + + // Create config file + configFile, cleanup := testutils.NewTestFile(t) + t.Cleanup(cleanup) + + // Create the default config + defaultConfig := DefaultConfig() + + // Marshal the default config + defaultConfigRaw, marshalErr := toml.Marshal(defaultConfig) + require.NoError(t, marshalErr) + + // Write valid TOML + _, writeErr := configFile.Write(defaultConfigRaw) + require.NoError(t, writeErr) + + cfg, loadErr := LoadConfigFile(configFile.Name()) + + require.NoError(t, loadErr) + assert.Equal(t, defaultConfig, cfg) + }) +}