Skip to content

Commit

Permalink
implement genesis config (#3600)
Browse files Browse the repository at this point in the history
closes: #3505
  • Loading branch information
dshulyak committed Sep 29, 2022
1 parent 5279493 commit d5ccfe8
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 54 deletions.
48 changes: 35 additions & 13 deletions cmd/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ import (
"github.com/spacemeshos/go-spacemesh/txs"
)

const edKeyFileName = "key.bin"
const (
edKeyFileName = "key.bin"
genesisFileName = "genesis.json"
)

// Logger names.
const (
Expand Down Expand Up @@ -115,19 +118,19 @@ var Cmd = &cobra.Command{
)
starter := func() error {
if err := app.Initialize(); err != nil {
return fmt.Errorf("init node: %w", err)
return err
}
// This blocks until the context is finished or until an error is produced
if err := app.Start(); err != nil {
return fmt.Errorf("start node: %w", err)
return err
}

return nil
}
err = starter()
app.Cleanup()
if err != nil {
log.With().Fatal("Failed to run the node. See logs for details.", log.Err(err))
log.With().Fatal(err.Error())
}
},
}
Expand Down Expand Up @@ -296,6 +299,31 @@ func (app *App) introduction() {

// Initialize sets up an exit signal, logging and checks the clock, returns error if clock is not in sync.
func (app *App) Initialize() (err error) {
// ensure all data folders exist
err = filesystem.ExistOrCreate(app.Config.DataDir())
if err != nil {
return fmt.Errorf("ensure folders exist: %w", err)
}

gpath := filepath.Join(app.Config.DataDir(), genesisFileName)
var existing config.GenesisConfig
if err := existing.LoadFromFile(gpath); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("failed to load genesis config at %s: %w", gpath, err)
}
if err := app.Config.Genesis.Validate(); err != nil {
return err
}
if err := app.Config.Genesis.WriteToFile(gpath); err != nil {
return fmt.Errorf("failed to write genesis config to %s: %w", gpath, err)
}
} else {
diff := existing.Diff(app.Config.Genesis)
if len(diff) > 0 {
return fmt.Errorf("genesis config was updated after initializing a node, if you know that update is required delete config at %s.\ndiff:\n%s", gpath, diff)
}
}

// tortoise wait zdist layers for hare to timeout for a layer. once hare timeout, tortoise will
// vote against all blocks in that layer. so it's important to make sure zdist takes longer than
// hare's max time duration to run consensus for a layer
Expand All @@ -315,12 +343,6 @@ func (app *App) Initialize() (err error) {
// override default config in timesync since timesync is using TimeConfigValues
timeCfg.TimeConfigValues = app.Config.TIME

// ensure all data folders exist
err = filesystem.ExistOrCreate(app.Config.DataDir())
if err != nil {
return fmt.Errorf("ensure folders exist: %w", err)
}

// exit gracefully - e.g. with app Cleanup on sig abort (ctrl-c)
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
Expand Down Expand Up @@ -466,7 +488,7 @@ func (app *App) initServices(ctx context.Context,
}
}

