Skip to content

Commit

Permalink
feat: sort wallet addresses (#836)
Browse files Browse the repository at this point in the history
  • Loading branch information
amirvalhalla authored Dec 6, 2023
1 parent 52eafc6 commit 26fcbed
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 127 deletions.
90 changes: 46 additions & 44 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import (
"github.com/pactus-project/pactus/config"
"github.com/pactus-project/pactus/crypto"
"github.com/pactus-project/pactus/crypto/bls"
"github.com/pactus-project/pactus/crypto/bls/hdkeychain"
"github.com/pactus-project/pactus/genesis"
"github.com/pactus-project/pactus/node"
"github.com/pactus-project/pactus/types/account"
"github.com/pactus-project/pactus/types/param"
"github.com/pactus-project/pactus/types/validator"
"github.com/pactus-project/pactus/util"
"github.com/pactus-project/pactus/wallet"
"github.com/pactus-project/pactus/wallet/addresspath"
)

// terminalSupported returns true if the current terminal supports
Expand Down Expand Up @@ -290,34 +292,29 @@ func CreateNode(numValidators int, chain genesis.ChainType, workingDir string,
case genesis.Mainnet:
panic("not yet!")
case genesis.Testnet:
err = genesis.TestnetGenesis().SaveToFile(genPath)
if err != nil {
if err := genesis.TestnetGenesis().SaveToFile(genPath); err != nil {
return nil, nil, err
}

err = config.SaveTestnetConfig(confPath, numValidators)
if err != nil {
if err := config.SaveTestnetConfig(confPath); err != nil {
return nil, nil, err
}

case genesis.Localnet:
err = makeLocalGenesis(*walletInstance).SaveToFile(genPath)
if err != nil {
if err := makeLocalGenesis(*walletInstance).SaveToFile(genPath); err != nil {
return nil, nil, err
}

err := config.SaveLocalnetConfig(confPath, numValidators)
if err != nil {
if err := config.SaveLocalnetConfig(confPath); err != nil {
return nil, nil, err
}
}

err = walletInstance.UpdatePassword("", walletPassword)
if err != nil {
if err := walletInstance.UpdatePassword("", walletPassword); err != nil {
return nil, nil, err
}

err = walletInstance.Save()
if err != nil {
if err := walletInstance.Save(); err != nil {
return nil, nil, err
}

Expand Down Expand Up @@ -356,20 +353,28 @@ func StartNode(workingDir string, passwordFetcher func(*wallet.Wallet) (string,
if err != nil {
return nil, nil, err
}
addrLabels := walletInstance.AddressInfos()
allValAddrs := walletInstance.AllValidatorAddresses()

if len(allValAddrs) < 1 || len(allValAddrs) > 32 {
return nil, nil, fmt.Errorf("number of validators must be between 1 and 32, but it's %d",
len(allValAddrs))
}

if len(addrLabels) < conf.Node.NumValidators {
return nil, nil, fmt.Errorf("not enough addresses in wallet")
if len(conf.Node.RewardAddresses) > 0 &&
len(conf.Node.RewardAddresses) != len(allValAddrs) {
return nil, nil, fmt.Errorf("reward addresses should be %v", len(allValAddrs))
}
validatorAddrs := make([]string, conf.Node.NumValidators)
for i := 0; i < conf.Node.NumValidators; i++ {
valAddr, _ := crypto.AddressFromString(addrLabels[i].Address)

validatorAddrs := make([]string, len(allValAddrs))
for i := 0; i < len(validatorAddrs); i++ {
valAddr, _ := crypto.AddressFromString(allValAddrs[i].Address)
if !valAddr.IsValidatorAddress() {
return nil, nil, fmt.Errorf("invalid validator address: %s", addrLabels[i].Address)
return nil, nil, fmt.Errorf("invalid validator address: %s", allValAddrs[i].Address)
}
validatorAddrs[i] = valAddr.String()
}
valKeys := make([]*bls.ValidatorKey, conf.Node.NumValidators)

valKeys := make([]*bls.ValidatorKey, len(allValAddrs))
password, ok := passwordFetcher(walletInstance)
if !ok {
return nil, nil, fmt.Errorf("aborted")
Expand All @@ -383,26 +388,27 @@ func StartNode(workingDir string, passwordFetcher func(*wallet.Wallet) (string,
}

// Create reward addresses
rewardAddrs := make([]crypto.Address, 0, conf.Node.NumValidators)
rewardAddrs := make([]crypto.Address, 0, len(allValAddrs))
if len(conf.Node.RewardAddresses) != 0 {
for _, addrStr := range conf.Node.RewardAddresses {
addr, _ := crypto.AddressFromString(addrStr)
rewardAddrs = append(rewardAddrs, addr)
}
} else {
for i := conf.Node.NumValidators; i < len(addrLabels); i++ {
addr, _ := crypto.AddressFromString(addrLabels[i].Address)
if addr.IsAccountAddress() {
rewardAddrs = append(rewardAddrs, addr)
if len(rewardAddrs) == conf.Node.NumValidators {
break
}
for i := 0; i < len(allValAddrs); i++ {
valAddrPath, _ := addresspath.NewPathFromString(allValAddrs[i].Path)
accAddrPath := addresspath.NewPath(valAddrPath.Purpose(), valAddrPath.CoinType(),
uint32(crypto.AddressTypeValidator)+hdkeychain.HardenedKeyStart, valAddrPath.AddressIndex())

addrInfo := walletInstance.AddressFromPath(accAddrPath.String())
if addrInfo == nil {
return nil, nil, fmt.Errorf("unable to find reward address for: %s", allValAddrs[i].Address)
}

addr, _ := crypto.AddressFromString(addrInfo.Address)
rewardAddrs = append(rewardAddrs, addr)
}
}
if len(rewardAddrs) != conf.Node.NumValidators {
return nil, nil, fmt.Errorf("not enough addresses in wallet")
}

nodeInstance, err := node.NewNode(gen, conf, valKeys, rewardAddrs)
if err != nil {
Expand Down Expand Up @@ -456,17 +462,13 @@ func tryLoadConfig(chainType genesis.ChainType, confPath string) (*config.Config
PrintWarnMsgf("Unable to load the config: %s", err)
PrintInfoMsgf("Attempting to restore the config to the default values...")

// First, try to open the old config file in non-strict mode
confBack, err := config.LoadFromFile(confPath, false, defConf)
if err != nil {
return nil, err
}

// Let's create a backup of the config
confBackupPath := fmt.Sprintf("%v_bak_%s", confPath, time.Now().Format("2006_01_02"))
err = os.Rename(confPath, confBackupPath)
if err != nil {
return nil, err
if util.PathExists(confPath) {
// Let's create a backup of the config
confBackupPath := fmt.Sprintf("%v_bak_%s", confPath, time.Now().Format("2006-01-02T15:04:05"))
err = os.Rename(confPath, confBackupPath)
if err != nil {
return nil, err
}
}

// Now, attempt to restore the config file with the number of validators from the old config.
Expand All @@ -475,13 +477,13 @@ func tryLoadConfig(chainType genesis.ChainType, confPath string) (*config.Config
panic("not yet implemented!")

case genesis.Testnet:
err = config.SaveTestnetConfig(confPath, confBack.Node.NumValidators)
err = config.SaveTestnetConfig(confPath)
if err != nil {
return nil, err
}

case genesis.Localnet:
err = config.SaveLocalnetConfig(confPath, confBack.Node.NumValidators)
err = config.SaveLocalnetConfig(confPath)
if err != nil {
return nil, err
}
Expand Down
4 changes: 0 additions & 4 deletions cmd/wallet/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@ func buildAllAddressesCmd(parentCmd *cobra.Command) {
}

line += info.Label
if info.Path == "" {
line += " (Imported)"
}

cmd.PrintInfoMsgf(line)
}
}
Expand Down
20 changes: 3 additions & 17 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,16 @@ type Config struct {
}

type NodeConfig struct {
NumValidators int `toml:"num_validators"` // TODO: we can remove this now
RewardAddresses []string `toml:"reward_addresses"`
}

func DefaultNodeConfig() *NodeConfig {
// TODO: We should have default config per network: Testnet, Mainnet.
return &NodeConfig{
NumValidators: 7,
}
return &NodeConfig{}
}

// BasicCheck performs basic checks on the configuration.
func (conf *NodeConfig) BasicCheck() error {
if conf.NumValidators < 1 || conf.NumValidators > 32 {
return errors.Errorf(errors.ErrInvalidConfig, "number of validators must be between 1 and 32")
}

if len(conf.RewardAddresses) > 0 &&
len(conf.RewardAddresses) != conf.NumValidators {
return errors.Errorf(errors.ErrInvalidConfig, "reward addresses should be %v", conf.NumValidators)
}

for _, addrStr := range conf.RewardAddresses {
addr, err := crypto.AddressFromString(addrStr)
if err != nil {
Expand Down Expand Up @@ -171,15 +159,13 @@ func SaveMainnetConfig(path string, numValidators int) error {
return util.WriteFile(path, []byte(conf))
}

func SaveTestnetConfig(path string, numValidators int) error {
func SaveTestnetConfig(path string) error {
conf := DefaultConfigTestnet()
conf.Node.NumValidators = numValidators
return util.WriteFile(path, conf.toTOML())
}

func SaveLocalnetConfig(path string, numValidators int) error {
func SaveLocalnetConfig(path string) error {
conf := DefaultConfigLocalnet()
conf.Node.NumValidators = numValidators
return util.WriteFile(path, conf.toTOML())
}

Expand Down
25 changes: 2 additions & 23 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestSaveMainnetConfig(t *testing.T) {

func TestSaveTestnetConfig(t *testing.T) {
path := util.TempFilePath()
assert.NoError(t, SaveTestnetConfig(path, 7))
assert.NoError(t, SaveTestnetConfig(path))

defConf := DefaultConfigTestnet()
conf, err := LoadFromFile(path, true, defConf)
Expand All @@ -35,7 +35,7 @@ func TestSaveTestnetConfig(t *testing.T) {

func TestSaveLocalnetConfig(t *testing.T) {
path := util.TempFilePath()
assert.NoError(t, SaveLocalnetConfig(path, 4))
assert.NoError(t, SaveLocalnetConfig(path))

defConf := DefaultConfigLocalnet()
conf, err := LoadFromFile(path, true, defConf)
Expand Down Expand Up @@ -80,7 +80,6 @@ func TestExampleConfig(t *testing.T) {
defaultConf := DefaultConfigMainnet()
defaultToml := string(defaultConf.toTOML())

exampleToml = strings.ReplaceAll(exampleToml, "%num_validators%", "7")
exampleToml = strings.ReplaceAll(exampleToml, "##", "")
exampleToml = strings.ReplaceAll(exampleToml, "\r\n", "\n") // For Windows
exampleToml = strings.ReplaceAll(exampleToml, "\n\n", "\n")
Expand All @@ -92,25 +91,8 @@ func TestExampleConfig(t *testing.T) {
func TestNodeConfigBasicCheck(t *testing.T) {
ts := testsuite.NewTestSuite(t)

t.Run("invalid number of validators", func(t *testing.T) {
conf := DefaultNodeConfig()
conf.NumValidators = 0

assert.Error(t, conf.BasicCheck())
})

t.Run("invalid number of reward addresses", func(t *testing.T) {
conf := DefaultNodeConfig()
conf.RewardAddresses = []string{
ts.RandAccAddress().String(),
}

assert.Error(t, conf.BasicCheck())
})

t.Run("invalid reward addresses", func(t *testing.T) {
conf := DefaultNodeConfig()
conf.NumValidators = 2
conf.RewardAddresses = []string{
ts.RandAccAddress().String(),
"abcd",
Expand All @@ -121,7 +103,6 @@ func TestNodeConfigBasicCheck(t *testing.T) {

t.Run("validator address as reward address", func(t *testing.T) {
conf := DefaultNodeConfig()
conf.NumValidators = 1
conf.RewardAddresses = []string{
ts.RandValAddress().String(),
}
Expand All @@ -131,7 +112,6 @@ func TestNodeConfigBasicCheck(t *testing.T) {

t.Run("ok", func(t *testing.T) {
conf := DefaultNodeConfig()
conf.NumValidators = 2
conf.RewardAddresses = []string{
ts.RandAccAddress().String(),
ts.RandAccAddress().String(),
Expand All @@ -142,7 +122,6 @@ func TestNodeConfigBasicCheck(t *testing.T) {

t.Run("no reward addresses inside config, Ok", func(t *testing.T) {
conf := DefaultNodeConfig()
conf.NumValidators = 2
conf.RewardAddresses = []string{}

assert.NoError(t, conf.BasicCheck())
Expand Down
3 changes: 0 additions & 3 deletions config/example_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
# `node` contains configuration options for the Pactus node.
[node]

# `num_validators` specifies the number of validators (consensus instances) to run on this node.
num_validators = %num_validators%

# `reward_addresses` specifies the addresses for collecting rewards.
# If it is empty, reward addresses will be obtained from the wallet.
# The number of reward addresses should be the same as the number of validators.
Expand Down
Loading

0 comments on commit 26fcbed

Please sign in to comment.