Skip to content

Commit

Permalink
fix: add support for custom node config file (gnolang#1240)
Browse files Browse the repository at this point in the history
## Description

This PR adds support for specifying a custom node configuration file
using the `--tm2-node-config` flag.

Resolves gnolang#1234

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [x] Provided any useful hints for running manual tests
- [x] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>
  • Loading branch information
zivkovicmilos authored and gfanton committed Nov 9, 2023
1 parent fc4e4dd commit 4afc62f
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 54 deletions.
134 changes: 104 additions & 30 deletions gno.land/cmd/gnoland/start.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package main

import (
"bufio"
"context"
"errors"
"flag"
"fmt"
"os"
"path/filepath"
"strings"
"time"
Expand Down Expand Up @@ -42,6 +44,7 @@ type startCfg struct {

txEventStoreType string
txEventStorePath string
nodeConfigPath string
}

func newStartCmd(io *commands.IO) *commands.Command {
Expand All @@ -54,8 +57,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)
},
)
}
Expand Down Expand Up @@ -121,7 +124,14 @@ func (c *startCfg) RegisterFlags(fs *flag.FlagSet) {
&c.config,
"config",
"",
"config file (optional)",
"the flag config file (optional)",
)

fs.StringVar(
&c.nodeConfigPath,
"tm2-node-config",
"",
"the node TOML config file path (optional)",
)

fs.StringVar(
Expand All @@ -148,14 +158,28 @@ func (c *startCfg) RegisterFlags(fs *flag.FlagSet) {
)
}

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 default node configuration
cfg, loadCfgErr = config.LoadOrMakeConfigWithOptions(rootDir, nil)
}

if loadCfgErr != nil {
return fmt.Errorf("unable to load node configuration, %w", loadCfgErr)
}

