From 3108183ba6ac178d59ee4cc1c7f9ecc346381c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Wed, 21 Apr 2021 17:01:10 -0400 Subject: [PATCH 01/11] chore: Persist node name --- cmd/gossamer/config.go | 10 ----- cmd/gossamer/utils.go | 4 +- dot/node.go | 10 ++++- dot/state/db.go | 15 ++++++++ dot/state/service.go | 85 ++++++++++++++++++++++++++++++++++++++++++ lib/common/db_keys.go | 2 + 6 files changed, 113 insertions(+), 13 deletions(-) diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index 0b47ff5721..670875196e 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -17,7 +17,6 @@ package main import ( - "encoding/binary" "fmt" "strconv" "strings" @@ -33,7 +32,6 @@ import ( "github.com/ChainSafe/gossamer/lib/runtime/life" "github.com/ChainSafe/gossamer/lib/runtime/wasmer" "github.com/ChainSafe/gossamer/lib/runtime/wasmtime" - "github.com/cosmos/go-bip39" log "github.com/ChainSafe/log15" "github.com/urfave/cli" @@ -407,17 +405,9 @@ func setDotGlobalConfig(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.Global cfg.MetricsPort = tomlCfg.Global.MetricsPort } - // TODO: generate random name if one is not assigned (see issue #1496) // check --name flag and update node configuration if name := ctx.GlobalString(NameFlag.Name); name != "" { cfg.Name = name - } else { - // generate random name - entropy, _ := bip39.NewEntropy(128) - randomNamesString, _ := bip39.NewMnemonic(entropy) - randomNames := strings.Split(randomNamesString, " ") - number := binary.BigEndian.Uint16(entropy) - cfg.Name = randomNames[0] + "-" + randomNames[1] + "-" + fmt.Sprint(number) } // check --basepath flag and update node configuration diff --git a/cmd/gossamer/utils.go b/cmd/gossamer/utils.go index dad18746f5..8bb3e253f6 100644 --- a/cmd/gossamer/utils.go +++ b/cmd/gossamer/utils.go @@ -35,6 +35,8 @@ import ( "golang.org/x/crypto/ssh/terminal" //nolint ) +const confirmCharacter = "Y" + // setupLogger sets up the gossamer logger func setupLogger(ctx *cli.Context) (log.Lvl, error) { handler := log.StreamHandler(os.Stdout, log.TerminalFormat()) @@ -76,7 +78,7 @@ func confirmMessage(msg string) bool { for { text, _ := reader.ReadString('\n') text = strings.ReplaceAll(text, "\n", "") - return strings.Compare("Y", text) == 0 + return strings.Compare(confirmCharacter, strings.ToUpper(text)) == 0 } } diff --git a/dot/node.go b/dot/node.go index cc11ef1330..7f31a72384 100644 --- a/dot/node.go +++ b/dot/node.go @@ -58,7 +58,6 @@ func InitNode(cfg *Config) error { setupLogger(cfg) logger.Info( "🕸️ initializing node...", - "name", cfg.Global.Name, "id", cfg.Global.ID, "basepath", cfg.Global.BasePath, "genesis", cfg.Init.Genesis, @@ -100,12 +99,19 @@ func InitNode(cfg *Config) error { // initialize state service with genesis data, block, and trie err = stateSrvc.Initialize(gen, header, t) + + if cfg.Global.Name != "" { + if cfg.Global.Name, err = stateSrvc.NodeGlobalName(); err != nil { + return err + } + } + if err != nil { return fmt.Errorf("failed to initialize state service: %s", err) } logger.Info( - "node initialized", + "🕸️ node initialized", "name", cfg.Global.Name, "id", cfg.Global.ID, "basepath", cfg.Global.BasePath, diff --git a/dot/state/db.go b/dot/state/db.go index 8b88c64deb..0f5d609dcf 100644 --- a/dot/state/db.go +++ b/dot/state/db.go @@ -27,6 +27,21 @@ import ( database "github.com/ChainSafe/chaindb" ) +// StoreNodeGlobalName stores the current node name to avoid create new ones after each initialization +func StoreNodeGlobalName(db database.Database, nodeName string) error { + return db.Put(common.NodeNameKey, []byte(nodeName)) +} + +// LoadNodeGlobalName loads the latest stored node global name +func LoadNodeGlobalName(db database.Database) (string, error) { + nodeName, err := db.Get(common.NodeNameKey) + if err != nil { + return "", err + } + + return string(nodeName), nil +} + // StoreBestBlockHash stores the hash at the BestBlockHashKey func StoreBestBlockHash(db database.Database, hash common.Hash) error { return db.Put(common.BestBlockHashKey, hash[:]) diff --git a/dot/state/service.go b/dot/state/service.go index 6fb9ebdc2c..5b110f76c4 100644 --- a/dot/state/service.go +++ b/dot/state/service.go @@ -18,10 +18,13 @@ package state import ( "bytes" + "encoding/binary" + "errors" "fmt" "math/big" "os" "path/filepath" + "strings" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/blocktree" @@ -29,6 +32,7 @@ import ( rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage" "github.com/ChainSafe/gossamer/lib/runtime/wasmer" "github.com/ChainSafe/gossamer/lib/trie" + "github.com/cosmos/go-bip39" "github.com/ChainSafe/chaindb" log "github.com/ChainSafe/log15" @@ -82,6 +86,53 @@ func (s *Service) DB() chaindb.Database { return s.db } +func (s *Service) NodeGlobalName() (string, error) { + logger.Info("getting node global name") + + // Load database configs + var db chaindb.Database + cfg := &chaindb.Config{} + + // check database type + if s.isMemDB { + cfg.InMemory = true + } + + // get data directory from service + basepath, err := filepath.Abs(s.dbPath) + if err != nil { + return "", fmt.Errorf("failed to read basepath: %s", err) + } + + cfg.DataDir = basepath + + // initialize database using data directory + db, err = chaindb.NewBadgerDB(cfg) + if err != nil { + return "", err + } + + var name string + if name, err = s.loadNodeName(db); err != nil { + + return "", err + } + + if name == "" { + name = generateRandomNodeName() + + if err = s.storeNodeName(db, name); err != nil { + return "", err + } + } + + if err = db.Close(); err != nil { + return "", fmt.Errorf("failed to close database: %s", err) + } + + return name, nil +} + // Initialize initializes the genesis state of the DB using the given storage trie. The trie should be loaded with the genesis storage state. // This only needs to be called during genesis initialization of the node; it doesn't need to be called during normal startup. func (s *Service) Initialize(gen *genesis.Genesis, header *types.Header, t *trie.Trie) error { @@ -496,3 +547,37 @@ func (s *Service) Import(header *types.Header, t *trie.Trie, firstSlot uint64) e return s.db.Close() } + +// storeNodeName persist the global node name on initialization +func (s *Service) storeNodeName(db chaindb.Database, name string) error { + if err := StoreNodeGlobalName(db, name); err != nil { + return fmt.Errorf("failed to write node global name to database: %w", err) + } + + return nil +} + +// loadNodeName will retrieve the node name on reinitialization +func (s *Service) loadNodeName(db chaindb.Database) (string, error) { + var err error + var nodeName string + + if nodeName, err = LoadNodeGlobalName(db); err != nil { + if errors.Is(err, chaindb.ErrKeyNotFound) { + return "", nil + } + + return "", fmt.Errorf("failed to retrieve node global name from database: %w", err) + } + + return nodeName, nil +} + +func generateRandomNodeName() string { + // generate random name + entropy, _ := bip39.NewEntropy(128) + randomNamesString, _ := bip39.NewMnemonic(entropy) + randomNames := strings.Split(randomNamesString, " ") + number := binary.BigEndian.Uint16(entropy) + return randomNames[0] + "-" + randomNames[1] + "-" + fmt.Sprint(number) +} diff --git a/lib/common/db_keys.go b/lib/common/db_keys.go index 05e431c09d..0b64c848e9 100644 --- a/lib/common/db_keys.go +++ b/lib/common/db_keys.go @@ -31,4 +31,6 @@ var ( LatestFinalizedRoundKey = []byte("latest_finalized_round") // WorkingStorageHashKey is the storage key that the runtime uses to store the latest working state root. WorkingStorageHashKey = []byte("working_storage_hash") + //NodeNameKey is the storage key to store de current node name and avoid create a new name every initialization + NodeNameKey = []byte("node_name") ) From 777f65809004c18a1b8ca0e94a763de6b47f7da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Sat, 24 Apr 2021 16:01:22 -0400 Subject: [PATCH 02/11] feat: persist node name across restarts --- chain/gssmr/config.toml | 2 +- cmd/gossamer/config.go | 93 +++++++++++++++++++++++++++++++------ cmd/gossamer/config_test.go | 60 ++++++++++++++++++++++++ cmd/gossamer/utils.go | 1 - dot/node.go | 69 ++++++++++++++++++++++++--- dot/node_test.go | 27 +++++++++++ dot/state/db.go | 19 ++++++++ dot/state/service.go | 85 --------------------------------- dot/utils.go | 14 ++++++ lib/utils/utils.go | 12 +++++ 10 files changed, 274 insertions(+), 108 deletions(-) diff --git a/chain/gssmr/config.toml b/chain/gssmr/config.toml index bff58944b1..57fadcf06c 100644 --- a/chain/gssmr/config.toml +++ b/chain/gssmr/config.toml @@ -21,7 +21,7 @@ key = "" unlock = "" [core] -roles = 4 +roles = 2 babe-authority = true grandpa-authority = true diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index 670875196e..04893cff9a 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -32,6 +32,7 @@ import ( "github.com/ChainSafe/gossamer/lib/runtime/life" "github.com/ChainSafe/gossamer/lib/runtime/wasmer" "github.com/ChainSafe/gossamer/lib/runtime/wasmtime" + "github.com/ChainSafe/gossamer/lib/utils" log "github.com/ChainSafe/log15" "github.com/urfave/cli" @@ -119,7 +120,6 @@ func createDotConfig(ctx *cli.Context) (*dot.Config, error) { logger.Error("failed to set chain configuration", "error", err) return nil, err } - // set log config err = setLogConfig(ctx, tomlCfg, &cfg.Global, &cfg.Log) if err != nil { @@ -130,7 +130,10 @@ func createDotConfig(ctx *cli.Context) (*dot.Config, error) { logger.Info("loaded package log configuration", "cfg", cfg.Log) // set global configuration values - setDotGlobalConfig(ctx, tomlCfg, &cfg.Global) + if err := setDotGlobalConfig(ctx, tomlCfg, &cfg.Global); err != nil { + logger.Error("failed to set global node configuration", "error", err) + return nil, err + } // set remaining cli configuration values setDotInitConfig(ctx, tomlCfg.Init, &cfg.Init) @@ -158,7 +161,10 @@ func createInitConfig(ctx *cli.Context) (*dot.Config, error) { } // set global configuration values - setDotGlobalConfig(ctx, tomlCfg, &cfg.Global) + if err := setDotGlobalConfig(ctx, tomlCfg, &cfg.Global); err != nil { + logger.Error("failed to set global node configuration", "error", err) + return nil, err + } // set log config err = setLogConfig(ctx, tomlCfg, &cfg.Global, &cfg.Log) @@ -194,7 +200,11 @@ func createImportStateConfig(ctx *cli.Context) (*dot.Config, error) { } // set global configuration values - setDotGlobalConfig(ctx, tomlCfg, &cfg.Global) + if err := setDotGlobalConfig(ctx, tomlCfg, &cfg.Global); err != nil { + logger.Error("failed to set global node configuration", "error", err) + return nil, err + } + return cfg, nil } @@ -208,7 +218,11 @@ func createBuildSpecConfig(ctx *cli.Context) (*dot.Config, error) { } // set global configuration values - setDotGlobalConfig(ctx, tomlCfg, &cfg.Global) + if err := setDotGlobalConfig(ctx, tomlCfg, &cfg.Global); err != nil { + logger.Error("failed to set global node configuration", "error", err) + return nil, err + } + return cfg, nil } @@ -227,7 +241,10 @@ func createExportConfig(ctx *cli.Context) (*dot.Config, error) { updateDotConfigFromGenesisJSONRaw(*tomlCfg, cfg) // set global configuration values - setDotGlobalConfig(ctx, tomlCfg, &cfg.Global) + if err := setDotGlobalConfig(ctx, tomlCfg, &cfg.Global); err != nil { + logger.Error("failed to set global node configuration", "error", err) + return nil, err + } // set log config err = setLogConfig(ctx, &ctoml.Config{}, &cfg.Global, &cfg.Log) @@ -383,8 +400,26 @@ func setDotInitConfig(ctx *cli.Context, tomlCfg ctoml.InitConfig, cfg *dot.InitC ) } -// setDotGlobalConfig sets dot.GlobalConfig using flag values from the cli context -func setDotGlobalConfig(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.GlobalConfig) { +func setDotGlobalConfig(ctx *cli.Context, tomlConfig *ctoml.Config, cfg *dot.GlobalConfig) error { + setDotGlobalConfigFromToml(tomlConfig, cfg) + setDotGlobalConfigFromFlags(ctx, cfg) + + if err := setDotGlobalConfigName(ctx, tomlConfig, cfg); err != nil { + return fmt.Errorf("could not set global node name: %w", err) + } + + logger.Debug( + "global configuration", + "name", cfg.Name, + "id", cfg.ID, + "basepath", cfg.BasePath, + ) + + return nil +} + +// setDotGlobalConfigFromToml will apply the toml configs to dot global config +func setDotGlobalConfigFromToml(tomlCfg *ctoml.Config, cfg *dot.GlobalConfig) { if tomlCfg != nil { if tomlCfg.Global.Name != "" { cfg.Name = tomlCfg.Global.Name @@ -404,7 +439,10 @@ func setDotGlobalConfig(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.Global cfg.MetricsPort = tomlCfg.Global.MetricsPort } +} +// setDotGlobalConfigFromFlags sets dot.GlobalConfig using flag values from the cli context +func setDotGlobalConfigFromFlags(ctx *cli.Context, cfg *dot.GlobalConfig) { // check --name flag and update node configuration if name := ctx.GlobalString(NameFlag.Name); name != "" { cfg.Name = name @@ -419,6 +457,7 @@ func setDotGlobalConfig(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.Global if cfg.BasePath == "" { cfg.BasePath = dot.GssmrConfig().Global.BasePath } + // check --log flag if lvlToInt, err := strconv.Atoi(ctx.String(LogFlag.Name)); err == nil { cfg.LogLvl = log.Lvl(lvlToInt) @@ -434,13 +473,39 @@ func setDotGlobalConfig(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.Global } cfg.NoTelemetry = ctx.Bool("no-telemetry") +} - logger.Debug( - "global configuration", - "name", cfg.Name, - "id", cfg.ID, - "basepath", cfg.BasePath, - ) +func setDotGlobalConfigName(ctx *cli.Context, tomlConfig *ctoml.Config, cfg *dot.GlobalConfig) error { + globalBasePath := utils.ExpandDir(cfg.BasePath) + initialized := dot.NodeInitialized(globalBasePath, false) + + // if node was previusly initialized then retrieve the node name + // from the current database + if initialized { + var err error + if cfg.Name, err = dot.LoadGlobalNodeName(globalBasePath); err != nil { + return err + } + + // if successfull global node name loaded + if cfg.Name != "" { + logger.Debug("load global node name from database", "name", cfg.Name) + return nil + } + } + + thereIsNameFlag := ctx.GlobalString(NameFlag.Name) != "" + thereIsNameTomlConfig := tomlConfig.Global.Name != "" + + // if the node was not initialized + // and no name flag was defined neither there is a name + // defined at toml config file then create a new + // random name and set at dot globals config + if !initialized && !thereIsNameFlag && !thereIsNameTomlConfig { + cfg.Name = dot.RandonNodeName() + } + + return nil } // setDotAccountConfig sets dot.AccountConfig using flag values from the cli context diff --git a/cmd/gossamer/config_test.go b/cmd/gossamer/config_test.go index c0485bc8a5..c34ce00918 100644 --- a/cmd/gossamer/config_test.go +++ b/cmd/gossamer/config_test.go @@ -23,6 +23,7 @@ import ( "github.com/ChainSafe/gossamer/chain/gssmr" "github.com/ChainSafe/gossamer/dot" "github.com/ChainSafe/gossamer/dot/state" + "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/genesis" "github.com/ChainSafe/gossamer/lib/utils" @@ -833,3 +834,62 @@ func TestUpdateConfigFromGenesisData(t *testing.T) { require.Equal(t, expected, cfg) } + +func TestGlobalNodeName_WhenNodeAlreadyHasStoredName(t *testing.T) { + // Initialize a node with a random name + globalName := dot.RandonNodeName() + + cfg := dot.NewTestConfig(t) + cfg.Global.Name = globalName + require.NotNil(t, cfg) + + genPath := dot.NewTestGenesisAndRuntime(t) + require.NotNil(t, genPath) + + defer utils.RemoveTestDir(t) + + cfg.Core.Roles = types.FullNodeRole + cfg.Core.BabeAuthority = false + cfg.Core.GrandpaAuthority = false + cfg.Core.BabeThresholdNumerator = 0 + cfg.Core.BabeThresholdDenominator = 0 + cfg.Init.Genesis = genPath + + err := dot.InitNode(cfg) + require.NoError(t, err) + + // call another command and test the name + testApp := cli.NewApp() + testApp.Writer = ioutil.Discard + + testcases := []struct { + description string + flags []string + values []interface{} + expected string + }{ + { + "Test gossamer --roles --basepath", + []string{"basepath", "roles"}, + []interface{}{cfg.Global.BasePath, "4"}, + globalName, + }, + { + "Test gossamer --roles", + []string{"basepath", "roles"}, + []interface{}{cfg.Global.BasePath, "0"}, + globalName, + }, + } + + for _, c := range testcases { + c := c // bypass scopelint false positive + t.Run(c.description, func(t *testing.T) { + ctx, err := newTestContext(c.description, c.flags, c.values) + require.Nil(t, err) + createdCfg, err := createDotConfig(ctx) + require.Nil(t, err) + require.Equal(t, c.expected, createdCfg.Global.Name) + }) + } +} diff --git a/cmd/gossamer/utils.go b/cmd/gossamer/utils.go index 8bb3e253f6..b5feb371ab 100644 --- a/cmd/gossamer/utils.go +++ b/cmd/gossamer/utils.go @@ -126,7 +126,6 @@ func newTestConfigWithFile(t *testing.T) (*dot.Config, *os.File) { require.NoError(t, err) tomlCfg := dotConfigToToml(cfg) - cfgFile := exportConfig(tomlCfg, file.Name()) return cfg, cfgFile } diff --git a/dot/node.go b/dot/node.go index 7f31a72384..36ed25a9c9 100644 --- a/dot/node.go +++ b/dot/node.go @@ -58,6 +58,7 @@ func InitNode(cfg *Config) error { setupLogger(cfg) logger.Info( "🕸️ initializing node...", + "name", cfg.Global.Name, "id", cfg.Global.ID, "basepath", cfg.Global.BasePath, "genesis", cfg.Init.Genesis, @@ -99,20 +100,17 @@ func InitNode(cfg *Config) error { // initialize state service with genesis data, block, and trie err = stateSrvc.Initialize(gen, header, t) - - if cfg.Global.Name != "" { - if cfg.Global.Name, err = stateSrvc.NodeGlobalName(); err != nil { - return err - } + if err != nil { + return fmt.Errorf("failed to initialize state service: %s", err) } + err = storeGlobalNodeName(cfg.Global.Name, cfg.Global.BasePath) if err != nil { - return fmt.Errorf("failed to initialize state service: %s", err) + return fmt.Errorf("failed to store global node name: %s", err) } logger.Info( "🕸️ node initialized", - "name", cfg.Global.Name, "id", cfg.Global.ID, "basepath", cfg.Global.BasePath, "genesis", cfg.Init.Genesis, @@ -128,6 +126,7 @@ func InitNode(cfg *Config) error { func NodeInitialized(basepath string, expected bool) bool { // check if key registry exists registry := path.Join(basepath, "KEYREGISTRY") + _, err := os.Stat(registry) if os.IsNotExist(err) { if expected { @@ -173,6 +172,34 @@ func NodeInitialized(basepath string, expected bool) bool { return true } +// LoadGlobalNodeName returns the stored global node name from database +func LoadGlobalNodeName(basepath string) (string, error) { + // initialize database using data directory + db, err := state.SetupDatabase(basepath) + if err != nil { + return "", err + } + + name, err := state.LoadNodeGlobalName(db) + if err != nil { + logger.Warn( + "failed to load global node name", + "basepath", basepath, + "error", err, + ) + return "", nil + } + + // close database + err = db.Close() + if err != nil { + logger.Error("failed to close database", "error", err) + return "", err + } + + return name, nil +} + // NewNode creates a new dot node from a dot node configuration func NewNode(cfg *Config, ks *keystore.GlobalKeystore, stopFunc func()) (*Node, error) { // set garbage collection percent to 10% @@ -204,6 +231,7 @@ func NewNode(cfg *Config, ks *keystore.GlobalKeystore, stopFunc func()) (*Node, // create state service and append state service to node services stateSrvc, err := createStateService(cfg) + if err != nil { return nil, fmt.Errorf("failed to create state service: %s", err) } @@ -360,6 +388,33 @@ func setupMetricsServer(address string) { }() } +// stores the global node name to reuse +func storeGlobalNodeName(name, basepath string) error { + db, err := state.SetupDatabase(basepath) + if err != nil { + return err + } + + err = state.StoreNodeGlobalName(db, name) + if err != nil { + logger.Warn( + "failed to store global node name", + "basepath", basepath, + "error", err, + ) + return nil + } + + // close database + err = db.Close() + if err != nil { + logger.Error("failed to close database", "error", err) + return err + } + + return nil +} + // Start starts all dot node services func (n *Node) Start() error { logger.Info("🕸️ starting node services...") diff --git a/dot/node_test.go b/dot/node_test.go index 6411392378..d76bd1d8ce 100644 --- a/dot/node_test.go +++ b/dot/node_test.go @@ -382,3 +382,30 @@ func TestNode_StopFunc(t *testing.T) { node.Stop() require.Equal(t, testvar, "after") } + +func TestNode_PersistGlobalName_WhenInitialize(t *testing.T) { + globalName := RandonNodeName() + + cfg := NewTestConfig(t) + cfg.Global.Name = globalName + require.NotNil(t, cfg) + + genPath := NewTestGenesisAndRuntime(t) + require.NotNil(t, genPath) + + defer utils.RemoveTestDir(t) + + cfg.Core.Roles = types.FullNodeRole + cfg.Core.BabeAuthority = false + cfg.Core.GrandpaAuthority = false + cfg.Core.BabeThresholdNumerator = 0 + cfg.Core.BabeThresholdDenominator = 0 + cfg.Init.Genesis = genPath + + err := InitNode(cfg) + require.NoError(t, err) + + storedName, err := LoadGlobalNodeName(cfg.Global.BasePath) + require.Nil(t, err) + require.Equal(t, globalName, storedName) +} diff --git a/dot/state/db.go b/dot/state/db.go index 0f5d609dcf..7fe5b753ae 100644 --- a/dot/state/db.go +++ b/dot/state/db.go @@ -27,6 +27,25 @@ import ( database "github.com/ChainSafe/chaindb" ) +// SetupDatabase will return an instance of database based on basepath +func SetupDatabase(basepath string) (database.Database, error) { + // initialize database using data directory + db, err := database.NewBadgerDB(&database.Config{ + DataDir: basepath, + }) + + if err != nil { + logger.Error( + "failed to setup database", + "basepath", basepath, + "error", err, + ) + return nil, err + } + + return db, nil +} + // StoreNodeGlobalName stores the current node name to avoid create new ones after each initialization func StoreNodeGlobalName(db database.Database, nodeName string) error { return db.Put(common.NodeNameKey, []byte(nodeName)) diff --git a/dot/state/service.go b/dot/state/service.go index 5b110f76c4..6fb9ebdc2c 100644 --- a/dot/state/service.go +++ b/dot/state/service.go @@ -18,13 +18,10 @@ package state import ( "bytes" - "encoding/binary" - "errors" "fmt" "math/big" "os" "path/filepath" - "strings" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/blocktree" @@ -32,7 +29,6 @@ import ( rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage" "github.com/ChainSafe/gossamer/lib/runtime/wasmer" "github.com/ChainSafe/gossamer/lib/trie" - "github.com/cosmos/go-bip39" "github.com/ChainSafe/chaindb" log "github.com/ChainSafe/log15" @@ -86,53 +82,6 @@ func (s *Service) DB() chaindb.Database { return s.db } -func (s *Service) NodeGlobalName() (string, error) { - logger.Info("getting node global name") - - // Load database configs - var db chaindb.Database - cfg := &chaindb.Config{} - - // check database type - if s.isMemDB { - cfg.InMemory = true - } - - // get data directory from service - basepath, err := filepath.Abs(s.dbPath) - if err != nil { - return "", fmt.Errorf("failed to read basepath: %s", err) - } - - cfg.DataDir = basepath - - // initialize database using data directory - db, err = chaindb.NewBadgerDB(cfg) - if err != nil { - return "", err - } - - var name string - if name, err = s.loadNodeName(db); err != nil { - - return "", err - } - - if name == "" { - name = generateRandomNodeName() - - if err = s.storeNodeName(db, name); err != nil { - return "", err - } - } - - if err = db.Close(); err != nil { - return "", fmt.Errorf("failed to close database: %s", err) - } - - return name, nil -} - // Initialize initializes the genesis state of the DB using the given storage trie. The trie should be loaded with the genesis storage state. // This only needs to be called during genesis initialization of the node; it doesn't need to be called during normal startup. func (s *Service) Initialize(gen *genesis.Genesis, header *types.Header, t *trie.Trie) error { @@ -547,37 +496,3 @@ func (s *Service) Import(header *types.Header, t *trie.Trie, firstSlot uint64) e return s.db.Close() } - -// storeNodeName persist the global node name on initialization -func (s *Service) storeNodeName(db chaindb.Database, name string) error { - if err := StoreNodeGlobalName(db, name); err != nil { - return fmt.Errorf("failed to write node global name to database: %w", err) - } - - return nil -} - -// loadNodeName will retrieve the node name on reinitialization -func (s *Service) loadNodeName(db chaindb.Database) (string, error) { - var err error - var nodeName string - - if nodeName, err = LoadNodeGlobalName(db); err != nil { - if errors.Is(err, chaindb.ErrKeyNotFound) { - return "", nil - } - - return "", fmt.Errorf("failed to retrieve node global name from database: %w", err) - } - - return nodeName, nil -} - -func generateRandomNodeName() string { - // generate random name - entropy, _ := bip39.NewEntropy(128) - randomNamesString, _ := bip39.NewMnemonic(entropy) - randomNames := strings.Split(randomNamesString, " ") - number := binary.BigEndian.Uint16(entropy) - return randomNames[0] + "-" + randomNames[1] + "-" + fmt.Sprint(number) -} diff --git a/dot/utils.go b/dot/utils.go index 03c9640468..5eb92d1bef 100644 --- a/dot/utils.go +++ b/dot/utils.go @@ -17,11 +17,14 @@ package dot import ( + "encoding/binary" "encoding/hex" "encoding/json" + "fmt" "io/ioutil" "os" "path/filepath" + "strings" "testing" ctoml "github.com/ChainSafe/gossamer/dot/config/toml" @@ -30,6 +33,7 @@ import ( "github.com/ChainSafe/gossamer/lib/runtime/wasmer" "github.com/ChainSafe/gossamer/lib/utils" log "github.com/ChainSafe/log15" + "github.com/cosmos/go-bip39" "github.com/naoina/toml" "github.com/stretchr/testify/require" ) @@ -235,3 +239,13 @@ func CreateJSONRawFile(bs *BuildSpec, fp string) *os.File { } return WriteConfig(data, fp) } + +// RandonNodeName generate a new random name +// if there is no name configured to the node +func RandonNodeName() string { + entropy, _ := bip39.NewEntropy(128) + randomNamesString, _ := bip39.NewMnemonic(entropy) + randomNames := strings.Split(randomNamesString, " ") + number := binary.BigEndian.Uint16(entropy) + return randomNames[0] + "-" + randomNames[1] + "-" + fmt.Sprint(number) +} diff --git a/lib/utils/utils.go b/lib/utils/utils.go index f12cc797bb..2b5eb2fa32 100644 --- a/lib/utils/utils.go +++ b/lib/utils/utils.go @@ -17,6 +17,7 @@ package utils import ( + "encoding/binary" "fmt" "io/ioutil" "os" @@ -25,6 +26,8 @@ import ( "path/filepath" "runtime" "strings" + + "github.com/cosmos/go-bip39" ) // PathExists returns true if the named file or directory exists, otherwise false @@ -192,3 +195,12 @@ func GetKusamaGenesisPath() string { return fp } + +// RandomNodeName returns a random name when there is no flag --name +func RandomNodeName() string { + entropy, _ := bip39.NewEntropy(128) + randomNamesString, _ := bip39.NewMnemonic(entropy) + randomNames := strings.Split(randomNamesString, " ") + number := binary.BigEndian.Uint16(entropy) + return randomNames[0] + "-" + randomNames[1] + "-" + fmt.Sprint(number) +} From 3de18095a5b2bc93eec481bdcccdecffc17a0717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Mon, 26 Apr 2021 19:21:18 -0400 Subject: [PATCH 03/11] chore: rollback config.toml --- chain/gssmr/config.toml | 2 +- cmd/gossamer/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/gssmr/config.toml b/chain/gssmr/config.toml index 57fadcf06c..bff58944b1 100644 --- a/chain/gssmr/config.toml +++ b/chain/gssmr/config.toml @@ -21,7 +21,7 @@ key = "" unlock = "" [core] -roles = 2 +roles = 4 babe-authority = true grandpa-authority = true diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index 04893cff9a..d109ad4d03 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -487,7 +487,7 @@ func setDotGlobalConfigName(ctx *cli.Context, tomlConfig *ctoml.Config, cfg *dot return err } - // if successfull global node name loaded + // if successful global node name loaded if cfg.Name != "" { logger.Debug("load global node name from database", "name", cfg.Name) return nil From 3fb7f50cdada6041d8bc2e04c7eb5f983e113f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Mon, 26 Apr 2021 19:21:54 -0400 Subject: [PATCH 04/11] chore: fix typo --- dot/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dot/utils.go b/dot/utils.go index 5eb92d1bef..4f67021322 100644 --- a/dot/utils.go +++ b/dot/utils.go @@ -240,9 +240,9 @@ func CreateJSONRawFile(bs *BuildSpec, fp string) *os.File { return WriteConfig(data, fp) } -// RandonNodeName generate a new random name +// RandomNodeName generate a new random name // if there is no name configured to the node -func RandonNodeName() string { +func RandomNodeName() string { entropy, _ := bip39.NewEntropy(128) randomNamesString, _ := bip39.NewMnemonic(entropy) randomNames := strings.Split(randomNamesString, " ") From 4fc1c89453f735a2259c4ff9d931afcccb6066b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Mon, 26 Apr 2021 19:22:44 -0400 Subject: [PATCH 05/11] chore: fix refs and remove unused stuff --- cmd/gossamer/config.go | 2 +- cmd/gossamer/config_test.go | 2 +- dot/node_test.go | 2 +- lib/utils/utils.go | 12 ------------ 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index d109ad4d03..e958760899 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -502,7 +502,7 @@ func setDotGlobalConfigName(ctx *cli.Context, tomlConfig *ctoml.Config, cfg *dot // defined at toml config file then create a new // random name and set at dot globals config if !initialized && !thereIsNameFlag && !thereIsNameTomlConfig { - cfg.Name = dot.RandonNodeName() + cfg.Name = dot.RandomNodeName() } return nil diff --git a/cmd/gossamer/config_test.go b/cmd/gossamer/config_test.go index c34ce00918..c42ebf83bf 100644 --- a/cmd/gossamer/config_test.go +++ b/cmd/gossamer/config_test.go @@ -837,7 +837,7 @@ func TestUpdateConfigFromGenesisData(t *testing.T) { func TestGlobalNodeName_WhenNodeAlreadyHasStoredName(t *testing.T) { // Initialize a node with a random name - globalName := dot.RandonNodeName() + globalName := dot.RandomNodeName() cfg := dot.NewTestConfig(t) cfg.Global.Name = globalName diff --git a/dot/node_test.go b/dot/node_test.go index d76bd1d8ce..b2009568fd 100644 --- a/dot/node_test.go +++ b/dot/node_test.go @@ -384,7 +384,7 @@ func TestNode_StopFunc(t *testing.T) { } func TestNode_PersistGlobalName_WhenInitialize(t *testing.T) { - globalName := RandonNodeName() + globalName := RandomNodeName() cfg := NewTestConfig(t) cfg.Global.Name = globalName diff --git a/lib/utils/utils.go b/lib/utils/utils.go index 2b5eb2fa32..f12cc797bb 100644 --- a/lib/utils/utils.go +++ b/lib/utils/utils.go @@ -17,7 +17,6 @@ package utils import ( - "encoding/binary" "fmt" "io/ioutil" "os" @@ -26,8 +25,6 @@ import ( "path/filepath" "runtime" "strings" - - "github.com/cosmos/go-bip39" ) // PathExists returns true if the named file or directory exists, otherwise false @@ -195,12 +192,3 @@ func GetKusamaGenesisPath() string { return fp } - -// RandomNodeName returns a random name when there is no flag --name -func RandomNodeName() string { - entropy, _ := bip39.NewEntropy(128) - randomNamesString, _ := bip39.NewMnemonic(entropy) - randomNames := strings.Split(randomNamesString, " ") - number := binary.BigEndian.Uint16(entropy) - return randomNames[0] + "-" + randomNames[1] + "-" + fmt.Sprint(number) -} From 427001b8b1274889022233e020f546ecc0c9d3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Tue, 27 Apr 2021 07:55:51 -0400 Subject: [PATCH 06/11] chore: force rename every init --- cmd/gossamer/config.go | 48 +++++++++++----------- cmd/gossamer/config_test.go | 80 +++++++++++++++++++++++++++++++++++++ cmd/gossamer/main.go | 21 +++++++--- cmd/gossamer/main_test.go | 41 +++++++++++++++++++ 4 files changed, 161 insertions(+), 29 deletions(-) diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index 71021e64a4..87a2fa4a3e 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -120,6 +120,7 @@ func createDotConfig(ctx *cli.Context) (*dot.Config, error) { logger.Error("failed to set chain configuration", "error", err) return nil, err } + // set log config err = setLogConfig(ctx, tomlCfg, &cfg.Global, &cfg.Log) if err != nil { @@ -421,10 +422,6 @@ func setDotGlobalConfig(ctx *cli.Context, tomlConfig *ctoml.Config, cfg *dot.Glo // setDotGlobalConfigFromToml will apply the toml configs to dot global config func setDotGlobalConfigFromToml(tomlCfg *ctoml.Config, cfg *dot.GlobalConfig) { if tomlCfg != nil { - if tomlCfg.Global.Name != "" { - cfg.Name = tomlCfg.Global.Name - } - if tomlCfg.Global.ID != "" { cfg.ID = tomlCfg.Global.ID } @@ -443,11 +440,6 @@ func setDotGlobalConfigFromToml(tomlCfg *ctoml.Config, cfg *dot.GlobalConfig) { // setDotGlobalConfigFromFlags sets dot.GlobalConfig using flag values from the cli context func setDotGlobalConfigFromFlags(ctx *cli.Context, cfg *dot.GlobalConfig) { - // check --name flag and update node configuration - if name := ctx.GlobalString(NameFlag.Name); name != "" { - cfg.Name = name - } - // check --basepath flag and update node configuration if basepath := ctx.GlobalString(BasePathFlag.Name); basepath != "" { cfg.BasePath = basepath @@ -475,13 +467,29 @@ func setDotGlobalConfigFromFlags(ctx *cli.Context, cfg *dot.GlobalConfig) { cfg.NoTelemetry = ctx.Bool("no-telemetry") } -func setDotGlobalConfigName(ctx *cli.Context, tomlConfig *ctoml.Config, cfg *dot.GlobalConfig) error { +func setDotGlobalConfigName(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.GlobalConfig) error { globalBasePath := utils.ExpandDir(cfg.BasePath) initialized := dot.NodeInitialized(globalBasePath, false) - // if node was previusly initialized then retrieve the node name - // from the current database - if initialized { + thereIsNameTomlConfig := tomlCfg.Global.Name != "" + thereIsNameFlag := ctx.GlobalString(NameFlag.Name) != "" + + // consider the --name flag as higher priority + if thereIsNameFlag { + cfg.Name = ctx.GlobalString(NameFlag.Name) + return nil + } + + // consider the name on config as a second priority + if thereIsNameTomlConfig { + cfg.Name = tomlCfg.Global.Name + return nil + } + + // if node was previusly initialized + // and the was not the init command + // then retrieve the node name from the current database + if initialized && ctx.Command.Name != initCommandName { var err error if cfg.Name, err = dot.LoadGlobalNodeName(globalBasePath); err != nil { return err @@ -494,17 +502,11 @@ func setDotGlobalConfigName(ctx *cli.Context, tomlConfig *ctoml.Config, cfg *dot } } - thereIsNameFlag := ctx.GlobalString(NameFlag.Name) != "" - thereIsNameTomlConfig := tomlConfig.Global.Name != "" - // if the node was not initialized - // and no name flag was defined neither there is a name - // defined at toml config file then create a new - // random name and set at dot globals config - if !initialized && !thereIsNameFlag && !thereIsNameTomlConfig { - cfg.Name = dot.RandomNodeName() - } - + // there is no name flag + // there is no name defined at toml config file + //then create a new random name and set at dot globals config + cfg.Name = dot.RandomNodeName() return nil } diff --git a/cmd/gossamer/config_test.go b/cmd/gossamer/config_test.go index c42ebf83bf..019ef0182e 100644 --- a/cmd/gossamer/config_test.go +++ b/cmd/gossamer/config_test.go @@ -893,3 +893,83 @@ func TestGlobalNodeName_WhenNodeAlreadyHasStoredName(t *testing.T) { }) } } + +func TestGlobalNodeNamePriorityOrder(t *testing.T) { + cfg, testCfgFile := newTestConfigWithFile(t) + require.NotNil(t, cfg) + require.NotNil(t, testCfgFile) + + defer utils.RemoveTestDir(t) + + // call another command and test the name + testApp := cli.NewApp() + testApp.Writer = ioutil.Discard + + // when name flag is defined + whenNameFlagIsDefined := struct { + description string + flags []string + values []interface{} + expected string + }{ + "Test gossamer --basepath --name --config", + []string{"basepath", "name", "config"}, + []interface{}{cfg.Global.BasePath, "mydefinedname", testCfgFile.Name()}, + "mydefinedname", + } + + c := whenNameFlagIsDefined + t.Run(c.description, func(t *testing.T) { + ctx, err := newTestContext(c.description, c.flags, c.values) + require.Nil(t, err) + createdCfg, err := createDotConfig(ctx) + require.Nil(t, err) + require.Equal(t, c.expected, createdCfg.Global.Name) + }) + + // when name flag is not defined + // then should load name from toml if it exists + whenNameIsDefinedOnTomlConfig := struct { + description string + flags []string + values []interface{} + expected string + }{ + "Test gossamer --basepath --config", + []string{"basepath", "config"}, + []interface{}{cfg.Global.BasePath, testCfgFile.Name()}, + cfg.Global.Name, + } + + c = whenNameIsDefinedOnTomlConfig + t.Run(c.description, func(t *testing.T) { + ctx, err := newTestContext(c.description, c.flags, c.values) + require.Nil(t, err) + createdCfg, err := createDotConfig(ctx) + require.Nil(t, err) + require.Equal(t, c.expected, createdCfg.Global.Name) + }) + + // when there is no name flag and no name in config + // should check the load is initialized or generate a new random name + cfg.Global.Name = "" + + whenThereIsNoName := struct { + description string + flags []string + values []interface{} + }{ + "Test gossamer --basepath", + []string{"basepath"}, + []interface{}{cfg.Global.BasePath}, + } + + t.Run(c.description, func(t *testing.T) { + ctx, err := newTestContext(whenThereIsNoName.description, whenThereIsNoName.flags, whenThereIsNoName.values) + require.Nil(t, err) + createdCfg, err := createDotConfig(ctx) + require.Nil(t, err) + require.NotEmpty(t, createdCfg.Global.Name) + require.NotEqual(t, cfg.Global.Name, createdCfg.Global.Name) + }) +} diff --git a/cmd/gossamer/main.go b/cmd/gossamer/main.go index 5c0d3d0ea3..b6d18f5a68 100644 --- a/cmd/gossamer/main.go +++ b/cmd/gossamer/main.go @@ -28,6 +28,15 @@ import ( "github.com/urfave/cli" ) +const ( + accountCommandName = "account" + exportCommandName = "export" + initCommandName = "init" + buildSpecCommandName = "build-spec" + importRuntimeCommandName = "import-runtime" + importStateCommandName = "import-state" +) + // app is the cli application var app = cli.NewApp() var logger = log.New("pkg", "cmd") @@ -36,7 +45,7 @@ var ( // exportCommand defines the "export" subcommand (ie, `gossamer export`) exportCommand = cli.Command{ Action: FixFlagOrder(exportAction), - Name: "export", + Name: exportCommandName, Usage: "Export configuration values to TOML configuration file", ArgsUsage: "", Flags: ExportFlags, @@ -47,7 +56,7 @@ var ( // initCommand defines the "init" subcommand (ie, `gossamer init`) initCommand = cli.Command{ Action: FixFlagOrder(initAction), - Name: "init", + Name: initCommandName, Usage: "Initialise node databases and load genesis data to state", ArgsUsage: "", Flags: InitFlags, @@ -58,7 +67,7 @@ var ( // accountCommand defines the "account" subcommand (ie, `gossamer account`) accountCommand = cli.Command{ Action: FixFlagOrder(accountAction), - Name: "account", + Name: accountCommandName, Usage: "Create and manage node keystore accounts", Flags: AccountFlags, Category: "ACCOUNT", @@ -72,7 +81,7 @@ var ( // buildSpecCommand creates a raw genesis file from a human readable genesis file. buildSpecCommand = cli.Command{ Action: FixFlagOrder(buildSpecAction), - Name: "build-spec", + Name: buildSpecCommandName, Usage: "Generates genesis JSON data, and can convert to raw genesis data", ArgsUsage: "", Flags: BuildSpecFlags, @@ -86,7 +95,7 @@ var ( // importRuntime generates a genesis file given a .wasm runtime binary. importRuntimeCommand = cli.Command{ Action: FixFlagOrder(importRuntimeAction), - Name: "import-runtime", + Name: importRuntimeCommandName, Usage: "Generates a genesis file given a .wasm runtime binary", ArgsUsage: "", Flags: RootFlags, @@ -97,7 +106,7 @@ var ( importStateCommand = cli.Command{ Action: FixFlagOrder(importStateAction), - Name: "import-state", + Name: importStateCommandName, Usage: "Import state from a JSON file and set it as the chain head state", ArgsUsage: "", Flags: ImportStateFlags, diff --git a/cmd/gossamer/main_test.go b/cmd/gossamer/main_test.go index a1ab39225f..c09ef05742 100644 --- a/cmd/gossamer/main_test.go +++ b/cmd/gossamer/main_test.go @@ -32,6 +32,7 @@ import ( "text/template" "time" + "github.com/ChainSafe/gossamer/dot" "github.com/ChainSafe/gossamer/lib/utils" "github.com/docker/docker/pkg/reexec" "github.com/stretchr/testify/require" @@ -281,7 +282,47 @@ func TestGossamerCommand(t *testing.T) { require.NotContains(t, string(stderr), m) } } +} + +func TestInitCommand_RenameNodeWhenCalled(t *testing.T) { + genesisPath := utils.GetGssmrGenesisRawPath() + + tempDir, err := ioutil.TempDir("", "gossamer-maintest-") + require.Nil(t, err) + + nodeName := dot.RandomNodeName() + init := runTestGossamer(t, + "init", + "--basepath", tempDir, + "--genesis", genesisPath, + "--name", nodeName, + "--config", defaultGssmrConfigPath, + "--force", + ) + + stdout, stderr := init.GetOutput() + require.Nil(t, err) + + t.Log("init gossamer output, ", "stdout", string(stdout), "stderr", string(stderr)) + + // should contains the name defined in name flag + require.Contains(t, string(stdout), nodeName) + + init = runTestGossamer(t, + "init", + "--basepath", tempDir, + "--genesis", genesisPath, + "--config", defaultGssmrConfigPath, + "--force", + ) + + stdout, stderr = init.GetOutput() + require.Nil(t, err) + + t.Log("init gossamer output, ", "stdout", string(stdout), "stderr", string(stderr)) + // should not contains the name from the last init + require.NotContains(t, string(stdout), nodeName) } func TestBuildSpecCommandWithOutput(t *testing.T) { From d8ad8fa1b7c7ba60a8e261bcbde77b04415c4dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Tue, 27 Apr 2021 08:02:55 -0400 Subject: [PATCH 07/11] chore: fix lint --- cmd/gossamer/config.go | 14 ++++++++------ cmd/gossamer/config_test.go | 4 ++-- dot/node.go | 4 ++-- dot/state/db.go | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index 87a2fa4a3e..65b29c2891 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -162,7 +162,8 @@ func createInitConfig(ctx *cli.Context) (*dot.Config, error) { } // set global configuration values - if err := setDotGlobalConfig(ctx, tomlCfg, &cfg.Global); err != nil { + err = setDotGlobalConfig(ctx, tomlCfg, &cfg.Global) + if err != nil { logger.Error("failed to set global node configuration", "error", err) return nil, err } @@ -242,7 +243,8 @@ func createExportConfig(ctx *cli.Context) (*dot.Config, error) { updateDotConfigFromGenesisJSONRaw(*tomlCfg, cfg) // set global configuration values - if err := setDotGlobalConfig(ctx, tomlCfg, &cfg.Global); err != nil { + err = setDotGlobalConfig(ctx, tomlCfg, &cfg.Global) + if err != nil { logger.Error("failed to set global node configuration", "error", err) return nil, err } @@ -469,7 +471,7 @@ func setDotGlobalConfigFromFlags(ctx *cli.Context, cfg *dot.GlobalConfig) { func setDotGlobalConfigName(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.GlobalConfig) error { globalBasePath := utils.ExpandDir(cfg.BasePath) - initialized := dot.NodeInitialized(globalBasePath, false) + initialised := dot.NodeInitialized(globalBasePath, false) thereIsNameTomlConfig := tomlCfg.Global.Name != "" thereIsNameFlag := ctx.GlobalString(NameFlag.Name) != "" @@ -486,10 +488,10 @@ func setDotGlobalConfigName(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.Gl return nil } - // if node was previusly initialized + // if node was previusly initialised // and the was not the init command // then retrieve the node name from the current database - if initialized && ctx.Command.Name != initCommandName { + if initialised && ctx.Command.Name != initCommandName { var err error if cfg.Name, err = dot.LoadGlobalNodeName(globalBasePath); err != nil { return err @@ -502,7 +504,7 @@ func setDotGlobalConfigName(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.Gl } } - // if the node was not initialized + // if the node was not initialised // there is no name flag // there is no name defined at toml config file //then create a new random name and set at dot globals config diff --git a/cmd/gossamer/config_test.go b/cmd/gossamer/config_test.go index 019ef0182e..13adecab88 100644 --- a/cmd/gossamer/config_test.go +++ b/cmd/gossamer/config_test.go @@ -836,7 +836,7 @@ func TestUpdateConfigFromGenesisData(t *testing.T) { } func TestGlobalNodeName_WhenNodeAlreadyHasStoredName(t *testing.T) { - // Initialize a node with a random name + // Initialise a node with a random name globalName := dot.RandomNodeName() cfg := dot.NewTestConfig(t) @@ -951,7 +951,7 @@ func TestGlobalNodeNamePriorityOrder(t *testing.T) { }) // when there is no name flag and no name in config - // should check the load is initialized or generate a new random name + // should check the load is initialised or generate a new random name cfg.Global.Name = "" whenThereIsNoName := struct { diff --git a/dot/node.go b/dot/node.go index 3db76627ae..4e270469e0 100644 --- a/dot/node.go +++ b/dot/node.go @@ -110,7 +110,7 @@ func InitNode(cfg *Config) error { } logger.Info( - "node initialised", + "node initialised", "name", cfg.Global.Name, "id", cfg.Global.ID, "basepath", cfg.Global.BasePath, @@ -175,7 +175,7 @@ func NodeInitialized(basepath string, expected bool) bool { // LoadGlobalNodeName returns the stored global node name from database func LoadGlobalNodeName(basepath string) (string, error) { - // initialize database using data directory + // initialise database using data directory db, err := state.SetupDatabase(basepath) if err != nil { return "", err diff --git a/dot/state/db.go b/dot/state/db.go index 7fe5b753ae..1bc1bfe23c 100644 --- a/dot/state/db.go +++ b/dot/state/db.go @@ -29,7 +29,7 @@ import ( // SetupDatabase will return an instance of database based on basepath func SetupDatabase(basepath string) (database.Database, error) { - // initialize database using data directory + // initialise database using data directory db, err := database.NewBadgerDB(&database.Config{ DataDir: basepath, }) From 7120f05140d9680569c1aae27b9000d9fef57831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Tue, 27 Apr 2021 14:15:46 -0400 Subject: [PATCH 08/11] chore: resolve comments --- cmd/gossamer/config.go | 16 +++------------- dot/state/db.go | 14 +------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index 65b29c2891..74524d0272 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -473,41 +473,31 @@ func setDotGlobalConfigName(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.Gl globalBasePath := utils.ExpandDir(cfg.BasePath) initialised := dot.NodeInitialized(globalBasePath, false) - thereIsNameTomlConfig := tomlCfg.Global.Name != "" - thereIsNameFlag := ctx.GlobalString(NameFlag.Name) != "" - // consider the --name flag as higher priority - if thereIsNameFlag { + if tomlCfg.Global.Name != "" { cfg.Name = ctx.GlobalString(NameFlag.Name) return nil } // consider the name on config as a second priority - if thereIsNameTomlConfig { + if ctx.GlobalString(NameFlag.Name) != "" { cfg.Name = tomlCfg.Global.Name return nil } - // if node was previusly initialised - // and the was not the init command - // then retrieve the node name from the current database + // if node was previously initialised and is not the init command if initialised && ctx.Command.Name != initCommandName { var err error if cfg.Name, err = dot.LoadGlobalNodeName(globalBasePath); err != nil { return err } - // if successful global node name loaded if cfg.Name != "" { logger.Debug("load global node name from database", "name", cfg.Name) return nil } } - // if the node was not initialised - // there is no name flag - // there is no name defined at toml config file - //then create a new random name and set at dot globals config cfg.Name = dot.RandomNodeName() return nil } diff --git a/dot/state/db.go b/dot/state/db.go index 1bc1bfe23c..f4f49d1f85 100644 --- a/dot/state/db.go +++ b/dot/state/db.go @@ -29,21 +29,9 @@ import ( // SetupDatabase will return an instance of database based on basepath func SetupDatabase(basepath string) (database.Database, error) { - // initialise database using data directory - db, err := database.NewBadgerDB(&database.Config{ + return database.NewBadgerDB(&database.Config{ DataDir: basepath, }) - - if err != nil { - logger.Error( - "failed to setup database", - "basepath", basepath, - "error", err, - ) - return nil, err - } - - return db, nil } // StoreNodeGlobalName stores the current node name to avoid create new ones after each initialization From 17dea68854899ac192136b35c907e9962d6513f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Thu, 29 Apr 2021 17:13:33 -0400 Subject: [PATCH 09/11] fix: resolve issue with name --- cmd/gossamer/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index d0ff22124f..1695c73e62 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -474,13 +474,13 @@ func setDotGlobalConfigName(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.Gl initialised := dot.NodeInitialized(globalBasePath, false) // consider the --name flag as higher priority - if tomlCfg.Global.Name != "" { + if ctx.GlobalString(NameFlag.Name) != "" { cfg.Name = ctx.GlobalString(NameFlag.Name) return nil } // consider the name on config as a second priority - if ctx.GlobalString(NameFlag.Name) != "" { + if tomlCfg.Global.Name != "" { cfg.Name = tomlCfg.Global.Name return nil } From 50a78c3da9e09ada723ff74e247f5ea328275687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Thu, 29 Apr 2021 22:41:21 -0400 Subject: [PATCH 10/11] chore: return err and close db anyways --- dot/node.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/dot/node.go b/dot/node.go index 0259342574..2b1fc57c8e 100644 --- a/dot/node.go +++ b/dot/node.go @@ -398,6 +398,8 @@ func storeGlobalNodeName(name, basepath string) error { return err } + defer db.Close() + basestate := state.NewBaseState(db) err = basestate.StoreNodeGlobalName(name) if err != nil { @@ -406,13 +408,6 @@ func storeGlobalNodeName(name, basepath string) error { "basepath", basepath, "error", err, ) - return nil - } - - // close database - err = db.Close() - if err != nil { - logger.Error("failed to close database", "error", err) return err } From e99354a07bbf2732ba07efdc2de8122ff6851b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Melo=20J=C3=BAnior?= Date: Thu, 29 Apr 2021 23:03:52 -0400 Subject: [PATCH 11/11] chore: check db close err --- dot/node.go | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/dot/node.go b/dot/node.go index 2b1fc57c8e..25ac6561b8 100644 --- a/dot/node.go +++ b/dot/node.go @@ -174,33 +174,33 @@ func NodeInitialized(basepath string, expected bool) bool { } // LoadGlobalNodeName returns the stored global node name from database -func LoadGlobalNodeName(basepath string) (string, error) { +func LoadGlobalNodeName(basepath string) (nodename string, err error) { // initialise database using data directory db, err := state.SetupDatabase(basepath) if err != nil { return "", err } - basestate := state.NewBaseState(db) + defer func() { + err = db.Close() + if err != nil { + logger.Error("failed to close database", "error", err) + return + } + }() - name, err := basestate.LoadNodeGlobalName() + basestate := state.NewBaseState(db) + nodename, err = basestate.LoadNodeGlobalName() if err != nil { logger.Warn( "failed to load global node name", "basepath", basepath, "error", err, ) - return "", nil - } - - // close database - err = db.Close() - if err != nil { - logger.Error("failed to close database", "error", err) return "", err } - return name, nil + return nodename, err } // NewNode creates a new dot node from a dot node configuration @@ -392,13 +392,19 @@ func setupMetricsServer(address string) { } // stores the global node name to reuse -func storeGlobalNodeName(name, basepath string) error { +func storeGlobalNodeName(name, basepath string) (err error) { db, err := state.SetupDatabase(basepath) if err != nil { return err } - defer db.Close() + defer func() { + err = db.Close() + if err != nil { + logger.Error("failed to close database", "error", err) + return + } + }() basestate := state.NewBaseState(db) err = basestate.StoreNodeGlobalName(name)