goldenATXID := types.ATXID(types.HexToHash32(app.Config.GoldenATXID))
goldenATXID := types.ATXID(app.Config.Genesis.GenesisID().ToHash32())
if goldenATXID == *types.EmptyATXID {
return errors.New("invalid golden atx id")
}
Expand Down Expand Up @@ -1036,9 +1058,9 @@ func (app *App) Start() error {
/* Initialize all protocol services */

dbStorepath := app.Config.DataDir()
gTime, err := time.Parse(time.RFC3339, app.Config.GenesisTime)
gTime, err := time.Parse(time.RFC3339, app.Config.Genesis.GenesisTime)
if err != nil {
return fmt.Errorf("cannot parse genesis time %s: %d", app.Config.GenesisTime, err)
return fmt.Errorf("cannot parse genesis time %s: %d", app.Config.Genesis.GenesisTime, err)
}
ld := time.Duration(app.Config.LayerDurationSec) * time.Second
clock := timesync.NewClock(timesync.RealClock{}, ld, gTime, lg.WithName("clock"))
Expand Down
62 changes: 56 additions & 6 deletions cmd/node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -709,8 +709,8 @@ func TestSpacemeshApp_TransactionService(t *testing.T) {
app.Config.SyncInterval = 1000000
app.Config.LayerDurationSec = 2

app.Config.GenesisTime = time.Now().Add(20 * time.Second).Format(time.RFC3339)
app.Config.Genesis = &apiConfig.GenesisConfig{
app.Config.Genesis = &config.GenesisConfig{
GenesisTime: time.Now().Add(20 * time.Second).Format(time.RFC3339),
Accounts: map[string]uint64{
address.String(): 100_000_000,
},
Expand Down Expand Up @@ -801,14 +801,18 @@ func TestSpacemeshApp_TransactionService(t *testing.T) {

func TestInitialize_BadTortoiseParams(t *testing.T) {
conf := config.DefaultConfig()
conf.DataDirParent = t.TempDir()
app := New(WithLog(logtest.New(t)), WithConfig(&conf))
require.NoError(t, app.Initialize())

conf = config.DefaultTestConfig()
conf.DataDirParent = t.TempDir()
app = New(WithLog(logtest.New(t)), WithConfig(&conf))
require.NoError(t, app.Initialize())

app = New(WithLog(logtest.New(t)), WithConfig(getTestDefaultConfig()))
tconf := getTestDefaultConfig()
tconf.DataDirParent = t.TempDir()
app = New(WithLog(logtest.New(t)), WithConfig(tconf))
require.NoError(t, app.Initialize())

conf.Tortoise.Zdist = 5
Expand Down Expand Up @@ -914,6 +918,53 @@ func TestConfig_GenesisAccounts(t *testing.T) {
})
}

func TestGenesisConfig(t *testing.T) {
t.Run("config is written to a file", func(t *testing.T) {
app := New()
app.Config = getTestDefaultConfig()
app.Config.DataDirParent = t.TempDir()

require.NoError(t, app.Initialize())
var existing config.GenesisConfig
require.NoError(t, existing.LoadFromFile(filepath.Join(app.Config.DataDir(), genesisFileName)))
require.Empty(t, existing.Diff(app.Config.Genesis))
})
t.Run("no error if no diff", func(t *testing.T) {
app := New()
app.Config = getTestDefaultConfig()
app.Config.DataDirParent = t.TempDir()

require.NoError(t, app.Initialize())
require.NoError(t, app.Initialize())
})
t.Run("fatal error on a diff", func(t *testing.T) {
app := New()
app.Config = getTestDefaultConfig()
app.Config.DataDirParent = t.TempDir()

require.NoError(t, app.Initialize())
app.Config.Genesis.ExtraData = "changed"
err := app.Initialize()
require.ErrorContains(t, err, "genesis config")
})
t.Run("not valid time", func(t *testing.T) {
app := New()
app.Config = getTestDefaultConfig()
app.Config.DataDirParent = t.TempDir()
app.Config.Genesis.GenesisTime = time.Now().Format(time.RFC1123)

require.ErrorContains(t, app.Initialize(), "time.RFC3339")
})
t.Run("long extra data", func(t *testing.T) {
app := New()
app.Config = getTestDefaultConfig()
app.Config.DataDirParent = t.TempDir()
app.Config.Genesis.ExtraData = string(make([]byte, 256))

require.ErrorContains(t, app.Initialize(), "extra-data")
})
}

func getTestDefaultConfig() *config.Config {
cfg, err := LoadConfigFromFile()
if err != nil {
Expand Down Expand Up @@ -959,11 +1010,10 @@ func getTestDefaultConfig() *config.Config {
cfg.FETCH.MaxRetriesForPeer = 5
cfg.FETCH.BatchSize = 5
cfg.FETCH.BatchTimeout = 5
cfg.GoldenATXID = "0x5678"

cfg.Beacon = beacon.NodeSimUnitTestConfig()

cfg.Genesis = apiConfig.DefaultTestGenesisConfig()
cfg.Genesis = config.DefaultTestGenesisConfig()

types.SetLayersPerEpoch(cfg.LayersPerEpoch)

Expand All @@ -977,7 +1027,7 @@ func initSingleInstance(lg log.Log, cfg config.Config, i int, genesisTime string
) (*App, error) {
smApp := New(WithLog(lg))
smApp.Config = &cfg
smApp.Config.GenesisTime = genesisTime
smApp.Config.Genesis.GenesisTime = genesisTime

coinbaseAddressBytes := make([]byte, 4)
binary.LittleEndian.PutUint32(coinbaseAddressBytes, uint32(i+1))
Expand Down
6 changes: 2 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,14 @@ func AddCommands(cmd *cobra.Command) {
config.OracleServerWorldID, "The worldid to use with the oracle server (temporary) ")
cmd.PersistentFlags().StringVar(&config.PoETServer, "poet-server",
config.PoETServer, "The poet server url. (temporary) ")
cmd.PersistentFlags().StringVar(&config.GenesisTime, "genesis-time",
config.GenesisTime, "Time of the genesis layer in 2019-13-02T17:02:00+00:00 format")
cmd.PersistentFlags().StringVar(&config.Genesis.GenesisTime, "genesis-time",
config.Genesis.GenesisTime, "Time of the genesis layer in 2019-13-02T17:02:00+00:00 format")
cmd.PersistentFlags().IntVar(&config.LayerDurationSec, "layer-duration-sec",
config.LayerDurationSec, "Duration between layers in seconds")
cmd.PersistentFlags().IntVar(&config.LayerAvgSize, "layer-average-size",
config.LayerAvgSize, "Layer Avg size")
cmd.PersistentFlags().BoolVar(&config.PprofHTTPServer, "pprof-server",
config.PprofHTTPServer, "enable http pprof server")
cmd.PersistentFlags().StringVar(&config.GoldenATXID, "golden-atx",
config.GoldenATXID, "golden ATX hash")
cmd.PersistentFlags().Uint64Var(&config.TickSize, "tick-size", config.TickSize, "number of poet leaves in a single tick")
cmd.PersistentFlags().StringVar(&config.PublishEventsURL, "events-url",
config.PublishEventsURL, "publish events to this url; if no url specified no events will be published")
Expand Down
38 changes: 16 additions & 22 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"math"
"path/filepath"
"time"

"github.com/spf13/viper"

Expand Down Expand Up @@ -38,21 +37,21 @@ var (
// Config defines the top level configuration for a spacemesh node.
type Config struct {
BaseConfig `mapstructure:"main"`
Address *types.Config `mapstructure:"address"`
Genesis *apiConfig.GenesisConfig `mapstructure:"genesis"`
Tortoise tortoise.Config `mapstructure:"tortoise"`
P2P p2p.Config `mapstructure:"p2p"`
API apiConfig.Config `mapstructure:"api"`
HARE hareConfig.Config `mapstructure:"hare"`
HareEligibility eligConfig.Config `mapstructure:"hare-eligibility"`
Beacon beacon.Config `mapstructure:"beacon"`
TIME timeConfig.TimeConfig `mapstructure:"time"`
VM vm.Config `mapstructure:"vm"`
POST activation.PostConfig `mapstructure:"post"`
POET activation.PoetConfig `mapstructure:"poet"`
SMESHING SmeshingConfig `mapstructure:"smeshing"`
LOGGING LoggerConfig `mapstructure:"logging"`
FETCH fetch.Config `mapstructure:"fetch"`
Address *types.Config `mapstructure:"address"`
Genesis *GenesisConfig `mapstructure:"genesis"`
Tortoise tortoise.Config `mapstructure:"tortoise"`
P2P p2p.Config `mapstructure:"p2p"`
API apiConfig.Config `mapstructure:"api"`
HARE hareConfig.Config `mapstructure:"hare"`
HareEligibility eligConfig.Config `mapstructure:"hare-eligibility"`
Beacon beacon.Config `mapstructure:"beacon"`
TIME timeConfig.TimeConfig `mapstructure:"time"`
VM vm.Config `mapstructure:"vm"`
POST activation.PostConfig `mapstructure:"post"`
POET activation.PoetConfig `mapstructure:"poet"`
SMESHING SmeshingConfig `mapstructure:"smeshing"`
LOGGING LoggerConfig `mapstructure:"logging"`
FETCH fetch.Config `mapstructure:"fetch"`
}

// DataDir returns the absolute path to use for the node's data. This is the tilde-expanded path given in the config
Expand All @@ -79,7 +78,6 @@ type BaseConfig struct {
OracleServer string `mapstructure:"oracle_server"`
OracleServerWorldID int `mapstructure:"oracle_server_worldid"`

GenesisTime string `mapstructure:"genesis-time"`
LayerDurationSec int `mapstructure:"layer-duration-sec"`
LayerAvgSize int `mapstructure:"layer-average-size"`
LayersPerEpoch uint32 `mapstructure:"layers-per-epoch"`
Expand All @@ -88,8 +86,6 @@ type BaseConfig struct {

PprofHTTPServer bool `mapstructure:"pprof-server"`

GoldenATXID string `mapstructure:"golden-atx"`

GenesisActiveSet int `mapstructure:"genesis-active-size"` // the active set size for genesis

SyncRequestTimeout int `mapstructure:"sync-request-timeout"` // ms the timeout for direct request in the sync
Expand Down Expand Up @@ -118,7 +114,7 @@ func DefaultConfig() Config {
return Config{
Address: types.DefaultAddressConfig(),
BaseConfig: defaultBaseConfig(),
Genesis: apiConfig.DefaultGenesisConfig(),
Genesis: DefaultGenesisConfig(),
Tortoise: tortoise.DefaultConfig(),
P2P: p2p.DefaultConfig(),
API: apiConfig.DefaultConfig(),
Expand Down Expand Up @@ -158,11 +154,9 @@ func defaultBaseConfig() BaseConfig {
ProfilerName: "gp-spacemesh",
OracleServer: "http://localhost:3030",
OracleServerWorldID: 0,
GenesisTime: time.Now().Format(time.RFC3339),
LayerDurationSec: 30,
LayersPerEpoch: 3,
PoETServer: "127.0.0.1",
GoldenATXID: "0x5678", // TODO: Change the value
SyncRequestTimeout: 2000,
SyncInterval: 10,
TxsPerProposal: 100,
Expand Down
Loading

0 comments on commit d5ccfe8

Please sign in to comment.