// create priv validator first.
// need it to generate genesis.json
Expand All @@ -165,13 +189,23 @@ func execStart(c *startCfg, args []string, io *commands.IO) error {

// write genesis file if missing.
genesisFilePath := filepath.Join(rootDir, cfg.Genesis)

genesisTxs, genesisTxsErr := loadGenesisTxs(c.genesisTxsFile, c.chainID, c.genesisRemote)
if genesisTxsErr != nil {
return fmt.Errorf("unable to load genesis txs, %w", genesisTxsErr)
}

if !osm.FileExists(genesisFilePath) {
genDoc := makeGenesisDoc(
genDoc, err := makeGenesisDoc(
priv.GetPubKey(),
c.chainID,
c.genesisBalancesFile,
loadGenesisTxs(c.genesisTxsFile, c.chainID, c.genesisRemote),
genesisTxs,
)
if err != nil {
return fmt.Errorf("unable to generate genesis.json, %w", err)
}

writeGenesisFile(genDoc, genesisFilePath)
}

Expand Down Expand Up @@ -248,7 +282,7 @@ func makeGenesisDoc(
chainID string,
genesisBalancesFile string,
genesisTxs []std.Tx,
) *bft.GenesisDoc {
) (*bft.GenesisDoc, error) {
gen := &bft.GenesisDoc{}

gen.GenesisTime = time.Now()
Expand All @@ -272,8 +306,10 @@ func makeGenesisDoc(
}

// Load distribution.
balances := loadGenesisBalances(genesisBalancesFile)
// debug: for _, balance := range balances { fmt.Println(balance) }
balances, err := loadGenesisBalances(genesisBalancesFile)
if err != nil {
return nil, fmt.Errorf("unable to load genesis balances, %w", err)
}

// Load initial packages from examples.
test1 := crypto.MustAddressFromString("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
Expand Down Expand Up @@ -319,7 +355,7 @@ func makeGenesisDoc(
Balances: balances,
Txs: txs,
}
return gen
return gen, nil
}

func writeGenesisFile(gen *bft.GenesisDoc, filePath string) {
Expand All @@ -333,11 +369,24 @@ func loadGenesisTxs(
path string,
chainID string,
genesisRemote string,
) []std.Tx {
txs := []std.Tx{}
txsBz := osm.MustReadFile(path)
txsLines := strings.Split(string(txsBz), "\n")
for _, txLine := range txsLines {
) ([]std.Tx, error) {
txs := make([]std.Tx, 0)

if !osm.FileExists(path) {
// No initial transactions
return txs, nil
}

txsFile, openErr := os.Open(path)
if openErr != nil {
return nil, fmt.Errorf("unable to open genesis txs file, %w", openErr)
}

scanner := bufio.NewScanner(txsFile)

for scanner.Scan() {
txLine := scanner.Text()

if txLine == "" {
continue // skip empty line
}
Expand All @@ -347,19 +396,40 @@ func loadGenesisTxs(
txLine = strings.ReplaceAll(txLine, "%%REMOTE%%", genesisRemote)

var tx std.Tx
amino.MustUnmarshalJSON([]byte(txLine), &tx)

if unmarshalErr := amino.UnmarshalJSON([]byte(txLine), &tx); unmarshalErr != nil {
return nil, fmt.Errorf("unable to amino unmarshal tx, %w", unmarshalErr)
}

txs = append(txs, tx)
}

return txs
if scanErr := scanner.Err(); scanErr != nil {
return nil, fmt.Errorf("error encountered while scanning, %w", scanErr)
}

return txs, nil
}

func loadGenesisBalances(path string) []string {
func loadGenesisBalances(path string) ([]string, error) {
// each balance is in the form: g1xxxxxxxxxxxxxxxx=100000ugnot
balances := []string{}
content := osm.MustReadFile(path)
lines := strings.Split(string(content), "\n")
for _, line := range lines {
balances := make([]string, 0)

if !osm.FileExists(path) {
// No initial balances
return balances, nil
}

balancesFile, openErr := os.Open(path)
if openErr != nil {
return nil, fmt.Errorf("unable to open genesis balances file, %w", openErr)
}

scanner := bufio.NewScanner(balancesFile)

for scanner.Scan() {
line := scanner.Text()

line = strings.TrimSpace(line)

// remove comments.
Expand All @@ -371,12 +441,16 @@ func loadGenesisBalances(path string) []string {
continue
}

parts := strings.Split(line, "=")
if len(parts) != 2 {
panic("invalid genesis_balance line: " + line)
if len(strings.Split(line, "=")) != 2 {
return nil, fmt.Errorf("invalid genesis_balance line: %s", line)
}

balances = append(balances, line)
}
return balances

if scanErr := scanner.Err(); scanErr != nil {
return nil, fmt.Errorf("error encountered while scanning, %w", scanErr)
}

return balances, nil
}
2 changes: 0 additions & 2 deletions gno.land/pkg/integration/gnoland.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,6 @@ func execTestingGnoland(t *testing.T, logger log.Logger, gnoDataDir, gnoRootDir
cfg := config.TestConfig().SetRootDir(gnoDataDir)
{
cfg.EnsureDirs()
cfg.Consensus.CreateEmptyBlocks = true
cfg.Consensus.CreateEmptyBlocksInterval = time.Duration(0)
cfg.RPC.ListenAddress = "tcp://127.0.0.1:0"
cfg.P2P.ListenAddress = "tcp://127.0.0.1:0"
}
Expand Down
34 changes: 21 additions & 13 deletions tm2/pkg/bft/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,32 +40,40 @@ 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 {
cfg = DefaultConfig()
options(cfg)
if options != nil {
options(cfg)
}
cfg.SetRootDir(root)
cfg.EnsureDirs()
WriteConfigFile(configPath, cfg)

// Validate the configuration
if validateErr := cfg.ValidateBasic(); validateErr != nil {
return nil, fmt.Errorf("unable to validate config, %w", validateErr)
}
}
if err := cfg.ValidateBasic(); err != nil {
panic(err)
}
return cfg

return cfg, nil
}

// TestConfig returns a configuration that can be used for testing
Expand Down
28 changes: 19 additions & 9 deletions tm2/pkg/bft/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,27 @@ 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
}

// Validate the config
if validateErr := nodeConfig.ValidateBasic(); validateErr != nil {
return nil, fmt.Errorf("unable to validate config, %w", validateErr)
}
return &config

return &nodeConfig, nil
}

/****** these are for production settings ***********/
Expand Down
Loading

0 comments on commit 4afc62f

Please sign in to comment.