Skip to content

Commit

Permalink
Validate genesis's InitialStakeDuration (ava-labs#2542)
Browse files Browse the repository at this point in the history
  • Loading branch information
abi87 authored Feb 15, 2023
1 parent da32bb2 commit 58b17f9
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 17 deletions.
9 changes: 5 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -824,17 +824,17 @@ func getTxFeeConfig(v *viper.Viper, networkID uint32) genesis.TxFeeConfig {
return genesis.GetTxFeeConfig(networkID)
}

func getGenesisData(v *viper.Viper, networkID uint32) ([]byte, ids.ID, error) {
func getGenesisData(v *viper.Viper, networkID uint32, stakingCfg *genesis.StakingConfig) ([]byte, ids.ID, error) {
// try first loading genesis content directly from flag/env-var
if v.IsSet(GenesisConfigContentKey) {
genesisData := v.GetString(GenesisConfigContentKey)
return genesis.FromFlag(networkID, genesisData)
return genesis.FromFlag(networkID, genesisData, stakingCfg)
}

// if content is not specified go for the file
if v.IsSet(GenesisConfigFileKey) {
genesisFileName := GetExpandedArg(v, GenesisConfigFileKey)
return genesis.FromFile(networkID, genesisFileName)
return genesis.FromFile(networkID, genesisFileName, stakingCfg)
}

// finally if file is not specified/readable go for the predefined config
Expand Down Expand Up @@ -1376,7 +1376,8 @@ func GetNodeConfig(v *viper.Viper) (node.Config, error) {
nodeConfig.TxFeeConfig = getTxFeeConfig(v, nodeConfig.NetworkID)

// Genesis Data
nodeConfig.GenesisBytes, nodeConfig.AvaxAssetID, err = getGenesisData(v, nodeConfig.NetworkID)
genesisStakingCfg := nodeConfig.StakingConfig.StakingConfig
nodeConfig.GenesisBytes, nodeConfig.AvaxAssetID, err = getGenesisData(v, nodeConfig.NetworkID, &genesisStakingCfg)
if err != nil {
return node.Config{}, fmt.Errorf("unable to load genesis file: %w", err)
}
Expand Down
17 changes: 12 additions & 5 deletions genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
)

var (
errStakeDurationTooHigh = errors.New("initial stake duration larger than maximum configured")
errNoInitiallyStakedFunds = errors.New("initial staked funds cannot be empty")
errNoSupply = errors.New("initial supply must be > 0")
errNoStakeDuration = errors.New("initial stake duration must be > 0")
Expand Down Expand Up @@ -106,7 +107,7 @@ func validateInitialStakedFunds(config *Config) error {

// validateConfig returns an error if the provided
// *Config is not considered valid.
func validateConfig(networkID uint32, config *Config) error {
func validateConfig(networkID uint32, config *Config, stakingCfg *StakingConfig) error {
if networkID != config.NetworkID {
return fmt.Errorf(
"networkID %d specified but genesis config contains networkID %d",
Expand Down Expand Up @@ -139,6 +140,12 @@ func validateConfig(networkID uint32, config *Config) error {
return errNoStakeDuration
}

// Initial stake duration of genesis validators must be
// not larger than maximal stake duration specified for any validator.
if config.InitialStakeDuration > uint64(stakingCfg.MaxStakeDuration.Seconds()) {
return errStakeDurationTooHigh
}

if len(config.InitialStakers) == 0 {
return errNoStakers
}
Expand Down Expand Up @@ -183,7 +190,7 @@ func validateConfig(networkID uint32, config *Config) error {
// 1. The byte representation of the genesis state of the platform chain
// (ie the genesis state of the network)
// 2. The asset ID of AVAX
func FromFile(networkID uint32, filepath string) ([]byte, ids.ID, error) {
func FromFile(networkID uint32, filepath string, stakingCfg *StakingConfig) ([]byte, ids.ID, error) {
switch networkID {
case constants.MainnetID, constants.TestnetID, constants.LocalID:
return nil, ids.ID{}, fmt.Errorf(
Expand All @@ -198,7 +205,7 @@ func FromFile(networkID uint32, filepath string) ([]byte, ids.ID, error) {
return nil, ids.ID{}, fmt.Errorf("unable to load provided genesis config at %s: %w", filepath, err)
}

if err := validateConfig(networkID, config); err != nil {
if err := validateConfig(networkID, config, stakingCfg); err != nil {
return nil, ids.ID{}, fmt.Errorf("genesis config validation failed: %w", err)
}

Expand All @@ -224,7 +231,7 @@ func FromFile(networkID uint32, filepath string) ([]byte, ids.ID, error) {
// 1. The byte representation of the genesis state of the platform chain
// (ie the genesis state of the network)
// 2. The asset ID of AVAX
func FromFlag(networkID uint32, genesisContent string) ([]byte, ids.ID, error) {
func FromFlag(networkID uint32, genesisContent string, stakingCfg *StakingConfig) ([]byte, ids.ID, error) {
switch networkID {
case constants.MainnetID, constants.TestnetID, constants.LocalID:
return nil, ids.ID{}, fmt.Errorf(
Expand All @@ -239,7 +246,7 @@ func FromFlag(networkID uint32, genesisContent string) ([]byte, ids.ID, error) {
return nil, ids.ID{}, fmt.Errorf("unable to load genesis content from flag: %w", err)
}

if err := validateConfig(networkID, customConfig); err != nil {
if err := validateConfig(networkID, customConfig, stakingCfg); err != nil {
return nil, ids.ID{}, fmt.Errorf("genesis config validation failed: %w", err)
}

Expand Down
30 changes: 22 additions & 8 deletions genesis/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"path/filepath"
"testing"
"time"

_ "embed"

Expand All @@ -27,6 +28,10 @@ var (
invalidGenesisConfigJSON = []byte(`{
"networkID": 9999}}}}
}`)

genesisStakingCfg = &StakingConfig{
MaxStakeDuration: 365 * 24 * time.Hour,
}
)

func TestValidateConfig(t *testing.T) {
Expand Down Expand Up @@ -68,7 +73,7 @@ func TestValidateConfig(t *testing.T) {
thisConfig.Allocations = []Allocation{}
return &thisConfig
}(),
err: "initial supply must be > 0",
err: errNoSupply.Error(),
},
"no initial stakers": {
networkID: 12345,
Expand All @@ -77,7 +82,7 @@ func TestValidateConfig(t *testing.T) {
thisConfig.InitialStakers = []Staker{}
return &thisConfig
}(),
err: "initial stakers must be > 0",
err: errNoStakers.Error(),
},
"invalid initial stake duration": {
networkID: 12345,
Expand All @@ -86,7 +91,16 @@ func TestValidateConfig(t *testing.T) {
thisConfig.InitialStakeDuration = 0
return &thisConfig
}(),
err: "initial stake duration must be > 0",
err: errNoStakeDuration.Error(),
},
"too large initial stake duration": {
networkID: 12345,
config: func() *Config {
thisConfig := LocalConfig
thisConfig.InitialStakeDuration = uint64(genesisStakingCfg.MaxStakeDuration+time.Second) / uint64(time.Second)
return &thisConfig
}(),
err: errStakeDurationTooHigh.Error(),
},
"invalid stake offset": {
networkID: 12345,
Expand All @@ -104,7 +118,7 @@ func TestValidateConfig(t *testing.T) {
thisConfig.InitialStakedFunds = []ids.ShortID(nil)
return &thisConfig
}(),
err: "initial staked funds cannot be empty",
err: errNoInitiallyStakedFunds.Error(),
},
"duplicate initial staked funds": {
networkID: 12345,
Expand All @@ -131,7 +145,7 @@ func TestValidateConfig(t *testing.T) {
thisConfig.CChainGenesis = ""
return &thisConfig
}(),
err: "C-Chain genesis cannot be empty",
err: errNoCChainGenesis.Error(),
},
"empty message": {
networkID: 12345,
Expand All @@ -147,7 +161,7 @@ func TestValidateConfig(t *testing.T) {
t.Run(name, func(t *testing.T) {
require := require.New(t)

err := validateConfig(test.networkID, test.config)
err := validateConfig(test.networkID, test.config, genesisStakingCfg)
if len(test.err) > 0 {
require.Error(err)
require.Contains(err.Error(), test.err)
Expand Down Expand Up @@ -228,7 +242,7 @@ func TestGenesisFromFile(t *testing.T) {
customFile = test.missingFilepath
}

genesisBytes, _, err := FromFile(test.networkID, customFile)
genesisBytes, _, err := FromFile(test.networkID, customFile, genesisStakingCfg)
if len(test.err) > 0 {
require.Error(err)
require.Contains(err.Error(), test.err)
Expand Down Expand Up @@ -317,7 +331,7 @@ func TestGenesisFromFlag(t *testing.T) {
}
content := base64.StdEncoding.EncodeToString(genBytes)

genesisBytes, _, err := FromFlag(test.networkID, content)
genesisBytes, _, err := FromFlag(test.networkID, content, genesisStakingCfg)
if len(test.err) > 0 {
require.Error(err)
require.Contains(err.Error(), test.err)
Expand Down

0 comments on commit 58b17f9

Please sign in to comment.